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 "atombios-obsolete.h"
17 #include "connector.h"
27 # define TRACE(x...) _sPrintf("radeon_hd: " x)
29 # define TRACE(x...) ;
32 #define ERROR(x...) _sPrintf("radeon_hd: " x)
36 dp_aux_speak(uint32 connectorIndex
, uint8
* send
, int sendBytes
,
37 uint8
* recv
, int recvBytes
, uint8 delay
, uint8
* ack
)
39 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
40 if (dpInfo
->auxPin
== 0) {
41 ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__
);
45 int index
= GetIndexIntoMasterTable(COMMAND
, ProcessAuxChannelTransaction
);
47 // Build AtomBIOS Transaction
48 union auxChannelTransaction
{
49 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1
;
50 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2
;
52 union auxChannelTransaction args
;
53 memset(&args
, 0, sizeof(args
));
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;
61 // Careful! This value differs in different atombios calls :-|
62 args
.v2
.ucHPD_ID
= connector_pick_atom_hpdid(connectorIndex
);
64 unsigned char* base
= (unsigned char*)(gAtomContext
->scratch
+ 1);
66 // TODO: This isn't correct for big endian systems!
67 // send needs to be swapped on big endian.
68 memcpy(base
, send
, sendBytes
);
70 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
72 *ack
= args
.v2
.ucReplyStatus
;
74 switch (args
.v2
.ucReplyStatus
) {
76 ERROR("%s: dp_aux channel timeout!\n", __func__
);
79 ERROR("%s: dp_aux channel flags not zero!\n", __func__
);
82 ERROR("%s: dp_aux channel error!\n", __func__
);
86 int recvLength
= args
.v1
.ucDataOutLen
;
87 if (recvLength
> recvBytes
)
88 recvLength
= recvBytes
;
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
);
100 dp_aux_transaction(uint32 connectorIndex
, dp_aux_msg
* message
)
103 if (message
== NULL
) {
104 ERROR("%s: DP message is invalid!\n", __func__
);
108 if (message
->size
> 16) {
109 ERROR("%s: Too many bytes! (%" B_PRIuSIZE
")\n", __func__
,
114 uint8 transactionSize
= 4;
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
;
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__
);
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;
136 if (message
->size
== 0)
137 auxMessage
[3] |= 3 << 4;
139 auxMessage
[3] |= transactionSize
<< 4;
142 for (retry
= 0; retry
< 7; retry
++) {
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
);
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
,
160 ERROR("%s: Unknown dp_aux_msg request!\n", __func__
);
164 if (result
== B_BUSY
)
166 else if (result
< B_OK
)
170 message
->reply
= ack
;
171 switch(message
->reply
& DP_AUX_NATIVE_REPLY_MASK
) {
172 case DP_AUX_NATIVE_REPLY_ACK
:
174 case DP_AUX_NATIVE_REPLY_DEFER
:
175 TRACE("%s: aux reply defer received. Snoozing.\n", __func__
);
179 TRACE("%s: aux invalid native reply: 0x%02x\n", __func__
,
185 ERROR("%s: IO Error. %" B_PRIu8
" attempts\n", __func__
, retry
);
191 dpcd_reg_write(uint32 connectorIndex
, uint16 address
, uint8 value
)
193 //TRACE("%s: connector(%" B_PRId32 "): 0x%" B_PRIx16 " -> 0x%" B_PRIx8 "\n",
194 // __func__, connectorIndex, address, value);
196 memset(&message
, 0, sizeof(message
));
198 message
.address
= address
;
199 message
.buffer
= &value
;
200 message
.request
= DP_AUX_NATIVE_WRITE
;
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",
212 dpcd_reg_read(uint32 connectorIndex
, uint16 address
)
214 //TRACE("%s: connector(%" B_PRId32 "): read 0x%" B_PRIx16 ".\n",
215 // __func__, connectorIndex, address);
219 memset(&message
, 0, sizeof(message
));
221 message
.address
= address
;
222 message
.buffer
= &response
;
223 message
.request
= DP_AUX_NATIVE_READ
;
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",
237 dp_aux_get_i2c_byte(uint32 connectorIndex
, uint16 address
, uint8
* data
,
238 bool start
, bool stop
)
242 memset(&message
, 0, sizeof(message
));
244 message
.address
= address
;
245 message
.buffer
= reply
;
246 message
.request
= DP_AUX_I2C_READ
;
249 // Remove Middle-Of-Transmission on final transaction
250 message
.request
|= DP_AUX_I2C_MOT
;
253 // Bare address packet
254 message
.buffer
= NULL
;
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__
);
265 switch (message
.reply
& DP_AUX_I2C_REPLY_MASK
) {
266 case DP_AUX_I2C_REPLY_ACK
:
269 case DP_AUX_I2C_REPLY_NACK
:
270 TRACE("%s: aux i2c nack\n", __func__
);
272 case DP_AUX_I2C_REPLY_DEFER
:
273 TRACE("%s: aux i2c defer\n", __func__
);
277 TRACE("%s: aux invalid I2C reply: 0x%02x\n",
278 __func__
, message
.reply
);
287 dp_aux_set_i2c_byte(uint32 connectorIndex
, uint16 address
, uint8
* data
,
288 bool start
, bool stop
)
291 memset(&message
, 0, sizeof(message
));
293 message
.address
= address
;
294 message
.buffer
= data
;
295 message
.request
= DP_AUX_I2C_WRITE
;
298 message
.request
|= DP_AUX_I2C_MOT
;
300 message
.buffer
= NULL
;
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__
);
310 switch (message
.reply
& DP_AUX_I2C_REPLY_MASK
) {
311 case DP_AUX_I2C_REPLY_ACK
:
313 case DP_AUX_I2C_REPLY_NACK
:
314 ERROR("%s: aux i2c nack\n", __func__
);
316 case DP_AUX_I2C_REPLY_DEFER
:
317 TRACE("%s: aux i2c defer\n", __func__
);
321 ERROR("%s: aux invalid I2C reply: 0x%02x\n", __func__
,
332 dp_get_encoder_config(uint32 connectorIndex
)
336 uint32 digEncoderID
= encoder_pick_dig(connectorIndex
);
338 result
|= ATOM_DP_CONFIG_DIG2_ENCODER
;
340 result
|= ATOM_DP_CONFIG_DIG1_ENCODER
;
342 bool linkB
= gConnector
[connectorIndex
]->encoder
.linkEnumeration
343 == GRAPH_OBJECT_ENUM_ID2
? true : false;
345 result
|= ATOM_DP_CONFIG_LINK_B
;
347 result
|= ATOM_DP_CONFIG_LINK_A
;
354 dp_get_lane_count(uint32 connectorIndex
, display_mode
* mode
)
357 size_t pixelsPerChunk
;
358 status_t result
= dp_get_pixel_size_for((color_space
)mode
->space
,
359 &pixelChunk
, NULL
, &pixelsPerChunk
);
361 if (result
!= B_OK
) {
362 TRACE("%s: Invalid color space!\n", __func__
);
366 uint32 bitsPerPixel
= (pixelChunk
/ pixelsPerChunk
) * 8;
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
;
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
,
378 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
382 TRACE("%s: Lanes: %" B_PRIu32
"\n", __func__
, lane
);
388 dp_get_link_rate(uint32 connectorIndex
, display_mode
* mode
)
390 uint16 encoderID
= gConnector
[connectorIndex
]->encoderExternal
.objectID
;
392 if (encoderID
== ENCODER_OBJECT_ID_NUTMEG
)
396 size_t pixelsPerChunk
;
397 status_t result
= dp_get_pixel_size_for((color_space
)mode
->space
,
398 &pixelChunk
, NULL
, &pixelsPerChunk
);
400 if (result
!= B_OK
) {
401 TRACE("%s: Invalid color space!\n", __func__
);
405 uint32 bitsPerPixel
= (pixelChunk
/ pixelsPerChunk
) * 8;
406 uint32 laneCount
= dp_get_lane_count(connectorIndex
, mode
);
409 = dp_get_pixel_clock_max(162000, laneCount
, bitsPerPixel
);
410 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
413 maxPixelClock
= dp_get_pixel_clock_max(270000, laneCount
, bitsPerPixel
);
414 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
417 // TODO: DisplayPort 1.2
419 if (dp_is_dp12_capable(connectorIndex
)) {
420 maxPixelClock
= dp_get_pixel_clock_max(540000, laneCount
, bitsPerPixel
);
421 if (mode
->timing
.pixel_clock
<= maxPixelClock
)
426 return dp_decode_link_rate(dpcd_reg_read(connectorIndex
, DP_MAX_LINK_RATE
));
431 dp_encoder_service(int action
, int linkRate
, uint8 lane
, uint8 config
)
433 DP_ENCODER_SERVICE_PARAMETERS args
;
434 int index
= GetIndexIntoMasterTable(COMMAND
, DPEncoderService
);
436 memset(&args
, 0, sizeof(args
));
437 args
.ucLinkClock
= linkRate
/ 10;
438 args
.ucConfig
= config
;
439 args
.ucAction
= action
;
440 args
.ucLaneNum
= lane
;
443 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
444 return args
.ucStatus
;
449 dp_get_sink_type(uint32 connectorIndex
)
451 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
452 return dp_encoder_service(ATOM_DP_ACTION_GET_SINK_TYPE
, 0, 0,
458 dp_setup_connectors()
460 TRACE("%s\n", __func__
);
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;
471 // Configure communication pins.
472 uint32 i2cPinIndex
= gConnector
[index
]->i2cPinIndex
;
473 uint32 auxPin
= gGPIOInfo
[i2cPinIndex
]->hwPin
;
474 dpInfo
->auxPin
= auxPin
;
475 dpInfo
->valid
= true;
481 dp_get_link_status(uint32 connectorIndex
)
483 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
486 memset(&message
, 0, sizeof(message
));
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
;
493 // TODO: Delay 100? Newer AMD code doesn't care about link status
494 status_t result
= dp_aux_transaction(connectorIndex
, &message
);
496 if (result
!= B_OK
) {
497 ERROR("%s: DisplayPort link status failed\n", __func__
);
506 dp_get_lane_status(dp_info
* dp
, int lane
)
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;
516 dp_clock_recovery_ok(dp_info
* dp
)
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)
531 dp_clock_equalization_ok(dp_info
* dp
)
534 = dp
->linkStatus
[DP_LANE_ALIGN
- DP_LANE_STATUS_0_1
];
536 if ((laneAlignment
& DP_LANE_ALIGN_DONE
) == 0) {
537 TRACE("%s: false. Lane alignment incomplete.\n", __func__
);
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__
);
550 TRACE("%s: true. Lanes equalized.\n", __func__
);
556 dp_update_vs_emph(uint32 connectorIndex
)
558 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
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
);
565 memset(&message
, 0, sizeof(message
));
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
);
577 dp_get_adjust_request_voltage(dp_info
* dp
, int lane
)
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
];
584 return ((l
>> s
) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT
;
589 dp_get_adjust_request_pre_emphasis(dp_info
* dp
, int lane
)
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
];
596 return ((l
>> s
) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT
;
601 dp_get_adjust_train(dp_info
* dp
)
603 TRACE("%s\n", __func__
);
605 const char* voltageNames
[] = {
606 "0.4V", "0.6V", "0.8V", "1.2V"
608 const char* preEmphasisNames
[] = {
609 "0dB", "3.5dB", "6dB", "9.5dB"
613 uint8 preEmphasis
= 0;
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
);
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
],
625 if (laneVoltage
> voltage
)
626 voltage
= laneVoltage
;
627 if (lanePreEmphasis
> preEmphasis
)
628 preEmphasis
= lanePreEmphasis
;
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
;
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
;
639 for (lane
= 0; lane
< 4; lane
++)
640 dp
->trainingSet
[lane
] = voltage
| preEmphasis
;
645 dp_set_tp(uint32 connectorIndex
, int trainingPattern
)
647 TRACE("%s\n", __func__
);
648 radeon_shared_info
&info
= *gInfo
->shared_info
;
650 pll_info
* pll
= &gConnector
[connectorIndex
]->encoder
.pll
;
652 int rawTrainingPattern
= 0;
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
;
660 case DP_TRAIN_PATTERN_2
:
661 rawTrainingPattern
= ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2
;
663 case DP_TRAIN_PATTERN_3
:
664 rawTrainingPattern
= ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3
;
667 encoder_dig_setup(connectorIndex
, pll
->pixelClock
, rawTrainingPattern
);
669 switch (trainingPattern
) {
670 case DP_TRAIN_PATTERN_1
:
671 rawTrainingPattern
= 0;
673 case DP_TRAIN_PATTERN_2
:
674 rawTrainingPattern
= 1;
677 uint32 encoderConfig
= dp_get_encoder_config(connectorIndex
);
678 dp_encoder_service(ATOM_DP_ACTION_TRAINING_PATTERN_SEL
, pll
->pixelClock
,
679 rawTrainingPattern
, encoderConfig
);
682 // Enable training pattern on the sink
683 dpcd_reg_write(connectorIndex
, DP_TRAIN
, trainingPattern
);
688 dp_link_train_cr(uint32 connectorIndex
)
690 TRACE("%s: connector %" B_PRIu32
"\n", __func__
, connectorIndex
);
692 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
694 // Display Port Clock Recovery Training
696 bool clockRecovery
= false;
697 uint8 voltage
= 0xff;
700 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_1
);
701 memset(dp
->trainingSet
, 0, 4);
702 dp_update_vs_emph(connectorIndex
);
706 if (dp
->trainingReadInterval
== 0)
709 snooze(1000 * 4 * dp
->trainingReadInterval
);
711 if (!dp_get_link_status(connectorIndex
))
714 if (dp_clock_recovery_ok(dp
)) {
715 clockRecovery
= true;
719 for (lane
= 0; lane
< dp
->laneCount
; lane
++) {
720 if ((dp
->trainingSet
[lane
] & DP_TRAIN_MAX_SWING_EN
) == 0)
724 if (lane
== dp
->laneCount
) {
725 ERROR("%s: clock recovery reached max voltage\n", __func__
);
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__
);
736 dp
->trainingAttempts
= 0;
738 voltage
= dp
->trainingSet
[0] & DP_TRAIN_VCC_SWING_MASK
;
740 // Compute new trainingSet as requested by sink
741 dp_get_adjust_train(dp
);
743 dp_update_vs_emph(connectorIndex
);
746 if (!clockRecovery
) {
747 ERROR("%s: clock recovery failed\n", __func__
);
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
);
760 dp_link_train_ce(uint32 connectorIndex
, bool tp3Support
)
762 TRACE("%s: connector %" B_PRIu32
"\n", __func__
, connectorIndex
);
764 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
767 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_3
);
769 dp_set_tp(connectorIndex
, DP_TRAIN_PATTERN_2
);
771 dp
->trainingAttempts
= 0;
772 bool channelEqual
= false;
775 if (dp
->trainingReadInterval
== 0)
778 snooze(1000 * 4 * dp
->trainingReadInterval
);
780 if (!dp_get_link_status(connectorIndex
)) {
781 ERROR("%s: ERROR: Unable to get link status!\n", __func__
);
785 if (dp_clock_equalization_ok(dp
)) {
790 if (dp
->trainingAttempts
> 5) {
791 ERROR("%s: ERROR: failed > 5 times!\n", __func__
);
795 dp_get_adjust_train(dp
);
797 dp_update_vs_emph(connectorIndex
);
798 dp
->trainingAttempts
++;
802 ERROR("%s: ERROR: failed\n", __func__
);
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
);
816 dp_link_train(uint8 crtcID
)
818 TRACE("%s\n", __func__
);
820 uint32 connectorIndex
= gDisplay
[crtcID
]->connectorIndex
;
821 dp_info
* dp
= &gConnector
[connectorIndex
]->dpInfo
;
822 display_mode
* mode
= &gDisplay
[crtcID
]->currentMode
;
824 if (dp
->valid
!= true) {
825 ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32
"\n",
826 __func__
, connectorIndex
);
830 dp
->revision
= dpcd_reg_read(connectorIndex
, DP_DPCD_REV
);
831 dp
->trainingReadInterval
832 = dpcd_reg_read(connectorIndex
, DP_TRAINING_AUX_RD_INTERVAL
);
834 uint8 sandbox
= dpcd_reg_read(connectorIndex
, DP_MAX_LANE_COUNT
);
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;
841 // *** DisplayPort link training initialization
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
);
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
);
852 dpcd_reg_write(connectorIndex
, DP_DOWNSPREAD_CTRL
, 0);
854 encoder_dig_setup(connectorIndex
, mode
->timing
.pixel_clock
,
855 ATOM_ENCODER_CMD_SETUP_PANEL_MODE
);
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
;
864 dpcd_reg_write(connectorIndex
, DP_LANE_COUNT
, sandbox
);
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
);
870 uint32 encoderConfig
= dp_get_encoder_config(connectorIndex
);
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
);
877 dp_encoder_service(ATOM_DP_ACTION_TRAINING_START
,
878 mode
->timing
.pixel_clock
, 0, encoderConfig
);
881 // Disable the training pattern on the sink
882 dpcd_reg_write(connectorIndex
, DP_TRAIN
, DP_TRAIN_PATTERN_DISABLED
);
884 dp_link_train_cr(connectorIndex
);
885 dp_link_train_ce(connectorIndex
, dpTPS3Supported
);
887 // *** DisplayPort link training finish
890 // Disable the training pattern on the sink
891 dpcd_reg_write(connectorIndex
, DP_TRAIN
, DP_TRAIN_PATTERN_DISABLED
);
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
);
898 dp_encoder_service(ATOM_DP_ACTION_TRAINING_COMPLETE
,
899 mode
->timing
.pixel_clock
, 0, encoderConfig
);
907 ddc2_dp_read_edid1(uint32 connectorIndex
, edid1_info
* edid
)
909 TRACE("%s\n", __func__
);
911 dp_info
* dpInfo
= &gConnector
[connectorIndex
]->dpInfo
;
913 if (!dpInfo
->valid
) {
914 ERROR("%s: connector(%" B_PRIu32
") missing valid DisplayPort data!\n",
915 __func__
, connectorIndex
);
920 uint8
* rdata
= (uint8
*)&raw
;
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
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);
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);
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);
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);
950 dp_aux_get_i2c_byte(connectorIndex
, 0x50, &sdata
, false, true);
952 if (raw
.version
.version
!= 1 || raw
.version
.revision
> 4) {
953 ERROR("%s: EDID version or revision out of range\n", __func__
);
957 edid_decode(edid
, &raw
);
964 dp_get_pixel_size_for(color_space space
, size_t *pixelChunk
,
965 size_t *rowAlignment
, size_t *pixelsPerChunk
)
967 status_t result
= get_pixel_size_for(space
, pixelChunk
, NULL
,
970 if ((space
== B_RGB32
) || (space
== B_RGBA32
) || (space
== B_RGB32_BIG
)
971 || (space
== B_RGBA32_BIG
)) {
980 dp_is_dp12_capable(uint32 connectorIndex
)
982 TRACE("%s\n", __func__
);
983 radeon_shared_info
&info
= *gInfo
->shared_info
;
985 uint32 capabilities
= gConnector
[connectorIndex
]->encoder
.capabilities
;
987 // DP_DPCD_REV_12 as well?
989 if (info
.dceMajor
>= 5
990 && gInfo
->dpExternalClock
>= 539000
991 && (capabilities
& ATOM_ENCODER_CAP_RECORD_HBR2
) != 0) {
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");
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
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
);
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",
1037 ERROR("==========================================\n");