1 /* 2 * Copyright 2011-2015, 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 * Bill Randle, billr@neocat.org 8 */ 9 10 11 #include "displayport.h" 12 13 #include <Debug.h> 14 15 #include "accelerant_protos.h" 16 #include "atombios-obsolete.h" 17 #include "connector.h" 18 #include "mode.h" 19 #include "edid.h" 20 #include "encoder.h" 21 22 23 #undef TRACE 24 25 #define TRACE_DP 26 #ifdef TRACE_DP 27 # define TRACE(x...) _sPrintf("radeon_hd: " x) 28 #else 29 # define TRACE(x...) ; 30 #endif 31 32 #define ERROR(x...) _sPrintf("radeon_hd: " x) 33 34 35 static ssize_t 36 dp_aux_speak(uint32 connectorIndex, uint8* send, int sendBytes, 37 uint8* recv, int recvBytes, uint8 delay, uint8* ack) 38 { 39 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; 40 if (dpInfo->auxPin == 0) { 41 ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__); 42 return B_IO_ERROR; 43 } 44 45 int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); 46 47 // Build AtomBIOS Transaction 48 union auxChannelTransaction { 49 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; 50 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; 51 }; 52 union auxChannelTransaction args; 53 memset(&args, 0, sizeof(args)); 54 55 args.v2.lpAuxRequest = B_HOST_TO_LENDIAN_INT16(0 + 4); 56 args.v2.lpDataOut = B_HOST_TO_LENDIAN_INT16(16 + 4); 57 args.v2.ucDataOutLen = 0; 58 args.v2.ucChannelID = dpInfo->auxPin; 59 args.v2.ucDelay = delay / 10; 60 61 // Careful! This value differs in different atombios calls :-| 62 args.v2.ucHPD_ID = connector_pick_atom_hpdid(connectorIndex); 63 64 unsigned char* base = (unsigned char*)(gAtomContext->scratch + 1); 65 66 // TODO: This isn't correct for big endian systems! 67 // send needs to be swapped on big endian. 68 memcpy(base, send, sendBytes); 69 70 atom_execute_table(gAtomContext, index, (uint32*)&args); 71 72 *ack = args.v2.ucReplyStatus; 73 74 switch (args.v2.ucReplyStatus) { 75 case 1: 76 ERROR("%s: dp_aux channel timeout!\n", __func__); 77 return B_TIMED_OUT; 78 case 2: 79 ERROR("%s: dp_aux channel flags not zero!\n", __func__); 80 return B_BUSY; 81 case 3: 82 ERROR("%s: dp_aux channel error!\n", __func__); 83 return B_IO_ERROR; 84 } 85 86 int recvLength = args.v1.ucDataOutLen; 87 if (recvLength > recvBytes) 88 recvLength = recvBytes; 89 90 // TODO: This isn't correct for big endian systems! 91 // recv needs to be swapped on big endian. 92 if (recv && recvBytes) 93 memcpy(recv, base + 16, recvLength); 94 95 return recvLength; 96 } 97 98 99 status_t 100 dp_aux_transaction(uint32 connectorIndex, dp_aux_msg* message) 101 { 102 uint8 delay = 0; 103 if (message == NULL) { 104 ERROR("%s: DP message is invalid!\n", __func__); 105 return B_ERROR; 106 } 107 108 if (message->size > 16) { 109 ERROR("%s: Too many bytes! (%" B_PRIuSIZE ")\n", __func__, 110 message->size); 111 return B_ERROR; 112 } 113 114 uint8 transactionSize = 4; 115 116 switch(message->request & ~DP_AUX_I2C_MOT) { 117 case DP_AUX_NATIVE_WRITE: 118 case DP_AUX_I2C_WRITE: 119 case DP_AUX_I2C_WRITE_STATUS_UPDATE: 120 transactionSize += message->size; 121 break; 122 } 123 124 // If not bare address, check for buffer 125 if (message->size > 0 && message->buffer == NULL) { 126 ERROR("%s: DP message uninitalized buffer!\n", __func__); 127 return B_ERROR; 128 } 129 130 uint8 auxMessage[20]; 131 auxMessage[0] = message->address & 0xff; 132 auxMessage[1] = message->address >> 8; 133 auxMessage[2] = message->request << 4; 134 auxMessage[3] = message->size ? (message->size - 1) : 0; 135 136 if (message->size == 0) 137 auxMessage[3] |= 3 << 4; 138 else 139 auxMessage[3] |= transactionSize << 4; 140 141 uint8 retry; 142 for (retry = 0; retry < 7; retry++) { 143 uint8 ack; 144 ssize_t result = B_ERROR; 145 switch(message->request & ~DP_AUX_I2C_MOT) { 146 case DP_AUX_NATIVE_WRITE: 147 case DP_AUX_I2C_WRITE: 148 case DP_AUX_I2C_WRITE_STATUS_UPDATE: 149 memcpy(auxMessage + 4, message->buffer, message->size); 150 result = dp_aux_speak(connectorIndex, auxMessage, 151 transactionSize, NULL, 0, delay, &ack); 152 break; 153 case DP_AUX_NATIVE_READ: 154 case DP_AUX_I2C_READ: 155 result = dp_aux_speak(connectorIndex, auxMessage, 156 transactionSize, (uint8*)message->buffer, message->size, 157 delay, &ack); 158 break; 159 default: 160 ERROR("%s: Unknown dp_aux_msg request!\n", __func__); 161 return B_ERROR; 162 } 163 164 if (result == B_BUSY) 165 continue; 166 else if (result < B_OK) 167 return result; 168 169 ack >>= 4; 170 message->reply = ack; 171 switch(message->reply & DP_AUX_NATIVE_REPLY_MASK) { 172 case DP_AUX_NATIVE_REPLY_ACK: 173 return B_OK; 174 case DP_AUX_NATIVE_REPLY_DEFER: 175 TRACE("%s: aux reply defer received. Snoozing.\n", __func__); 176 snooze(400); 177 break; 178 default: 179 TRACE("%s: aux invalid native reply: 0x%02x\n", __func__, 180 message->reply); 181 return B_IO_ERROR; 182 } 183 } 184 185 ERROR("%s: IO Error. %" B_PRIu8 " attempts\n", __func__, retry); 186 return B_IO_ERROR; 187 } 188 189 190 void 191 dpcd_reg_write(uint32 connectorIndex, uint16 address, uint8 value) 192 { 193 //TRACE("%s: connector(%" B_PRId32 "): 0x%" B_PRIx16 " -> 0x%" B_PRIx8 "\n", 194 // __func__, connectorIndex, address, value); 195 dp_aux_msg message; 196 memset(&message, 0, sizeof(message)); 197 198 message.address = address; 199 message.buffer = &value; 200 message.request = DP_AUX_NATIVE_WRITE; 201 message.size = 1; 202 203 status_t result = dp_aux_transaction(connectorIndex, &message); 204 if (result != B_OK) { 205 ERROR("%s: error on DisplayPort aux write (0x%" B_PRIx32 ")\n", 206 __func__, result); 207 } 208 } 209 210 211 uint8 212 dpcd_reg_read(uint32 connectorIndex, uint16 address) 213 { 214 //TRACE("%s: connector(%" B_PRId32 "): read 0x%" B_PRIx16 ".\n", 215 // __func__, connectorIndex, address); 216 uint8 response[3]; 217 218 dp_aux_msg message; 219 memset(&message, 0, sizeof(message)); 220 221 message.address = address; 222 message.buffer = &response; 223 message.request = DP_AUX_NATIVE_READ; 224 message.size = 1; 225 226 status_t result = dp_aux_transaction(connectorIndex, &message); 227 if (result != B_OK) { 228 ERROR("%s: error on DisplayPort aux read (0x%" B_PRIx32 ")\n", 229 __func__, result); 230 } 231 232 return response[0]; 233 } 234 235 236 status_t 237 dp_aux_get_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data, 238 bool start, bool stop) 239 { 240 uint8 reply[3]; 241 dp_aux_msg message; 242 memset(&message, 0, sizeof(message)); 243 244 message.address = address; 245 message.buffer = reply; 246 message.request = DP_AUX_I2C_READ; 247 message.size = 1; 248 if (stop == false) { 249 // Remove Middle-Of-Transmission on final transaction 250 message.request |= DP_AUX_I2C_MOT; 251 } 252 if (stop || start) { 253 // Bare address packet 254 message.buffer = NULL; 255 message.size = 0; 256 } 257 258 for (int attempt = 0; attempt < 7; attempt++) { 259 status_t result = dp_aux_transaction(connectorIndex, &message); 260 if (result != B_OK) { 261 ERROR("%s: aux_ch transaction failed!\n", __func__); 262 return result; 263 } 264 265 switch (message.reply & DP_AUX_I2C_REPLY_MASK) { 266 case DP_AUX_I2C_REPLY_ACK: 267 *data = reply[0]; 268 return B_OK; 269 case DP_AUX_I2C_REPLY_NACK: 270 TRACE("%s: aux i2c nack\n", __func__); 271 return B_IO_ERROR; 272 case DP_AUX_I2C_REPLY_DEFER: 273 TRACE("%s: aux i2c defer\n", __func__); 274 snooze(400); 275 break; 276 default: 277 TRACE("%s: aux invalid I2C reply: 0x%02x\n", 278 __func__, message.reply); 279 return B_ERROR; 280 } 281 } 282 return B_ERROR; 283 } 284 285 286 status_t 287 dp_aux_set_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data, 288 bool start, bool stop) 289 { 290 dp_aux_msg message; 291 memset(&message, 0, sizeof(message)); 292 293 message.address = address; 294 message.buffer = data; 295 message.request = DP_AUX_I2C_WRITE; 296 message.size = 1; 297 if (stop == false) 298 message.request |= DP_AUX_I2C_MOT; 299 if (stop || start) { 300 message.buffer = NULL; 301 message.size = 0; 302 } 303 304 for (int attempt = 0; attempt < 7; attempt++) { 305 status_t result = dp_aux_transaction(connectorIndex, &message); 306 if (result != B_OK) { 307 ERROR("%s: aux_ch transaction failed!\n", __func__); 308 return result; 309 } 310 switch (message.reply & DP_AUX_I2C_REPLY_MASK) { 311 case DP_AUX_I2C_REPLY_ACK: 312 return B_OK; 313 case DP_AUX_I2C_REPLY_NACK: 314 ERROR("%s: aux i2c nack\n", __func__); 315 return B_IO_ERROR; 316 case DP_AUX_I2C_REPLY_DEFER: 317 TRACE("%s: aux i2c defer\n", __func__); 318 snooze(400); 319 break; 320 default: 321 ERROR("%s: aux invalid I2C reply: 0x%02x\n", __func__, 322 message.reply); 323 return B_IO_ERROR; 324 } 325 } 326 327 return B_ERROR; 328 } 329 330 331 uint32 332 dp_get_encoder_config(uint32 connectorIndex) 333 { 334 uint32 result = 0; 335 336 uint32 digEncoderID = encoder_pick_dig(connectorIndex); 337 if (digEncoderID) 338 result |= ATOM_DP_CONFIG_DIG2_ENCODER; 339 else 340 result |= ATOM_DP_CONFIG_DIG1_ENCODER; 341 342 bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration 343 == GRAPH_OBJECT_ENUM_ID2 ? true : false; 344 if (linkB) 345 result |= ATOM_DP_CONFIG_LINK_B; 346 else 347 result |= ATOM_DP_CONFIG_LINK_A; 348 349 return result; 350 } 351 352 353 uint32 354 dp_get_lane_count(uint32 connectorIndex, display_mode* mode) 355 { 356 size_t pixelChunk; 357 size_t pixelsPerChunk; 358 status_t result = dp_get_pixel_size_for((color_space)mode->space, 359 &pixelChunk, NULL, &pixelsPerChunk); 360 361 if (result != B_OK) { 362 TRACE("%s: Invalid color space!\n", __func__); 363 return 0; 364 } 365 366 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8; 367 368 uint32 dpMaxLinkRate 369 = dp_decode_link_rate(dpcd_reg_read(connectorIndex, DP_MAX_LINK_RATE)); 370 uint32 dpMaxLaneCount = dpcd_reg_read(connectorIndex, 371 DP_MAX_LANE_COUNT) & DP_MAX_LANE_COUNT_MASK; 372 373 uint32 lane; 374 // don't go below 2 lanes or display is jittery 375 for (lane = 2; lane < dpMaxLaneCount; lane <<= 1) { 376 uint32 maxPixelClock = dp_get_pixel_clock_max(dpMaxLinkRate, lane, 377 bitsPerPixel); 378 if (mode->timing.pixel_clock <= maxPixelClock) 379 break; 380 } 381 382 TRACE("%s: Lanes: %" B_PRIu32 "\n", __func__, lane); 383 return lane; 384 } 385 386 387 uint32 388 dp_get_link_rate(uint32 connectorIndex, display_mode* mode) 389 { 390 uint16 encoderID = gConnector[connectorIndex]->encoderExternal.objectID; 391 392 if (encoderID == ENCODER_OBJECT_ID_NUTMEG) 393 return 270000; 394 395 size_t pixelChunk; 396 size_t pixelsPerChunk; 397 status_t result = dp_get_pixel_size_for((color_space)mode->space, 398 &pixelChunk, NULL, &pixelsPerChunk); 399 400 if (result != B_OK) { 401 TRACE("%s: Invalid color space!\n", __func__); 402 return 0; 403 } 404 405 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8; 406 uint32 laneCount = dp_get_lane_count(connectorIndex, mode); 407 408 uint32 maxPixelClock 409 = dp_get_pixel_clock_max(162000, laneCount, bitsPerPixel); 410 if (mode->timing.pixel_clock <= maxPixelClock) 411 return 162000; 412 413 maxPixelClock = dp_get_pixel_clock_max(270000, laneCount, bitsPerPixel); 414 if (mode->timing.pixel_clock <= maxPixelClock) 415 return 270000; 416 417 // TODO: DisplayPort 1.2 418 #if 0 419 if (dp_is_dp12_capable(connectorIndex)) { 420 maxPixelClock = dp_get_pixel_clock_max(540000, laneCount, bitsPerPixel); 421 if (mode->timing.pixel_clock <= maxPixelClock) 422 return 540000; 423 } 424 #endif 425 426 return dp_decode_link_rate(dpcd_reg_read(connectorIndex, DP_MAX_LINK_RATE)); 427 } 428 429 430 static uint8 431 dp_encoder_service(int action, int linkRate, uint8 lane, uint8 config) 432 { 433 DP_ENCODER_SERVICE_PARAMETERS args; 434 int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); 435 436 memset(&args, 0, sizeof(args)); 437 args.ucLinkClock = linkRate / 10; 438 args.ucConfig = config; 439 args.ucAction = action; 440 args.ucLaneNum = lane; 441 args.ucStatus = 0; 442 443 atom_execute_table(gAtomContext, index, (uint32*)&args); 444 return args.ucStatus; 445 } 446 447 448 uint8 449 dp_get_sink_type(uint32 connectorIndex) 450 { 451 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; 452 return dp_encoder_service(ATOM_DP_ACTION_GET_SINK_TYPE, 0, 0, 453 dpInfo->auxPin); 454 } 455 456 457 void 458 dp_setup_connectors() 459 { 460 TRACE("%s\n", __func__); 461 462 for (uint32 index = 0; index < ATOM_MAX_SUPPORTED_DEVICE; index++) { 463 dp_info* dpInfo = &gConnector[index]->dpInfo; 464 // Validate connector is actually display port 465 if (gConnector[index]->valid == false 466 || connector_is_dp(index) == false) { 467 dpInfo->valid = false; 468 continue; 469 } 470 471 // Configure communication pins. 472 uint32 i2cPinIndex = gConnector[index]->i2cPinIndex; 473 uint32 auxPin = gGPIOInfo[i2cPinIndex]->hwPin; 474 dpInfo->auxPin = auxPin; 475 dpInfo->valid = true; 476 } 477 } 478 479 480 bool 481 dp_get_link_status(uint32 connectorIndex) 482 { 483 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 484 485 dp_aux_msg message; 486 memset(&message, 0, sizeof(message)); 487 488 message.request = DP_AUX_NATIVE_READ; 489 message.address = DP_LANE_STATUS_0_1; 490 message.size = DP_LINK_STATUS_SIZE; 491 message.buffer = dp->linkStatus; 492 493 // TODO: Delay 100? Newer AMD code doesn't care about link status 494 status_t result = dp_aux_transaction(connectorIndex, &message); 495 496 if (result != B_OK) { 497 ERROR("%s: DisplayPort link status failed\n", __func__); 498 return false; 499 } 500 501 return true; 502 } 503 504 505 static uint8 506 dp_get_lane_status(dp_info* dp, int lane) 507 { 508 int i = DP_LANE_STATUS_0_1 + (lane >> 1); 509 int s = (lane & 1) * 4; 510 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 511 return (l >> s) & 0xf; 512 } 513 514 515 static bool 516 dp_clock_recovery_ok(dp_info* dp) 517 { 518 int lane; 519 uint8 laneStatus; 520 521 for (lane = 0; lane < dp->laneCount; lane++) { 522 laneStatus = dp_get_lane_status(dp, lane); 523 if ((laneStatus & DP_LANE_STATUS_CR_DONE_A) == 0) 524 return false; 525 } 526 return true; 527 } 528 529 530 static bool 531 dp_clock_equalization_ok(dp_info* dp) 532 { 533 uint8 laneAlignment 534 = dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1]; 535 536 if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0) { 537 TRACE("%s: false. Lane alignment incomplete.\n", __func__); 538 return false; 539 } 540 541 int lane; 542 for (lane = 0; lane < dp->laneCount; lane++) { 543 uint8 laneStatus = dp_get_lane_status(dp, lane); 544 if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A) 545 != DP_LANE_STATUS_EQUALIZED_A) { 546 TRACE("%s: false. Lanes not yet equalized.\n", __func__); 547 return false; 548 } 549 } 550 TRACE("%s: true. Lanes equalized.\n", __func__); 551 return true; 552 } 553 554 555 static void 556 dp_update_vs_emph(uint32 connectorIndex) 557 { 558 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 559 560 // Set initial vs and emph on source 561 transmitter_dig_setup(connectorIndex, dp->linkRate, 0, 562 dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH); 563 564 dp_aux_msg message; 565 memset(&message, 0, sizeof(message)); 566 567 message.request = DP_AUX_NATIVE_WRITE; 568 message.address = DP_TRAIN_LANE0; 569 message.buffer = dp->trainingSet; 570 message.size = dp->laneCount; 571 // TODO: Review laneCount as it sounds strange. 572 dp_aux_transaction(connectorIndex, &message); 573 } 574 575 576 static uint8 577 dp_get_adjust_request_voltage(dp_info* dp, int lane) 578 { 579 int i = DP_ADJ_REQUEST_0_1 + (lane >> 1); 580 int s = (((lane & 1) != 0) ? DP_ADJ_VCC_SWING_LANEB_SHIFT 581 : DP_ADJ_VCC_SWING_LANEA_SHIFT); 582 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 583 584 return ((l >> s) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT; 585 } 586 587 588 static uint8 589 dp_get_adjust_request_pre_emphasis(dp_info* dp, int lane) 590 { 591 int i = DP_ADJ_REQUEST_0_1 + (lane >> 1); 592 int s = (((lane & 1) != 0) ? DP_ADJ_PRE_EMPHASIS_LANEB_SHIFT 593 : DP_ADJ_PRE_EMPHASIS_LANEA_SHIFT); 594 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 595 596 return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 597 } 598 599 600 static void 601 dp_get_adjust_train(dp_info* dp) 602 { 603 TRACE("%s\n", __func__); 604 605 const char* voltageNames[] = { 606 "0.4V", "0.6V", "0.8V", "1.2V" 607 }; 608 const char* preEmphasisNames[] = { 609 "0dB", "3.5dB", "6dB", "9.5dB" 610 }; 611 612 uint8 voltage = 0; 613 uint8 preEmphasis = 0; 614 int lane; 615 616 for (lane = 0; lane < dp->laneCount; lane++) { 617 uint8 laneVoltage = dp_get_adjust_request_voltage(dp, lane); 618 uint8 lanePreEmphasis = dp_get_adjust_request_pre_emphasis(dp, lane); 619 620 TRACE("%s: Requested %s at %s for lane %d\n", __func__, 621 preEmphasisNames[lanePreEmphasis >> DP_TRAIN_PRE_EMPHASIS_SHIFT], 622 voltageNames[laneVoltage >> DP_TRAIN_VCC_SWING_SHIFT], 623 lane); 624 625 if (laneVoltage > voltage) 626 voltage = laneVoltage; 627 if (lanePreEmphasis > preEmphasis) 628 preEmphasis = lanePreEmphasis; 629 } 630 631 // Check for maximum voltage and toggle max if reached 632 if (voltage >= DP_TRAIN_VCC_SWING_1200) 633 voltage |= DP_TRAIN_MAX_SWING_EN; 634 635 // Check for maximum pre-emphasis and toggle max if reached 636 if (preEmphasis >= DP_TRAIN_PRE_EMPHASIS_9_5) 637 preEmphasis |= DP_TRAIN_MAX_EMPHASIS_EN; 638 639 for (lane = 0; lane < 4; lane++) 640 dp->trainingSet[lane] = voltage | preEmphasis; 641 } 642 643 644 static void 645 dp_set_tp(uint32 connectorIndex, int trainingPattern) 646 { 647 TRACE("%s\n", __func__); 648 radeon_shared_info &info = *gInfo->shared_info; 649 650 pll_info* pll = &gConnector[connectorIndex]->encoder.pll; 651 652 int rawTrainingPattern = 0; 653 654 if (info.dceMajor >= 4) { 655 TRACE("%s: Training with encoder...\n", __func__); 656 switch (trainingPattern) { 657 case DP_TRAIN_PATTERN_1: 658 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1; 659 break; 660 case DP_TRAIN_PATTERN_2: 661 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2; 662 break; 663 case DP_TRAIN_PATTERN_3: 664 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3; 665 break; 666 } 667 encoder_dig_setup(connectorIndex, pll->pixelClock, rawTrainingPattern); 668 } else { 669 switch (trainingPattern) { 670 case DP_TRAIN_PATTERN_1: 671 rawTrainingPattern = 0; 672 break; 673 case DP_TRAIN_PATTERN_2: 674 rawTrainingPattern = 1; 675 break; 676 } 677 uint32 encoderConfig = dp_get_encoder_config(connectorIndex); 678 dp_encoder_service(ATOM_DP_ACTION_TRAINING_PATTERN_SEL, pll->pixelClock, 679 rawTrainingPattern, encoderConfig); 680 } 681 682 // Enable training pattern on the sink 683 dpcd_reg_write(connectorIndex, DP_TRAIN, trainingPattern); 684 } 685 686 687 status_t 688 dp_link_train_cr(uint32 connectorIndex) 689 { 690 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex); 691 692 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 693 694 // Display Port Clock Recovery Training 695 696 bool clockRecovery = false; 697 uint8 voltage = 0xff; 698 int lane; 699 700 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1); 701 memset(dp->trainingSet, 0, 4); 702 dp_update_vs_emph(connectorIndex); 703 snooze(400); 704 705 while (1) { 706 if (dp->trainingReadInterval == 0) 707 snooze(100); 708 else 709 snooze(1000 * 4 * dp->trainingReadInterval); 710 711 if (!dp_get_link_status(connectorIndex)) 712 break; 713 714 if (dp_clock_recovery_ok(dp)) { 715 clockRecovery = true; 716 break; 717 } 718 719 for (lane = 0; lane < dp->laneCount; lane++) { 720 if ((dp->trainingSet[lane] & DP_TRAIN_MAX_SWING_EN) == 0) 721 break; 722 } 723 724 if (lane == dp->laneCount) { 725 ERROR("%s: clock recovery reached max voltage\n", __func__); 726 break; 727 } 728 729 if ((dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK) == voltage) { 730 dp->trainingAttempts++; 731 if (dp->trainingAttempts >= 5) { 732 ERROR("%s: clock recovery tried 5 times\n", __func__); 733 break; 734 } 735 } else 736 dp->trainingAttempts = 0; 737 738 voltage = dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK; 739 740 // Compute new trainingSet as requested by sink 741 dp_get_adjust_train(dp); 742 743 dp_update_vs_emph(connectorIndex); 744 } 745 746 if (!clockRecovery) { 747 ERROR("%s: clock recovery failed\n", __func__); 748 return B_ERROR; 749 } 750 751 TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n", 752 __func__, dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK, 753 (dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK) 754 >> DP_TRAIN_PRE_EMPHASIS_SHIFT); 755 return B_OK; 756 } 757 758 759 status_t 760 dp_link_train_ce(uint32 connectorIndex, bool tp3Support) 761 { 762 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex); 763 764 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 765 766 if (tp3Support) 767 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_3); 768 else 769 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2); 770 771 dp->trainingAttempts = 0; 772 bool channelEqual = false; 773 774 while (1) { 775 if (dp->trainingReadInterval == 0) 776 snooze(400); 777 else 778 snooze(1000 * 4 * dp->trainingReadInterval); 779 780 if (!dp_get_link_status(connectorIndex)) { 781 ERROR("%s: ERROR: Unable to get link status!\n", __func__); 782 break; 783 } 784 785 if (dp_clock_equalization_ok(dp)) { 786 channelEqual = true; 787 break; 788 } 789 790 if (dp->trainingAttempts > 5) { 791 ERROR("%s: ERROR: failed > 5 times!\n", __func__); 792 break; 793 } 794 795 dp_get_adjust_train(dp); 796 797 dp_update_vs_emph(connectorIndex); 798 dp->trainingAttempts++; 799 } 800 801 if (!channelEqual) { 802 ERROR("%s: ERROR: failed\n", __func__); 803 return B_ERROR; 804 } 805 806 TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n", 807 __func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK, 808 (dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK) 809 >> DP_TRAIN_PRE_EMPHASIS_SHIFT); 810 811 return B_OK; 812 } 813 814 815 status_t 816 dp_link_train(uint8 crtcID) 817 { 818 TRACE("%s\n", __func__); 819 820 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 821 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 822 display_mode* mode = &gDisplay[crtcID]->currentMode; 823 824 if (dp->valid != true) { 825 ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n", 826 __func__, connectorIndex); 827 return B_ERROR; 828 } 829 830 dp->revision = dpcd_reg_read(connectorIndex, DP_DPCD_REV); 831 dp->trainingReadInterval 832 = dpcd_reg_read(connectorIndex, DP_TRAINING_AUX_RD_INTERVAL); 833 834 uint8 sandbox = dpcd_reg_read(connectorIndex, DP_MAX_LANE_COUNT); 835 836 radeon_shared_info &info = *gInfo->shared_info; 837 bool dpTPS3Supported = false; 838 if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0) 839 dpTPS3Supported = true; 840 841 // *** DisplayPort link training initialization 842 843 // Power up the DP sink 844 if (dp->revision >= DP_DPCD_REV_11) 845 dpcd_reg_write(connectorIndex, DP_SET_POWER, DP_SET_POWER_D0); 846 847 // Possibly enable downspread on the sink 848 if ((dpcd_reg_read(connectorIndex, DP_MAX_DOWNSPREAD) & 0x1) != 0) { 849 dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL, 850 DP_DOWNSPREAD_CTRL_AMP_EN); 851 } else 852 dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL, 0); 853 854 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 855 ATOM_ENCODER_CMD_SETUP_PANEL_MODE); 856 857 // Enable enhanced frame if supported 858 sandbox = dpcd_reg_read(connectorIndex, DP_LANE_COUNT); 859 if (dp->revision >= DP_DPCD_REV_11 860 && (dpcd_reg_read(connectorIndex, DP_MAX_LANE_COUNT) 861 & DP_ENHANCED_FRAME_CAP_EN)) { 862 sandbox |= DP_ENHANCED_FRAME_EN; 863 } 864 dpcd_reg_write(connectorIndex, DP_LANE_COUNT, sandbox); 865 866 // Set the link rate on the DP sink 867 sandbox = dp_encode_link_rate(dp->linkRate); 868 dpcd_reg_write(connectorIndex, DP_LINK_RATE, sandbox); 869 870 uint32 encoderConfig = dp_get_encoder_config(connectorIndex); 871 872 // Start link training on source 873 if (info.dceMajor >= 4) { 874 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 875 ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); 876 } else { 877 dp_encoder_service(ATOM_DP_ACTION_TRAINING_START, 878 mode->timing.pixel_clock, 0, encoderConfig); 879 } 880 881 // Disable the training pattern on the sink 882 dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); 883 884 dp_link_train_cr(connectorIndex); 885 dp_link_train_ce(connectorIndex, dpTPS3Supported); 886 887 // *** DisplayPort link training finish 888 snooze(400); 889 890 // Disable the training pattern on the sink 891 dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); 892 893 // Disable the training pattern on the source 894 if (info.dceMajor >= 4) { 895 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 896 ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); 897 } else { 898 dp_encoder_service(ATOM_DP_ACTION_TRAINING_COMPLETE, 899 mode->timing.pixel_clock, 0, encoderConfig); 900 } 901 902 return B_OK; 903 } 904 905 906 bool 907 ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid) 908 { 909 TRACE("%s\n", __func__); 910 911 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; 912 913 if (!dpInfo->valid) { 914 ERROR("%s: connector(%" B_PRIu32 ") missing valid DisplayPort data!\n", 915 __func__, connectorIndex); 916 return false; 917 } 918 919 edid1_raw raw; 920 uint8* rdata = (uint8*)&raw; 921 uint8 sdata = 0; 922 923 // The following sequence is from a trace of the Linux kernel 924 // radeon code; not sure if the initial writes to address 0 are 925 // requried. 926 // TODO: This surely cane be cleaned up 927 dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, true, false); 928 dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, false, true); 929 930 dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false); 931 dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false); 932 dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false); 933 dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, false); 934 dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, true); 935 936 dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false); 937 dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false); 938 dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false); 939 940 for (uint32 i = 0; i < sizeof(raw); i++) { 941 status_t result = dp_aux_get_i2c_byte(connectorIndex, 0x50, 942 rdata++, false, false); 943 if (result != B_OK) { 944 TRACE("%s: error reading EDID data at index %" B_PRIu32 ", " 945 "result = 0x%" B_PRIx32 "\n", __func__, i, result); 946 dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true); 947 return false; 948 } 949 } 950 dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true); 951 952 if (raw.version.version != 1 || raw.version.revision > 4) { 953 ERROR("%s: EDID version or revision out of range\n", __func__); 954 return false; 955 } 956 957 edid_decode(edid, &raw); 958 959 return true; 960 } 961 962 963 status_t 964 dp_get_pixel_size_for(color_space space, size_t *pixelChunk, 965 size_t *rowAlignment, size_t *pixelsPerChunk) 966 { 967 status_t result = get_pixel_size_for(space, pixelChunk, NULL, 968 pixelsPerChunk); 969 970 if ((space == B_RGB32) || (space == B_RGBA32) || (space == B_RGB32_BIG) 971 || (space == B_RGBA32_BIG)) { 972 *pixelChunk = 3; 973 } 974 975 return result; 976 } 977 978 979 bool 980 dp_is_dp12_capable(uint32 connectorIndex) 981 { 982 TRACE("%s\n", __func__); 983 radeon_shared_info &info = *gInfo->shared_info; 984 985 uint32 capabilities = gConnector[connectorIndex]->encoder.capabilities; 986 987 // DP_DPCD_REV_12 as well? 988 989 if (info.dceMajor >= 5 990 && gInfo->dpExternalClock >= 539000 991 && (capabilities & ATOM_ENCODER_CAP_RECORD_HBR2) != 0) { 992 return true; 993 } 994 995 return false; 996 } 997 998 999 void 1000 debug_dp_info() 1001 { 1002 ERROR("Current DisplayPort Info =================\n"); 1003 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 1004 if (gConnector[id]->valid == true) { 1005 dp_info* dp = &gConnector[id]->dpInfo; 1006 ERROR("Connector #%" B_PRIu32 ") DP: %s\n", id, 1007 dp->valid ? "true" : "false"); 1008 1009 if (!dp->valid) 1010 continue; 1011 ERROR(" + DP Config Data\n"); 1012 ERROR(" - max lane count: %d\n", 1013 dpcd_reg_read(id, DP_MAX_LANE_COUNT) & DP_MAX_LANE_COUNT_MASK); 1014 ERROR(" - max link rate: %d\n", 1015 dpcd_reg_read(id, DP_MAX_LINK_RATE)); 1016 ERROR(" - receiver port count: %d\n", 1017 dpcd_reg_read(id, DP_NORP) & DP_NORP_MASK); 1018 ERROR(" - downstream port present: %s\n", 1019 dpcd_reg_read(id, DP_DOWNSTREAMPORT) & DP_DOWNSTREAMPORT_EN 1020 ? "yes" : "no"); 1021 ERROR(" - downstream port count: %d\n", 1022 dpcd_reg_read(id, DP_DOWNSTREAMPORT_COUNT) 1023 & DP_DOWNSTREAMPORT_COUNT_MASK); 1024 ERROR(" + Training\n"); 1025 ERROR(" - attempts: %" B_PRIu8 "\n", 1026 dp->trainingAttempts); 1027 ERROR(" - delay: %d\n", 1028 dp->trainingReadInterval); 1029 ERROR(" + Data\n"); 1030 ERROR(" - auxPin: 0x%" B_PRIX32"\n", dp->auxPin); 1031 ERROR(" + Video\n"); 1032 ERROR(" - laneCount: %d\n", dp->laneCount); 1033 ERROR(" - linkRate: %" B_PRIu32 "\n", 1034 dp->linkRate); 1035 } 1036 } 1037 ERROR("==========================================\n"); 1038 } 1039