vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon_hd / displayport.cpp
blob9249b6e468b3466094de2efe51a6b8251cff9c15
1 /*
2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Alexander von Gluck IV, kallisti5@unixzen.com
7 * Bill Randle, billr@neocat.org
8 */
11 #include "displayport.h"
13 #include <Debug.h>
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"
23 #undef TRACE
25 #define TRACE_DP
26 #ifdef TRACE_DP
27 # define TRACE(x...) _sPrintf("radeon_hd: " x)
28 #else
29 # define TRACE(x...) ;
30 #endif
32 #define ERROR(x...) _sPrintf("radeon_hd: " x)
35 static ssize_t
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__);
42 return B_IO_ERROR;
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) {
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;
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);
95 return recvLength;
99 status_t
100 dp_aux_transaction(uint32 connectorIndex, dp_aux_msg* message)
102 uint8 delay = 0;
103 if (message == NULL) {
104 ERROR("%s: DP message is invalid!\n", __func__);
105 return B_ERROR;
108 if (message->size > 16) {
109 ERROR("%s: Too many bytes! (%" B_PRIuSIZE ")\n", __func__,
110 message->size);
111 return B_ERROR;
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;
121 break;
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;
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;
138 else
139 auxMessage[3] |= transactionSize << 4;
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;
164 if (result == B_BUSY)
165 continue;
166 else if (result < B_OK)
167 return result;
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;
185 ERROR("%s: IO Error. %" B_PRIu8 " attempts\n", __func__, retry);
186 return B_IO_ERROR;
190 void
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);
195 dp_aux_msg message;
196 memset(&message, 0, sizeof(message));
198 message.address = address;
199 message.buffer = &value;
200 message.request = DP_AUX_NATIVE_WRITE;
201 message.size = 1;
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);
211 uint8
212 dpcd_reg_read(uint32 connectorIndex, uint16 address)
214 //TRACE("%s: connector(%" B_PRId32 "): read 0x%" B_PRIx16 ".\n",
215 // __func__, connectorIndex, address);
216 uint8 response[3];
218 dp_aux_msg message;
219 memset(&message, 0, sizeof(message));
221 message.address = address;
222 message.buffer = &response;
223 message.request = DP_AUX_NATIVE_READ;
224 message.size = 1;
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);
232 return response[0];
236 status_t
237 dp_aux_get_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data,
238 bool start, bool stop)
240 uint8 reply[3];
241 dp_aux_msg message;
242 memset(&message, 0, sizeof(message));
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;
252 if (stop || start) {
253 // Bare address packet
254 message.buffer = NULL;
255 message.size = 0;
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;
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;
282 return B_ERROR;
286 status_t
287 dp_aux_set_i2c_byte(uint32 connectorIndex, uint16 address, uint8* data,
288 bool start, bool stop)
290 dp_aux_msg message;
291 memset(&message, 0, sizeof(message));
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;
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;
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;
327 return B_ERROR;
331 uint32
332 dp_get_encoder_config(uint32 connectorIndex)
334 uint32 result = 0;
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;
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;
349 return result;
353 uint32
354 dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
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);
361 if (result != B_OK) {
362 TRACE("%s: Invalid color space!\n", __func__);
363 return 0;
366 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8;
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;
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;
382 TRACE("%s: Lanes: %" B_PRIu32 "\n", __func__, lane);
383 return lane;
387 uint32
388 dp_get_link_rate(uint32 connectorIndex, display_mode* mode)
390 uint16 encoderID = gConnector[connectorIndex]->encoderExternal.objectID;
392 if (encoderID == ENCODER_OBJECT_ID_NUTMEG)
393 return 270000;
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);
400 if (result != B_OK) {
401 TRACE("%s: Invalid color space!\n", __func__);
402 return 0;
405 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8;
406 uint32 laneCount = dp_get_lane_count(connectorIndex, mode);
408 uint32 maxPixelClock
409 = dp_get_pixel_clock_max(162000, laneCount, bitsPerPixel);
410 if (mode->timing.pixel_clock <= maxPixelClock)
411 return 162000;
413 maxPixelClock = dp_get_pixel_clock_max(270000, laneCount, bitsPerPixel);
414 if (mode->timing.pixel_clock <= maxPixelClock)
415 return 270000;
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;
424 #endif
426 return dp_decode_link_rate(dpcd_reg_read(connectorIndex, DP_MAX_LINK_RATE));
430 static uint8
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;
441 args.ucStatus = 0;
443 atom_execute_table(gAtomContext, index, (uint32*)&args);
444 return args.ucStatus;
448 uint8
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,
453 dpInfo->auxPin);
457 void
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;
468 continue;
471 // Configure communication pins.
472 uint32 i2cPinIndex = gConnector[index]->i2cPinIndex;
473 uint32 auxPin = gGPIOInfo[i2cPinIndex]->hwPin;
474 dpInfo->auxPin = auxPin;
475 dpInfo->valid = true;
480 bool
481 dp_get_link_status(uint32 connectorIndex)
483 dp_info* dp = &gConnector[connectorIndex]->dpInfo;
485 dp_aux_msg message;
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__);
498 return false;
501 return true;
505 static uint8
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;
515 static bool
516 dp_clock_recovery_ok(dp_info* dp)
518 int lane;
519 uint8 laneStatus;
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;
526 return true;
530 static bool
531 dp_clock_equalization_ok(dp_info* dp)
533 uint8 laneAlignment
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__);
538 return false;
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;
550 TRACE("%s: true. Lanes equalized.\n", __func__);
551 return true;
555 static void
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);
564 dp_aux_msg message;
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);
576 static uint8
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;
588 static uint8
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;
600 static void
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"
612 uint8 voltage = 0;
613 uint8 preEmphasis = 0;
614 int lane;
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],
623 lane);
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;
644 static void
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;
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;
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;
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);
687 status_t
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;
698 int lane;
700 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
701 memset(dp->trainingSet, 0, 4);
702 dp_update_vs_emph(connectorIndex);
703 snooze(400);
705 while (1) {
706 if (dp->trainingReadInterval == 0)
707 snooze(100);
708 else
709 snooze(1000 * 4 * dp->trainingReadInterval);
711 if (!dp_get_link_status(connectorIndex))
712 break;
714 if (dp_clock_recovery_ok(dp)) {
715 clockRecovery = true;
716 break;
719 for (lane = 0; lane < dp->laneCount; lane++) {
720 if ((dp->trainingSet[lane] & DP_TRAIN_MAX_SWING_EN) == 0)
721 break;
724 if (lane == dp->laneCount) {
725 ERROR("%s: clock recovery reached max voltage\n", __func__);
726 break;
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;
735 } else
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__);
748 return B_ERROR;
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;
759 status_t
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;
766 if (tp3Support)
767 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_3);
768 else
769 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2);
771 dp->trainingAttempts = 0;
772 bool channelEqual = false;
774 while (1) {
775 if (dp->trainingReadInterval == 0)
776 snooze(400);
777 else
778 snooze(1000 * 4 * dp->trainingReadInterval);
780 if (!dp_get_link_status(connectorIndex)) {
781 ERROR("%s: ERROR: Unable to get link status!\n", __func__);
782 break;
785 if (dp_clock_equalization_ok(dp)) {
786 channelEqual = true;
787 break;
790 if (dp->trainingAttempts > 5) {
791 ERROR("%s: ERROR: failed > 5 times!\n", __func__);
792 break;
795 dp_get_adjust_train(dp);
797 dp_update_vs_emph(connectorIndex);
798 dp->trainingAttempts++;
801 if (!channelEqual) {
802 ERROR("%s: ERROR: failed\n", __func__);
803 return B_ERROR;
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);
811 return B_OK;
815 status_t
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);
827 return B_ERROR;
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);
851 } else
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);
876 } else {
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
888 snooze(400);
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);
897 } else {
898 dp_encoder_service(ATOM_DP_ACTION_TRAINING_COMPLETE,
899 mode->timing.pixel_clock, 0, encoderConfig);
902 return B_OK;
906 bool
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);
916 return false;
919 edid1_raw raw;
920 uint8* rdata = (uint8*)&raw;
921 uint8 sdata = 0;
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);
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);
947 return false;
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__);
954 return false;
957 edid_decode(edid, &raw);
959 return true;
963 status_t
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,
968 pixelsPerChunk);
970 if ((space == B_RGB32) || (space == B_RGBA32) || (space == B_RGB32_BIG)
971 || (space == B_RGBA32_BIG)) {
972 *pixelChunk = 3;
975 return result;
979 bool
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) {
992 return true;
995 return false;
999 void
1000 debug_dp_info()
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");
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);
1037 ERROR("==========================================\n");