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