2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Alexander von Gluck IV, kallisti5@unixzen.com
7 * Bill Randle, billr@neocat.org
11 #include "displayport.h"
15 #include "accelerant_protos.h"
16 #include "connector.h"
26 # define TRACE(x...) _sPrintf("radeon_hd: " x)
28 # define TRACE(x...) ;
31 #define ERROR(x...) _sPrintf("radeon_hd: " x)
35 dp_aux_speak(uint32 connectorIndex
, uint8
* send
, int sendBytes
,
36 uint8
* recv
, int recvBytes
, uint8 delay
, uint8
* ack
)
38 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
39 if (dpInfo
->auxPin
== 0) {
40 ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__
);
44 int index
= GetIndexIntoMasterTable(COMMAND
, ProcessAuxChannelTransaction
);
46 // Build AtomBIOS Transaction
47 union auxChannelTransaction
{
48 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1
;
49 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2
;
51 union auxChannelTransaction args
;
52 memset(&args
, 0, sizeof(args
));
54 args
.v2
.lpAuxRequest
= B_HOST_TO_LENDIAN_INT16(0 + 4);
55 args
.v2
.lpDataOut
= B_HOST_TO_LENDIAN_INT16(16 + 4);
56 args
.v2
.ucDataOutLen
= 0;
57 args
.v2
.ucChannelID
= dpInfo
->auxPin
;
58 args
.v2
.ucDelay
= delay
/ 10;
60 // Careful! This value differs in different atombios calls :-|
61 args
.v2
.ucHPD_ID
= connector_pick_atom_hpdid(connectorIndex
);
63 unsigned char* base
= (unsigned char*)(gAtomContext
->scratch
+ 1);
65 // TODO: This isn't correct for big endian systems!
66 // send needs to be swapped on big endian.
67 memcpy(base
, send
, sendBytes
);
69 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
71 *ack
= args
.v2
.ucReplyStatus
;
73 switch (args
.v2
.ucReplyStatus
) {
75 ERROR("%s: dp_aux channel timeout!\n", __func__
);
78 ERROR("%s: dp_aux channel flags not zero!\n", __func__
);
81 ERROR("%s: dp_aux channel error!\n", __func__
);
85 int recvLength
= args
.v1
.ucDataOutLen
;
86 if (recvLength
> recvBytes
)
87 recvLength
= recvBytes
;
89 // TODO: This isn't correct for big endian systems!
90 // recv needs to be swapped on big endian.
91 if (recv
&& recvBytes
)
92 memcpy(recv
, base
+ 16, recvLength
);
99 dp_aux_transaction(uint32 connectorIndex
, dp_aux_msg
* message
)
102 if (message
== NULL
) {
103 ERROR("%s: DP message is invalid!\n", __func__
);
107 if (message
->size
> 16) {
108 ERROR("%s: Too many bytes! (%" B_PRIuSIZE
")\n", __func__
,
113 uint8 transactionSize
= 4;
115 switch(message
->request
& ~DP_AUX_I2C_MOT
) {
116 case DP_AUX_NATIVE_WRITE
:
117 case DP_AUX_I2C_WRITE
:
118 transactionSize
+= message
->size
;
122 // If not bare address, check for buffer
123 if (message
->size
> 0 && message
->buffer
== NULL
) {
124 ERROR("%s: DP message uninitalized buffer!\n", __func__
);
128 uint8 auxMessage
[20];
129 auxMessage
[0] = message
->address
& 0xff;
130 auxMessage
[1] = message
->address
>> 8;
131 auxMessage
[2] = message
->request
<< 4;
132 auxMessage
[3] = message
->size
? (message
->size
- 1) : 0;
134 if (message
->size
== 0)
135 auxMessage
[3] |= 3 << 4;
137 auxMessage
[3] |= transactionSize
<< 4;
140 for (retry
= 0; retry
< 7; retry
++) {
142 ssize_t result
= B_ERROR
;
143 switch(message
->request
& ~DP_AUX_I2C_MOT
) {
144 case DP_AUX_NATIVE_WRITE
:
145 case DP_AUX_I2C_WRITE
:
146 memcpy(auxMessage
+ 4, message
->buffer
, message
->size
);
147 result
= dp_aux_speak(connectorIndex
, auxMessage
,
148 transactionSize
, NULL
, 0, delay
, &ack
);
150 case DP_AUX_NATIVE_READ
:
151 case DP_AUX_I2C_READ
:
152 result
= dp_aux_speak(connectorIndex
, auxMessage
,
153 transactionSize
, (uint8
*)message
->buffer
, message
->size
,
157 ERROR("%s: Unknown dp_aux_msg request!\n", __func__
);
161 if (result
== B_BUSY
)
163 else if (result
< B_OK
)
167 message
->reply
= ack
;
168 switch(message
->reply
& DP_AUX_NATIVE_REPLY_MASK
) {
169 case DP_AUX_NATIVE_REPLY_ACK
:
171 case DP_AUX_NATIVE_REPLY_DEFER
:
172 TRACE("%s: aux reply defer received. Snoozing.\n", __func__
);
176 TRACE("%s: aux invalid native reply: 0x%02x\n", __func__
,
182 ERROR("%s: IO Error. %" B_PRIu8
" attempts\n", __func__
, retry
);
188 dpcd_reg_write(uint32 connectorIndex
, uint16 address
, uint8 value
)
190 //TRACE("%s: connector(%" B_PRId32 "): 0x%" B_PRIx16 " -> 0x%" B_PRIx8 "\n",
191 // __func__, connectorIndex, address, value);
193 memset(&message
, 0, sizeof(message
));
195 message
.address
= address
;
196 message
.buffer
= &value
;
197 message
.request
= DP_AUX_NATIVE_WRITE
;
200 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
201 if (result
!= B_OK
) {
202 ERROR("%s: error on DisplayPort aux write (0x%" B_PRIx32
")\n",
209 dpcd_reg_read(uint32 connectorIndex
, uint16 address
)
211 //TRACE("%s: connector(%" B_PRId32 "): read 0x%" B_PRIx16 ".\n",
212 // __func__, connectorIndex, address);
216 memset(&message
, 0, sizeof(message
));
218 message
.address
= address
;
219 message
.buffer
= &response
;
220 message
.request
= DP_AUX_NATIVE_READ
;
223 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
224 if (result
!= B_OK
) {
225 ERROR("%s: error on DisplayPort aux read (0x%" B_PRIx32
")\n",
234 dp_aux_get_i2c_byte(uint32 connectorIndex
, uint16 address
, uint8
* data
,
235 bool start
, bool stop
)
239 memset(&message
, 0, sizeof(message
));
241 message
.address
= address
;
242 message
.buffer
= reply
;
243 message
.request
= DP_AUX_I2C_READ
;
246 // Remove Middle-Of-Transmission on final transaction
247 message
.request
|= DP_AUX_I2C_MOT
;
250 // Bare address packet
251 message
.buffer
= NULL
;
255 for (int attempt
= 0; attempt
< 7; attempt
++) {
256 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
257 if (result
!= B_OK
) {
258 ERROR("%s: aux_ch transaction failed!\n", __func__
);
262 switch (message
.reply
& DP_AUX_I2C_REPLY_MASK
) {
263 case DP_AUX_I2C_REPLY_ACK
:
266 case DP_AUX_I2C_REPLY_NACK
:
267 TRACE("%s: aux i2c nack\n", __func__
);
269 case DP_AUX_I2C_REPLY_DEFER
:
270 TRACE("%s: aux i2c defer\n", __func__
);
274 TRACE("%s: aux invalid I2C reply: 0x%02x\n",
275 __func__
, message
.reply
);
284 dp_aux_set_i2c_byte(uint32 connectorIndex
, uint16 address
, uint8
* data
,
285 bool start
, bool stop
)
288 memset(&message
, 0, sizeof(message
));
290 message
.address
= address
;
291 message
.buffer
= data
;
292 message
.request
= DP_AUX_I2C_WRITE
;
295 message
.request
|= DP_AUX_I2C_MOT
;
297 message
.buffer
= NULL
;
301 for (int attempt
= 0; attempt
< 7; attempt
++) {
302 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
303 if (result
!= B_OK
) {
304 ERROR("%s: aux_ch transaction failed!\n", __func__
);
307 switch (message
.reply
& DP_AUX_I2C_REPLY_MASK
) {
308 case DP_AUX_I2C_REPLY_ACK
:
310 case DP_AUX_I2C_REPLY_NACK
:
311 ERROR("%s: aux i2c nack\n", __func__
);
313 case DP_AUX_I2C_REPLY_DEFER
:
314 TRACE("%s: aux i2c defer\n", __func__
);
318 ERROR("%s: aux invalid I2C reply: 0x%02x\n", __func__
,
329 dp_get_lane_count(uint32 connectorIndex
, display_mode
* mode
)
332 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
335 size_t pixelsPerChunk
;
336 status_t result
= dp_get_pixel_size_for((color_space
)mode
->space
,
337 &pixelChunk
, NULL
, &pixelsPerChunk
);
339 if (result
!= B_OK
) {
340 TRACE("%s: Invalid color space!\n", __func__
);
344 uint32 bitsPerPixel
= (pixelChunk
/ pixelsPerChunk
) * 8;
346 uint32 dpMaxLinkRate
= dp_get_link_rate_max(dpInfo
);
347 uint32 dpMaxLaneCount
= dp_get_lane_count_max(dpInfo
);
350 // don't go below 2 lanes or display is jittery
351 for (lane
= 2; lane
< dpMaxLaneCount
; lane
<<= 1) {
352 uint32 maxPixelClock
= dp_get_pixel_clock_max(dpMaxLinkRate
, lane
,
354 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
358 TRACE("%s: Lanes: %" B_PRIu32
"\n", __func__
, lane
);
364 dp_get_link_rate(uint32 connectorIndex
, display_mode
* mode
)
366 uint16 encoderID
= gConnector
[connectorIndex
]->encoderExternal
.objectID
;
368 if (encoderID
== ENCODER_OBJECT_ID_NUTMEG
)
371 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
372 uint32 laneCount
= dp_get_lane_count(connectorIndex
, mode
);
375 size_t pixelsPerChunk
;
376 status_t result
= dp_get_pixel_size_for((color_space
)mode
->space
,
377 &pixelChunk
, NULL
, &pixelsPerChunk
);
379 if (result
!= B_OK
) {
380 TRACE("%s: Invalid color space!\n", __func__
);
384 uint32 bitsPerPixel
= (pixelChunk
/ pixelsPerChunk
) * 8;
387 = dp_get_pixel_clock_max(162000, laneCount
, bitsPerPixel
);
388 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
391 maxPixelClock
= dp_get_pixel_clock_max(270000, laneCount
, bitsPerPixel
);
392 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
395 // TODO: DisplayPort 1.2
397 if (dp_is_dp12_capable(connectorIndex
)) {
398 maxPixelClock
= dp_get_pixel_clock_max(540000, laneCount
, bitsPerPixel
);
399 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
404 return dp_get_link_rate_max(dpInfo
);
409 dp_setup_connectors()
411 TRACE("%s\n", __func__
);
413 for (uint32 index
= 0; index
< ATOM_MAX_SUPPORTED_DEVICE
; index
++) {
414 dp_info
* dpInfo
= &gConnector
[index
]->dpInfo
;
415 dpInfo
->valid
= false;
416 if (gConnector
[index
]->valid
== false
417 || connector_is_dp(index
) == false) {
418 dpInfo
->config
[0] = 0;
422 TRACE("%s: found dp connector on index %" B_PRIu32
"\n",
424 uint32 i2cPinIndex
= gConnector
[index
]->i2cPinIndex
;
426 uint32 auxPin
= gGPIOInfo
[i2cPinIndex
]->hwPin
;
427 dpInfo
->auxPin
= auxPin
;
430 memset(&message
, 0, sizeof(message
));
432 message
.address
= DP_DPCD_REV
;
433 message
.request
= DP_AUX_NATIVE_READ
;
435 message
.size
= DP_DPCD_SIZE
;
436 message
.buffer
= dpInfo
->config
;
438 status_t result
= dp_aux_transaction(index
, &message
);
440 if (result
== B_OK
) {
441 dpInfo
->valid
= true;
442 TRACE("%s: connector(%" B_PRIu32
"): successful read of DPCD\n",
445 TRACE("%s: connector(%" B_PRIu32
"): failed read of DPCD\n",
449 TRACE("%s: DPCD is ", __func__);
451 for (position = 0; position < message.size; position++)
452 _sPrintf("%02x ", message.buffer + position);
460 dp_get_link_status(uint32 connectorIndex
)
462 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
465 memset(&message
, 0, sizeof(message
));
467 message
.request
= DP_AUX_NATIVE_READ
;
468 message
.address
= DP_LANE_STATUS_0_1
;
469 message
.size
= DP_LINK_STATUS_SIZE
;
470 message
.buffer
= dp
->linkStatus
;
472 // TODO: Delay 100? Newer AMD code doesn't care about link status
473 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
475 if (result
!= B_OK
) {
476 ERROR("%s: DisplayPort link status failed\n", __func__
);
485 dp_get_lane_status(dp_info
* dp
, int lane
)
487 int i
= DP_LANE_STATUS_0_1
+ (lane
>> 1);
488 int s
= (lane
& 1) * 4;
489 uint8 l
= dp
->linkStatus
[i
- DP_LANE_STATUS_0_1
];
490 return (l
>> s
) & 0xf;
495 dp_clock_recovery_ok(dp_info
* dp
)
500 for (lane
= 0; lane
< dp
->laneCount
; lane
++) {
501 laneStatus
= dp_get_lane_status(dp
, lane
);
502 if ((laneStatus
& DP_LANE_STATUS_CR_DONE_A
) == 0)
510 dp_clock_equalization_ok(dp_info
* dp
)
513 = dp
->linkStatus
[DP_LANE_ALIGN
- DP_LANE_STATUS_0_1
];
515 if ((laneAlignment
& DP_LANE_ALIGN_DONE
) == 0)
519 for (lane
= 0; lane
< dp
->laneCount
; lane
++) {
520 uint8 laneStatus
= dp_get_lane_status(dp
, lane
);
521 if ((laneStatus
& DP_LANE_STATUS_EQUALIZED_A
)
522 != DP_LANE_STATUS_EQUALIZED_A
) {
531 dp_update_vs_emph(uint32 connectorIndex
)
533 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
535 // Set initial vs and emph on source
536 transmitter_dig_setup(connectorIndex
, dp
->linkRate
, 0,
537 dp
->trainingSet
[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH
);
540 memset(&message
, 0, sizeof(message
));
542 message
.request
= DP_AUX_NATIVE_WRITE
;
543 message
.address
= DP_TRAIN_LANE0
;
544 message
.buffer
= dp
->trainingSet
;
545 message
.size
= dp
->laneCount
;
546 // TODO: Review laneCount as it sounds strange.
547 dp_aux_transaction(connectorIndex
, &message
);
552 dp_get_adjust_request_voltage(dp_info
* dp
, int lane
)
554 int i
= DP_ADJ_REQUEST_0_1
+ (lane
>> 1);
555 int s
= (((lane
& 1) != 0) ? DP_ADJ_VCC_SWING_LANEB_SHIFT
556 : DP_ADJ_VCC_SWING_LANEA_SHIFT
);
557 uint8 l
= dp
->linkStatus
[i
- DP_LANE_STATUS_0_1
];
559 return ((l
>> s
) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT
;
564 dp_get_adjust_request_pre_emphasis(dp_info
* dp
, int lane
)
566 int i
= DP_ADJ_REQUEST_0_1
+ (lane
>> 1);
567 int s
= (((lane
& 1) != 0) ? DP_ADJ_PRE_EMPHASIS_LANEB_SHIFT
568 : DP_ADJ_PRE_EMPHASIS_LANEA_SHIFT
);
569 uint8 l
= dp
->linkStatus
[i
- DP_LANE_STATUS_0_1
];
571 return ((l
>> s
) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT
;
576 dp_get_adjust_train(dp_info
* dp
)
578 TRACE("%s\n", __func__
);
580 const char* voltageNames
[] = {
581 "0.4V", "0.6V", "0.8V", "1.2V"
583 const char* preEmphasisNames
[] = {
584 "0dB", "3.5dB", "6dB", "9.5dB"
588 uint8 preEmphasis
= 0;
591 for (lane
= 0; lane
< dp
->laneCount
; lane
++) {
592 uint8 laneVoltage
= dp_get_adjust_request_voltage(dp
, lane
);
593 uint8 lanePreEmphasis
= dp_get_adjust_request_pre_emphasis(dp
, lane
);
595 TRACE("%s: Requested %s at %s for lane %d\n", __func__
,
596 preEmphasisNames
[lanePreEmphasis
>> DP_TRAIN_PRE_EMPHASIS_SHIFT
],
597 voltageNames
[laneVoltage
>> DP_TRAIN_VCC_SWING_SHIFT
],
600 if (laneVoltage
> voltage
)
601 voltage
= laneVoltage
;
602 if (lanePreEmphasis
> preEmphasis
)
603 preEmphasis
= lanePreEmphasis
;
606 // Check for maximum voltage and toggle max if reached
607 if (voltage
>= DP_TRAIN_VCC_SWING_1200
)
608 voltage
|= DP_TRAIN_MAX_SWING_EN
;
610 // Check for maximum pre-emphasis and toggle max if reached
611 if (preEmphasis
>= DP_TRAIN_PRE_EMPHASIS_9_5
)
612 preEmphasis
|= DP_TRAIN_MAX_EMPHASIS_EN
;
614 for (lane
= 0; lane
< 4; lane
++)
615 dp
->trainingSet
[lane
] = voltage
| preEmphasis
;
620 dp_encoder_service(uint32 connectorIndex
, int action
, int linkRate
,
623 DP_ENCODER_SERVICE_PARAMETERS args
;
624 int index
= GetIndexIntoMasterTable(COMMAND
, DPEncoderService
);
626 memset(&args
, 0, sizeof(args
));
627 args
.ucLinkClock
= linkRate
;
628 args
.ucAction
= action
;
629 args
.ucLaneNum
= lane
;
633 // We really can't do ATOM_DP_ACTION_GET_SINK_TYPE with the
634 // way I designed this below. Not used though.
636 // Calculate encoder_id config
637 if (encoder_pick_dig(connectorIndex
))
638 args
.ucConfig
|= ATOM_DP_CONFIG_DIG2_ENCODER
;
640 args
.ucConfig
|= ATOM_DP_CONFIG_DIG1_ENCODER
;
642 if (gConnector
[connectorIndex
]->encoder
.linkEnumeration
643 == GRAPH_OBJECT_ENUM_ID2
) {
644 args
.ucConfig
|= ATOM_DP_CONFIG_LINK_B
;
646 args
.ucConfig
|= ATOM_DP_CONFIG_LINK_A
;
648 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
650 return args
.ucStatus
;
655 dp_set_tp(uint32 connectorIndex
, int trainingPattern
)
657 TRACE("%s\n", __func__
);
659 radeon_shared_info
&info
= *gInfo
->shared_info
;
660 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
661 pll_info
* pll
= &gConnector
[connectorIndex
]->encoder
.pll
;
663 int rawTrainingPattern
= 0;
665 /* set training pattern on the source */
666 if (info
.dceMajor
>= 4 || !dp
->trainingUseEncoder
) {
667 TRACE("%s: Training with encoder...\n", __func__
);
668 switch (trainingPattern
) {
669 case DP_TRAIN_PATTERN_1
:
670 rawTrainingPattern
= ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1
;
672 case DP_TRAIN_PATTERN_2
:
673 rawTrainingPattern
= ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2
;
675 case DP_TRAIN_PATTERN_3
:
676 rawTrainingPattern
= ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3
;
679 encoder_dig_setup(connectorIndex
, pll
->pixelClock
, rawTrainingPattern
);
681 TRACE("%s: Training with encoder service...\n", __func__
);
682 switch (trainingPattern
) {
683 case DP_TRAIN_PATTERN_1
:
684 rawTrainingPattern
= 0;
686 case DP_TRAIN_PATTERN_2
:
687 rawTrainingPattern
= 1;
690 dp_encoder_service(connectorIndex
, ATOM_DP_ACTION_TRAINING_PATTERN_SEL
,
691 dp
->linkRate
, rawTrainingPattern
);
694 // Enable training pattern on the sink
695 dpcd_reg_write(connectorIndex
, DP_TRAIN
, trainingPattern
);
700 dp_link_train_cr(uint32 connectorIndex
)
702 TRACE("%s\n", __func__
);
704 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
706 // Display Port Clock Recovery Training
708 bool clockRecovery
= false;
709 uint8 voltage
= 0xff;
712 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_1
);
713 memset(dp
->trainingSet
, 0, 4);
714 dp_update_vs_emph(connectorIndex
);
718 if (dp
->trainingReadInterval
== 0)
721 snooze(1000 * 4 * dp
->trainingReadInterval
);
723 if (!dp_get_link_status(connectorIndex
))
726 if (dp_clock_recovery_ok(dp
)) {
727 clockRecovery
= true;
731 for (lane
= 0; lane
< dp
->laneCount
; lane
++) {
732 if ((dp
->trainingSet
[lane
] & DP_TRAIN_MAX_SWING_EN
) == 0)
736 if (lane
== dp
->laneCount
) {
737 ERROR("%s: clock recovery reached max voltage\n", __func__
);
741 if ((dp
->trainingSet
[0] & DP_TRAIN_VCC_SWING_MASK
) == voltage
) {
742 dp
->trainingAttempts
++;
743 if (dp
->trainingAttempts
>= 5) {
744 ERROR("%s: clock recovery tried 5 times\n", __func__
);
748 dp
->trainingAttempts
= 0;
750 voltage
= dp
->trainingSet
[0] & DP_TRAIN_VCC_SWING_MASK
;
752 // Compute new trainingSet as requested by sink
753 dp_get_adjust_train(dp
);
755 dp_update_vs_emph(connectorIndex
);
758 if (!clockRecovery
) {
759 ERROR("%s: clock recovery failed\n", __func__
);
763 TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n",
764 __func__
, dp
->trainingSet
[0] & DP_TRAIN_VCC_SWING_MASK
,
765 (dp
->trainingSet
[0] & DP_TRAIN_PRE_EMPHASIS_MASK
)
766 >> DP_TRAIN_PRE_EMPHASIS_SHIFT
);
772 dp_link_train_ce(uint32 connectorIndex
, bool tp3Support
)
774 TRACE("%s\n", __func__
);
776 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
779 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_3
);
781 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_2
);
783 dp
->trainingAttempts
= 0;
784 bool channelEqual
= false;
787 if (dp
->trainingReadInterval
== 0)
790 snooze(1000 * 4 * dp
->trainingReadInterval
);
792 if (!dp_get_link_status(connectorIndex
)) {
793 ERROR("%s: ERROR: Unable to get link status!\n", __func__
);
797 if (dp_clock_equalization_ok(dp
)) {
802 if (dp
->trainingAttempts
> 5) {
803 ERROR("%s: ERROR: failed > 5 times!\n", __func__
);
807 dp_get_adjust_train(dp
);
809 dp_update_vs_emph(connectorIndex
);
810 dp
->trainingAttempts
++;
814 ERROR("%s: ERROR: failed\n", __func__
);
818 TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n",
819 __func__
, dp
->trainingSet
[0] & DP_ADJ_VCC_SWING_LANEA_MASK
,
820 (dp
->trainingSet
[0] & DP_TRAIN_PRE_EMPHASIS_MASK
)
821 >> DP_TRAIN_PRE_EMPHASIS_SHIFT
);
828 dp_link_train(uint8 crtcID
)
830 TRACE("%s\n", __func__
);
832 uint32 connectorIndex
= gDisplay
[crtcID
]->connectorIndex
;
833 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
834 display_mode
* mode
= &gDisplay
[crtcID
]->currentMode
;
836 if (dp
->valid
!= true) {
837 ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32
"\n",
838 __func__
, connectorIndex
);
842 int index
= GetIndexIntoMasterTable(COMMAND
, DPEncoderService
);
847 dp
->trainingUseEncoder
= true;
848 if (atom_parse_cmd_header(gAtomContext
, index
, &tableMajor
, &tableMinor
)
850 if (tableMinor
> 1) {
851 // The AtomBIOS DPEncoderService greater then 1.1 can't program the
852 // training pattern properly.
853 dp
->trainingUseEncoder
= false;
857 uint32 linkEnumeration
858 = gConnector
[connectorIndex
]->encoder
.linkEnumeration
;
860 uint32 dpEncoderID
= 0;
861 if (encoder_pick_dig(connectorIndex
) > 0)
862 dpEncoderID
|= ATOM_DP_CONFIG_DIG2_ENCODER
;
864 dpEncoderID
|= ATOM_DP_CONFIG_DIG1_ENCODER
;
865 if (linkEnumeration
== GRAPH_OBJECT_ENUM_ID2
)
866 dpEncoderID
|= ATOM_DP_CONFIG_LINK_B
;
868 dpEncoderID
|= ATOM_DP_CONFIG_LINK_A
;
870 dp
->trainingReadInterval
871 = dpcd_reg_read(connectorIndex
, DP_TRAINING_AUX_RD_INTERVAL
);
873 uint8 sandbox
= dpcd_reg_read(connectorIndex
, DP_MAX_LANE_COUNT
);
875 radeon_shared_info
&info
= *gInfo
->shared_info
;
876 bool dpTPS3Supported
= false;
877 if (info
.dceMajor
>= 5 && (sandbox
& DP_TPS3_SUPPORTED
) != 0)
878 dpTPS3Supported
= true;
880 // *** DisplayPort link training initialization
882 // Power up the DP sink
883 if (dp
->config
[0] >= DP_DPCD_REV_11
)
884 dpcd_reg_write(connectorIndex
, DP_SET_POWER
, DP_SET_POWER_D0
);
886 // Possibly enable downspread on the sink
887 if ((dp
->config
[3] & 0x1) != 0) {
888 dpcd_reg_write(connectorIndex
, DP_DOWNSPREAD_CTRL
,
889 DP_DOWNSPREAD_CTRL_AMP_EN
);
891 dpcd_reg_write(connectorIndex
, DP_DOWNSPREAD_CTRL
, 0);
893 encoder_dig_setup(connectorIndex
, mode
->timing
.pixel_clock
,
894 ATOM_ENCODER_CMD_SETUP_PANEL_MODE
);
896 // TODO: Doesn't this overwrite important dpcd info?
897 sandbox
= dp
->laneCount
;
898 if ((dp
->config
[0] >= DP_DPCD_REV_11
)
899 && (dp
->config
[2] & DP_ENHANCED_FRAME_CAP_EN
))
900 sandbox
|= DP_ENHANCED_FRAME_EN
;
901 dpcd_reg_write(connectorIndex
, DP_LANE_COUNT
, sandbox
);
903 // Set the link rate on the DP sink
904 sandbox
= dp_encode_link_rate(dp
->linkRate
);
905 dpcd_reg_write(connectorIndex
, DP_LINK_RATE
, sandbox
);
907 // Start link training on source
908 if (info
.dceMajor
>= 4 || !dp
->trainingUseEncoder
) {
909 encoder_dig_setup(connectorIndex
, mode
->timing
.pixel_clock
,
910 ATOM_ENCODER_CMD_DP_LINK_TRAINING_START
);
912 dp_encoder_service(connectorIndex
, ATOM_DP_ACTION_TRAINING_START
,
916 // Disable the training pattern on the sink
917 dpcd_reg_write(connectorIndex
, DP_TRAIN
, DP_TRAIN_PATTERN_DISABLED
);
919 dp_link_train_cr(connectorIndex
);
920 dp_link_train_ce(connectorIndex
, dpTPS3Supported
);
922 // *** DisplayPort link training finish
925 // Disable the training pattern on the sink
926 dpcd_reg_write(connectorIndex
, DP_TRAIN
, DP_TRAIN_PATTERN_DISABLED
);
928 // Disable the training pattern on the source
929 if (info
.dceMajor
>= 4 || !dp
->trainingUseEncoder
) {
930 encoder_dig_setup(connectorIndex
, mode
->timing
.pixel_clock
,
931 ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE
);
933 dp_encoder_service(connectorIndex
, ATOM_DP_ACTION_TRAINING_COMPLETE
,
942 ddc2_dp_read_edid1(uint32 connectorIndex
, edid1_info
* edid
)
944 TRACE("%s\n", __func__
);
946 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
948 if (!dpInfo
->valid
) {
949 ERROR("%s: connector(%" B_PRIu32
") missing valid DisplayPort data!\n",
950 __func__
, connectorIndex
);
955 uint8
* rdata
= (uint8
*)&raw
;
958 // The following sequence is from a trace of the Linux kernel
959 // radeon code; not sure if the initial writes to address 0 are
961 // TODO: This surely cane be cleaned up
962 dp_aux_set_i2c_byte(connectorIndex
, 0x00, &sdata
, true, false);
963 dp_aux_set_i2c_byte(connectorIndex
, 0x00, &sdata
, false, true);
965 dp_aux_set_i2c_byte(connectorIndex
, 0x50, &sdata
, true, false);
966 dp_aux_set_i2c_byte(connectorIndex
, 0x50, &sdata
, false, false);
967 dp_aux_get_i2c_byte(connectorIndex
, 0x50, rdata
, true, false);
968 dp_aux_get_i2c_byte(connectorIndex
, 0x50, rdata
, false, false);
969 dp_aux_get_i2c_byte(connectorIndex
, 0x50, rdata
, false, true);
971 dp_aux_set_i2c_byte(connectorIndex
, 0x50, &sdata
, true, false);
972 dp_aux_set_i2c_byte(connectorIndex
, 0x50, &sdata
, false, false);
973 dp_aux_get_i2c_byte(connectorIndex
, 0x50, rdata
, true, false);
975 for (uint32 i
= 0; i
< sizeof(raw
); i
++) {
976 status_t result
= dp_aux_get_i2c_byte(connectorIndex
, 0x50,
977 rdata
++, false, false);
978 if (result
!= B_OK
) {
979 TRACE("%s: error reading EDID data at index %" B_PRIu32
", "
980 "result = 0x%" B_PRIx32
"\n", __func__
, i
, result
);
981 dp_aux_get_i2c_byte(connectorIndex
, 0x50, &sdata
, false, true);
985 dp_aux_get_i2c_byte(connectorIndex
, 0x50, &sdata
, false, true);
987 if (raw
.version
.version
!= 1 || raw
.version
.revision
> 4) {
988 ERROR("%s: EDID version or revision out of range\n", __func__
);
992 edid_decode(edid
, &raw
);
999 dp_get_pixel_size_for(color_space space
, size_t *pixelChunk
,
1000 size_t *rowAlignment
, size_t *pixelsPerChunk
)
1002 status_t result
= get_pixel_size_for(space
, pixelChunk
, NULL
,
1005 if ((space
== B_RGB32
) || (space
== B_RGBA32
) || (space
== B_RGB32_BIG
)
1006 || (space
== B_RGBA32_BIG
)) {
1015 dp_is_dp12_capable(uint32 connectorIndex
)
1017 TRACE("%s\n", __func__
);
1018 radeon_shared_info
&info
= *gInfo
->shared_info
;
1020 uint32 capabilities
= gConnector
[connectorIndex
]->encoder
.capabilities
;
1022 if (info
.dceMajor
>= 5
1023 && gInfo
->dpExternalClock
>= 539000
1024 && (capabilities
& ATOM_ENCODER_CAP_RECORD_HBR2
) != 0) {
1035 ERROR("Current DisplayPort Info =================\n");
1036 for (uint32 id
= 0; id
< ATOM_MAX_SUPPORTED_DEVICE
; id
++) {
1037 if (gConnector
[id
]->valid
== true) {
1038 dp_info
* dp
= &gConnector
[id
]->dpInfo
;
1039 ERROR("Connector #%" B_PRIu32
") DP: %s\n", id
,
1040 dp
->valid
? "true" : "false");
1044 ERROR(" + DP Config Data\n");
1045 ERROR(" - max lane count: %d\n",
1046 dp
->config
[DP_MAX_LANE_COUNT
] & DP_MAX_LANE_COUNT_MASK
);
1047 ERROR(" - max link rate: %d\n",
1048 dp
->config
[DP_MAX_LINK_RATE
]);
1049 ERROR(" - receiver port count: %d\n",
1050 dp
->config
[DP_NORP
] & DP_NORP_MASK
);
1051 ERROR(" - downstream port present: %s\n",
1052 (dp
->config
[DP_DOWNSTREAMPORT
] & DP_DOWNSTREAMPORT_EN
)
1054 ERROR(" - downstream port count: %d\n",
1055 dp
->config
[DP_DOWNSTREAMPORT_COUNT
]
1056 & DP_DOWNSTREAMPORT_COUNT_MASK
);
1057 ERROR(" + Training\n");
1058 ERROR(" - use encoder: %s\n",
1059 dp
->trainingUseEncoder
? "true" : "false");
1060 ERROR(" - attempts: %" B_PRIu8
"\n",
1061 dp
->trainingAttempts
);
1062 ERROR(" - delay: %d\n",
1063 dp
->trainingReadInterval
);
1065 ERROR(" - auxPin: 0x%" B_PRIX32
"\n", dp
->auxPin
);
1066 ERROR(" + Video\n");
1067 ERROR(" - laneCount: %d\n", dp
->laneCount
);
1068 ERROR(" - linkRate: %" B_PRIu32
"\n",
1072 ERROR("==========================================\n");