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