xref: /haiku/src/add-ons/accelerants/radeon_hd/displayport.cpp (revision e688bf23d48bfd1216a0cacbdbda5e35a1bcd779)
1 /*
2  * Copyright 2011, 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  */
8 
9 
10 #include "displayport.h"
11 
12 #include <Debug.h>
13 
14 #include "accelerant_protos.h"
15 #include "connector.h"
16 #include "mode.h"
17 
18 
19 #undef TRACE
20 
21 #define TRACE_DP
22 #ifdef TRACE_DP
23 #   define TRACE(x...) _sPrintf("radeon_hd: " x)
24 #else
25 #   define TRACE(x...) ;
26 #endif
27 
28 #define ERROR(x...) _sPrintf("radeon_hd: " x)
29 
30 
31 static int
32 dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes,
33 	uint8* recv, int recvBytes, uint8 delay, uint8* ack)
34 {
35 	if (hwPin == 0) {
36 		ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__);
37 		return B_IO_ERROR;
38 	}
39 
40 	int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
41 
42 	// Build AtomBIOS Transaction
43 	union auxChannelTransaction {
44 		PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
45 		PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
46 	};
47 	union auxChannelTransaction args;
48 	memset(&args, 0, sizeof(args));
49 
50 	args.v1.lpAuxRequest = 0;
51 	args.v1.lpDataOut = 16;
52 	args.v1.ucDataOutLen = 0;
53 	args.v1.ucChannelID = hwPin;
54 	args.v1.ucDelay = delay / 10;
55 
56 	//if (ASIC_IS_DCE4(rdev))
57 	//	args.v2.ucHPD_ID = chan->rec.hpd;
58 
59 	unsigned char* base = (unsigned char*)gAtomContext->scratch;
60 	memcpy(base, send, sendBytes);
61 
62 	atom_execute_table(gAtomContext, index, (uint32*)&args);
63 
64 	*ack = args.v1.ucReplyStatus;
65 
66 	switch (args.v1.ucReplyStatus) {
67 		case 1:
68 			ERROR("%s: dp_aux_ch timeout!\n", __func__);
69 			return B_TIMED_OUT;
70 		case 2:
71 			ERROR("%s: dp_aux_ch flags not zero!\n", __func__);
72 			return B_BUSY;
73 		case 3:
74 			ERROR("%s: dp_aux_ch error!\n", __func__);
75 			return B_IO_ERROR;
76 	}
77 
78 	int recvLength = args.v1.ucDataOutLen;
79 	if (recvLength > recvBytes)
80 		recvLength = recvBytes;
81 
82 	if (recv && recvBytes)
83 		memcpy(recv, base + 16, recvLength);
84 
85 	return recvLength;
86 }
87 
88 
89 int
90 dp_aux_write(uint32 hwPin, uint16 address,
91 	uint8* send, uint8 sendBytes, uint8 delay)
92 {
93 	uint8 auxMessage[20];
94 	int auxMessageBytes = sendBytes + 4;
95 
96 	if (sendBytes > 16)
97 		return -1;
98 
99 	auxMessage[0] = address;
100 	auxMessage[1] = address >> 8;
101 	auxMessage[2] = AUX_NATIVE_WRITE << 4;
102 	auxMessage[3] = (auxMessageBytes << 4) | (sendBytes - 1);
103 	memcpy(&auxMessage[4], send, sendBytes);
104 
105 	uint8 retry;
106 	for (retry = 0; retry < 4; retry++) {
107 		uint8 ack;
108 		int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
109 			NULL, 0, delay, &ack);
110 
111 		if (result == B_BUSY)
112 			continue;
113 		else if (result < B_OK)
114 			return result;
115 
116 		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
117 			return sendBytes;
118 		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
119 			snooze(400);
120 		else
121 			return B_IO_ERROR;
122 	}
123 
124 	return B_IO_ERROR;
125 }
126 
127 
128 int
129 dp_aux_read(uint32 hwPin, uint16 address,
130 	uint8* recv, int recvBytes, uint8 delay)
131 {
132 	uint8 auxMessage[4];
133 	int auxMessageBytes = 4;
134 
135 	auxMessage[0] = address;
136 	auxMessage[1] = address >> 8;
137 	auxMessage[2] = AUX_NATIVE_READ << 4;
138 	auxMessage[3] = (auxMessageBytes << 4) | (recvBytes - 1);
139 
140 	uint8 retry;
141 	for (retry = 0; retry < 4; retry++) {
142 		uint8 ack;
143 		int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
144 			recv, recvBytes, delay, &ack);
145 
146 		if (result == B_BUSY)
147 			continue;
148 		else if (result < B_OK)
149 			return result;
150 
151 		if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
152 			return result;
153 		else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
154 			snooze(400);
155 		else
156 			return B_IO_ERROR;
157 	}
158 
159 	return B_IO_ERROR;
160 }
161 
162 
163 void
164 dpcd_reg_write(uint32 hwPin, uint16 address, uint8 value)
165 {
166 	dp_aux_write(hwPin, address, &value, 1, 0);
167 }
168 
169 
170 uint8
171 dpcd_reg_read(uint32 hwPin, uint16 address)
172 {
173 	uint8 value = 0;
174 	dp_aux_read(hwPin, address, &value, 1, 0);
175 
176 	return value;
177 }
178 
179 
180 status_t
181 dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end)
182 {
183 	uint8 auxMessage[5];
184 	int auxMessageBytes = 4; // 4 for read
185 
186 	/* Set up the command byte */
187 	auxMessage[2] = AUX_I2C_READ << 4;
188 	if (end == false)
189 		auxMessage[2] |= AUX_I2C_MOT << 4;
190 
191 	auxMessage[0] = address;
192 	auxMessage[1] = address >> 8;
193 
194 	auxMessage[3] = auxMessageBytes << 4;
195 
196 	int retry;
197 	for (retry = 0; retry < 4; retry++) {
198 		uint8 ack;
199 		uint8 reply[2];
200 		int replyBytes = 1;
201 
202 		int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
203 			reply, replyBytes, 0, &ack);
204 		if (result == B_BUSY)
205 			continue;
206 		else if (result < 0) {
207 			ERROR("%s: aux_ch failed: %d\n", __func__, result);
208 			return B_ERROR;
209 		}
210 
211 		switch (ack & AUX_NATIVE_REPLY_MASK) {
212 			case AUX_NATIVE_REPLY_ACK:
213 				// I2C-over-AUX Reply field is only valid for AUX_ACK
214 				break;
215 			case AUX_NATIVE_REPLY_NACK:
216 				TRACE("%s: aux_ch native nack\n", __func__);
217 				return B_IO_ERROR;
218 			case AUX_NATIVE_REPLY_DEFER:
219 				TRACE("%s: aux_ch native defer\n", __func__);
220 				snooze(400);
221 				continue;
222 			default:
223 				TRACE("%s: aux_ch invalid native reply: 0x%02x\n",
224 					__func__, ack);
225 				return B_ERROR;
226 		}
227 
228 		switch (ack & AUX_I2C_REPLY_MASK) {
229 			case AUX_I2C_REPLY_ACK:
230 				*data = reply[0];
231 				return B_OK;
232 			case AUX_I2C_REPLY_NACK:
233 				TRACE("%s: aux_i2c nack\n", __func__);
234 				return B_IO_ERROR;
235 			case AUX_I2C_REPLY_DEFER:
236 				TRACE("%s: aux_i2c defer\n", __func__);
237 				snooze(400);
238 				break;
239 			default:
240 				TRACE("%s: aux_i2c invalid native reply: 0x%02x\n",
241 					__func__, ack);
242 				return B_ERROR;
243 		}
244 	}
245 
246 	TRACE("%s: aux i2c too many retries, giving up.\n", __func__);
247 	return B_ERROR;
248 }
249 
250 
251 status_t
252 dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end)
253 {
254 	uint8 auxMessage[5];
255 	int auxMessageBytes = 5; // 5 for write
256 
257 	/* Set up the command byte */
258 	auxMessage[2] = AUX_I2C_WRITE << 4;
259 	if (end == false)
260 		auxMessage[2] |= AUX_I2C_MOT << 4;
261 
262 	auxMessage[0] = address;
263 	auxMessage[1] = address >> 8;
264 
265 	auxMessage[3] = auxMessageBytes << 4;
266 	auxMessage[4] = *data;
267 
268 	int retry;
269 	for (retry = 0; retry < 4; retry++) {
270 		uint8 ack;
271 		uint8 reply[2];
272 		int replyBytes = 1;
273 
274 		int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes,
275 			reply, replyBytes, 0, &ack);
276 		if (result == B_BUSY)
277 			continue;
278 		else if (result < 0) {
279 			ERROR("%s: aux_ch failed: %d\n", __func__, result);
280 			return B_ERROR;
281 		}
282 
283 		switch (ack & AUX_NATIVE_REPLY_MASK) {
284 			case AUX_NATIVE_REPLY_ACK:
285 				// I2C-over-AUX Reply field is only valid for AUX_ACK
286 				break;
287 			case AUX_NATIVE_REPLY_NACK:
288 				TRACE("%s: aux_ch native nack\n", __func__);
289 				return B_IO_ERROR;
290 			case AUX_NATIVE_REPLY_DEFER:
291 				TRACE("%s: aux_ch native defer\n", __func__);
292 				snooze(400);
293 				continue;
294 			default:
295 				TRACE("%s: aux_ch invalid native reply: 0x%02x\n",
296 					__func__, ack);
297 				return B_ERROR;
298 		}
299 
300 		switch (ack & AUX_I2C_REPLY_MASK) {
301 			case AUX_I2C_REPLY_ACK:
302 				// Success!
303 				return B_OK;
304 			case AUX_I2C_REPLY_NACK:
305 				TRACE("%s: aux_i2c nack\n", __func__);
306 				return B_IO_ERROR;
307 			case AUX_I2C_REPLY_DEFER:
308 				TRACE("%s: aux_i2c defer\n", __func__);
309 				snooze(400);
310 				break;
311 			default:
312 				TRACE("%s: aux_i2c invalid native reply: 0x%02x\n",
313 					__func__, ack);
314 				return B_ERROR;
315 		}
316 	}
317 
318 	TRACE("%s: aux i2c too many retries, giving up.\n", __func__);
319 	return B_OK;
320 }
321 
322 
323 uint32
324 dp_get_lane_count(uint32 connectorIndex, display_mode* mode)
325 {
326 	// Radeon specific
327 	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
328 
329 	size_t pixelChunk;
330 	size_t pixelsPerChunk;
331 	status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk,
332 		NULL, &pixelsPerChunk);
333 
334 	if (result != B_OK) {
335 		TRACE("%s: Invalid color space!\n", __func__);
336 		return 0;
337 	}
338 
339 	uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8;
340 
341 	uint32 dpMaxLinkRate = dp_get_link_rate_max(dpInfo);
342 	uint32 dpMaxLaneCount = dp_get_lane_count_max(dpInfo);
343 
344 	uint32 lane;
345 	for (lane = 1; lane < dpMaxLaneCount; lane <<= 1) {
346 		uint32 maxPixelClock = dp_get_pixel_clock_max(dpMaxLinkRate, lane,
347 			bitsPerPixel);
348 		if (mode->timing.pixel_clock <= maxPixelClock)
349 			break;
350 	}
351 
352 	TRACE("%s: Lanes: %" B_PRIu32 "\n", __func__, lane);
353 	return lane;
354 }
355 
356 
357 uint32
358 dp_get_link_rate(uint32 connectorIndex, display_mode* mode)
359 {
360 	uint16 encoderID = gConnector[connectorIndex]->encoderExternal.objectID;
361 
362 	if (encoderID == ENCODER_OBJECT_ID_NUTMEG)
363 		return 270000;
364 
365 	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
366 	uint32 laneCount = dp_get_lane_count(connectorIndex, mode);
367 
368 	size_t pixelChunk;
369 	size_t pixelsPerChunk;
370 	status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk,
371 		NULL, &pixelsPerChunk);
372 
373 	if (result != B_OK) {
374 		TRACE("%s: Invalid color space!\n", __func__);
375 		return 0;
376 	}
377 
378 	uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8;
379 
380 	uint32 maxPixelClock
381 		= dp_get_pixel_clock_max(162000, laneCount, bitsPerPixel);
382 	if (mode->timing.pixel_clock <= maxPixelClock)
383 		return 162000;
384 
385 	maxPixelClock = dp_get_pixel_clock_max(270000, laneCount, bitsPerPixel);
386 	if (mode->timing.pixel_clock <= maxPixelClock)
387 		return 270000;
388 
389 	// TODO: DisplayPort 1.2
390 	#if 0
391 	if (is_dp12_capable(connectorIndex)) {
392 		maxPixelClock = dp_get_pixel_clock_max(540000, laneCount, bitsPerPixel);
393 		if (mode->timing.pixel_clock <= maxPixelClock)
394 			return 540000;
395 	}
396 	#endif
397 
398 	return dp_get_link_rate_max(dpInfo);
399 }
400 
401 
402 void
403 dp_setup_connectors()
404 {
405 	TRACE("%s\n", __func__);
406 
407 	for (uint32 index = 0; index < ATOM_MAX_SUPPORTED_DEVICE; index++) {
408 		dp_info* dpInfo = &gConnector[index]->dpInfo;
409 		dpInfo->valid = false;
410 		if (gConnector[index]->valid == false) {
411 			dpInfo->config[0] = 0;
412 			continue;
413 		}
414 
415 		if (connector_is_dp(index) == false) {
416 			dpInfo->config[0] = 0;
417 			continue;
418 		}
419 
420 		uint32 gpioID = gConnector[index]->gpioID;
421 
422 		uint32 auxPin = gGPIOInfo[gpioID]->hwPin;
423 		dpInfo->auxPin = auxPin;
424 
425 		uint8 auxMessage[25];
426 		int result;
427 
428 		result = dp_aux_read(auxPin, DP_DPCD_REV, auxMessage, 8, 0);
429 		if (result > 0) {
430 			dpInfo->valid = true;
431 			memcpy(dpInfo->config, auxMessage, 8);
432 		}
433 	}
434 }
435 
436 
437 static bool
438 dp_get_link_status(dp_info* dp)
439 {
440 	int result = dp_aux_read(dp->auxPin, DP_LANE_STATUS_0_1,
441 		dp->linkStatus, DP_LINK_STATUS_SIZE, 100);
442 
443 	if (result <= 0) {
444 		ERROR("%s: DisplayPort link status failed\n", __func__);
445 		return false;
446 	}
447 
448 	return true;
449 }
450 
451 
452 static uint8
453 dp_get_lane_status(dp_info* dp, int lane)
454 {
455 	int i = DP_LANE_STATUS_0_1 + (lane >> 1);
456 	int s = (lane & 1) * 4;
457 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
458 	return (l >> s) & 0xf;
459 }
460 
461 
462 static bool
463 dp_clock_recovery_ok(dp_info* dp)
464 {
465 	int lane;
466 	uint8 laneStatus;
467 
468 	for (lane = 0; lane < dp->laneCount; lane++) {
469 		laneStatus = dp_get_lane_status(dp, lane);
470 		if ((laneStatus & DP_LANE_STATUS_CR_DONE_A) == 0)
471 			return false;
472 	}
473 	return true;
474 }
475 
476 
477 static bool
478 dp_clock_equalization_ok(dp_info* dp)
479 {
480 	uint8 laneAlignment
481 		= dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1];
482 
483 	if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0)
484 		return false;
485 
486 	int lane;
487 	for (lane = 0; lane < dp->laneCount; lane++) {
488 		uint8 laneStatus = dp_get_lane_status(dp, lane);
489 		if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A)
490 			!= DP_LANE_STATUS_EQUALIZED_A) {
491 			return false;
492 		}
493 	}
494 	return true;
495 }
496 
497 
498 static void
499 dp_update_vs_emph(uint32 connectorIndex)
500 {
501 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
502 
503 	// Set initial vs and emph on source
504 	transmitter_dig_setup(connectorIndex, dp->linkRate, 0,
505 		dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
506 
507 	// Set vs and emph on the sink
508 	dp_aux_write(dp->auxPin, DP_TRAIN_LANE0,
509 		dp->trainingSet, dp->laneCount, 0);
510 }
511 
512 
513 static uint8
514 dp_get_adjust_request_voltage(dp_info* dp, int lane)
515 {
516 	int i = DP_ADJ_REQUEST_0_1 + (lane >> 1);
517 	int s = (((lane & 1) != 0) ? DP_ADJ_VCC_SWING_LANEB_SHIFT
518 		: DP_ADJ_VCC_SWING_LANEA_SHIFT);
519 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
520 
521 	return ((l >> s) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT;
522 }
523 
524 
525 static uint8
526 dp_get_adjust_request_pre_emphasis(dp_info* dp, int lane)
527 {
528 	int i = DP_ADJ_REQUEST_0_1 + (lane >> 1);
529 	int s = (((lane & 1) != 0) ? DP_ADJ_PRE_EMPHASIS_LANEB_SHIFT
530 		: DP_ADJ_PRE_EMPHASIS_LANEA_SHIFT);
531 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
532 
533 	return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
534 }
535 
536 
537 static void
538 dp_get_adjust_train(dp_info* dp)
539 {
540 	TRACE("%s\n", __func__);
541 
542 	const char* voltageNames[] = {
543 		"0.4V", "0.6V", "0.8V", "1.2V"
544 	};
545 	const char* preEmphasisNames[] = {
546 		"0dB", "3.5dB", "6dB", "9.5dB"
547 	};
548 
549 	uint8 voltage = 0;
550 	uint8 preEmphasis = 0;
551 	int lane;
552 
553 	for (lane = 0; lane < dp->laneCount; lane++) {
554 		uint8 laneVoltage = dp_get_adjust_request_voltage(dp, lane);
555 		uint8 lanePreEmphasis = dp_get_adjust_request_pre_emphasis(dp, lane);
556 
557 		TRACE("%s: Requested %s at %s for lane %d\n", __func__,
558 			preEmphasisNames[lanePreEmphasis >> DP_TRAIN_PRE_EMPHASIS_SHIFT],
559 			voltageNames[laneVoltage >> DP_TRAIN_VCC_SWING_SHIFT],
560 			lane);
561 
562 		if (laneVoltage > voltage)
563 			voltage = laneVoltage;
564 		if (lanePreEmphasis > preEmphasis)
565 			preEmphasis = lanePreEmphasis;
566 	}
567 
568 	// Check for maximum voltage and toggle max if reached
569 	if (voltage >= DP_TRAIN_VCC_SWING_1200)
570 		voltage |= DP_TRAIN_MAX_SWING_EN;
571 
572 	// Check for maximum pre-emphasis and toggle max if reached
573 	if (preEmphasis >= DP_TRAIN_PRE_EMPHASIS_9_5)
574 		preEmphasis |= DP_TRAIN_MAX_EMPHASIS_EN;
575 
576 	for (lane = 0; lane < 4; lane++)
577 		dp->trainingSet[lane] = voltage | preEmphasis;
578 }
579 
580 
581 static void
582 dp_set_tp(uint32 connectorIndex, int trainingPattern)
583 {
584 	TRACE("%s\n", __func__);
585 
586 	radeon_shared_info &info = *gInfo->shared_info;
587 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
588 
589 	int rawTrainingPattern = 0;
590 
591 	/* set training pattern on the source */
592 	if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
593 		switch (trainingPattern) {
594 			case DP_TRAIN_PATTERN_1:
595 				rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
596 				break;
597 			case DP_TRAIN_PATTERN_2:
598 				rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
599 				break;
600 			case DP_TRAIN_PATTERN_3:
601 				rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
602 				break;
603 		}
604 		// TODO: PixelClock 0 ok?
605 		encoder_dig_setup(connectorIndex, 0, rawTrainingPattern);
606 	} else {
607 		ERROR("%s: TODO: dp_encoder_service\n", __func__);
608 		return;
609 		#if 0
610 		switch (trainingPattern) {
611 			case DP_TRAINING_PATTERN_1:
612 				rawTrainingPattern = 0;
613 				break;
614 			case DP_TRAINING_PATTERN_2:
615 				rawTrainingPattern = 1;
616 				break;
617 		}
618 		radeon_dp_encoder_service(dp_info->rdev,
619 			ATOM_DP_ACTION_TRAINING_PATTERN_SEL, dp_info->dp_clock,
620 			dp_info->enc_id, rawTrainingPattern);
621 		#endif
622 	}
623 
624 	// Enable training pattern on the sink
625 	dpcd_reg_write(dp->auxPin, DP_TRAIN, trainingPattern);
626 }
627 
628 
629 status_t
630 dp_link_train_cr(uint32 connectorIndex)
631 {
632 	TRACE("%s\n", __func__);
633 
634 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
635 
636 	// Display Port Clock Recovery Training
637 
638 	bool clockRecovery = false;
639 	uint8 voltage = 0xff;
640 	int lane;
641 
642 	dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
643 	memset(dp->trainingSet, 0, 4);
644 	dp_update_vs_emph(connectorIndex);
645 
646 	while (1) {
647 		if (dp->trainingReadInterval == 0)
648 			snooze(100);
649 		else
650 			snooze(1000 * 4 * dp->trainingReadInterval);
651 
652 		if (!dp_get_link_status(dp))
653 			break;
654 
655 		if (dp_clock_recovery_ok(dp)) {
656 			clockRecovery = true;
657 			break;
658 		}
659 
660 		for (lane = 0; lane < dp->laneCount; lane++) {
661 			if ((dp->trainingSet[lane] & DP_TRAIN_MAX_SWING_EN) == 0)
662 				break;
663 		}
664 
665 		if (lane == dp->laneCount) {
666 			ERROR("%s: clock recovery reached max voltage\n", __func__);
667 			break;
668 		}
669 
670 		if ((dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK) == voltage) {
671 			dp->trainingAttempts++;
672 			if (dp->trainingAttempts >= 5) {
673 				ERROR("%s: clock recovery tried 5 times\n", __func__);
674 				break;
675 			}
676 		} else
677 			dp->trainingAttempts = 0;
678 
679 		voltage = dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK;
680 
681 		// Compute new trainingSet as requested by sink
682 		dp_get_adjust_train(dp);
683 
684 		dp_update_vs_emph(connectorIndex);
685 	}
686 
687 	if (!clockRecovery) {
688 		ERROR("%s: clock recovery failed\n", __func__);
689 		return B_ERROR;
690 	}
691 
692 	TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n",
693 		__func__, dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK,
694 		(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
695 		>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
696 	return B_OK;
697 }
698 
699 
700 status_t
701 dp_link_train_ce(uint32 connectorIndex)
702 {
703 	TRACE("%s\n", __func__);
704 
705 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
706 
707 	// TODO: DisplayPort: Supports TP3?
708 	dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2);
709 
710 	dp->trainingAttempts = 0;
711 	bool channelEqual = false;
712 
713 	while (1) {
714 		if (dp->trainingReadInterval == 0)
715 			snooze(100);
716 		else
717 			snooze(1000 * 4 * dp->trainingReadInterval);
718 
719 		if (!dp_get_link_status(dp))
720 			break;
721 
722 		if (dp_clock_equalization_ok(dp)) {
723 			channelEqual = true;
724 			break;
725 		}
726 
727 		if (dp->trainingAttempts > 5) {
728 			ERROR("%s: ERROR: failed > 5 times!\n", __func__);
729 			break;
730 		}
731 
732 		dp_get_adjust_train(dp);
733 
734 		dp_update_vs_emph(connectorIndex);
735 		dp->trainingAttempts++;
736 	}
737 
738 	if (!channelEqual) {
739 		ERROR("%s: ERROR: failed\n", __func__);
740 		return B_ERROR;
741 	}
742 
743 	TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n",
744 		__func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK,
745 		(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
746 		>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
747 
748 	return B_OK;
749 }
750 
751 
752 status_t
753 dp_link_train(uint32 connectorIndex, display_mode* mode)
754 {
755 	TRACE("%s\n", __func__);
756 
757 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
758 
759 	if (dp->valid != true) {
760 		ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n",
761 			__func__, connectorIndex);
762 		return B_ERROR;
763 	}
764 
765 	int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
766 	// Table version
767 	uint8 tableMajor;
768 	uint8 tableMinor;
769 
770 	dp->trainingUseEncoder = true;
771 	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
772 		== B_OK) {
773 		if (tableMinor > 1) {
774 			// The AtomBIOS DPEncoderService greater then 1.1 can't program the
775 			// training pattern properly.
776 			dp->trainingUseEncoder = false;
777 		}
778 	}
779 
780 	uint32 linkEnumeration
781 		= gConnector[connectorIndex]->encoder.linkEnumeration;
782 	uint32 gpioID = gConnector[connectorIndex]->gpioID;
783 	uint32 hwPin = gGPIOInfo[gpioID]->hwPin;
784 
785 	uint32 dpEncoderID = 0;
786 	if (encoder_pick_dig(connectorIndex) > 0)
787 		dpEncoderID |= ATOM_DP_CONFIG_DIG2_ENCODER;
788 	else
789 		dpEncoderID |= ATOM_DP_CONFIG_DIG1_ENCODER;
790 	if (linkEnumeration == GRAPH_OBJECT_ENUM_ID2)
791 		dpEncoderID |= ATOM_DP_CONFIG_LINK_B;
792 	else
793 		dpEncoderID |= ATOM_DP_CONFIG_LINK_A;
794 
795 	dp->trainingReadInterval
796 		= dpcd_reg_read(hwPin, DP_TRAINING_AUX_RD_INTERVAL);
797 
798 	uint8 sandbox = dpcd_reg_read(hwPin, DP_MAX_LANE_COUNT);
799 
800 	radeon_shared_info &info = *gInfo->shared_info;
801 	//bool dpTPS3Supported = false;
802 	//if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0)
803 	//	dpTPS3Supported = true;
804 
805 	// *** DisplayPort link training initialization
806 
807 	// Power up the DP sink
808 	if (dp->config[0] >= DP_DPCD_REV_11)
809 		dpcd_reg_write(hwPin, DP_SET_POWER, DP_SET_POWER_D0);
810 
811 	// Possibly enable downspread on the sink
812 	if ((dp->config[3] & 0x1) != 0)
813 		dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_DOWNSPREAD_CTRL_AMP_EN);
814 	else
815 		dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0);
816 
817 	encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
818 		ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
819 
820 	if (dp->config[0] >= DP_DPCD_REV_11)
821 		sandbox |= DP_ENHANCED_FRAME_EN;
822 	dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox);
823 
824 	// Set the link rate on the DP sink
825 	sandbox = dp_encode_link_rate(dp->linkRate);
826 	dpcd_reg_write(hwPin, DP_LINK_RATE, sandbox);
827 
828 	// Start link training on source
829 	if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
830 		encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
831 			ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
832 	} else {
833 		ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n",
834 			__func__);
835 	}
836 
837 	// Disable the training pattern on the sink
838 	dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
839 
840 	dp_link_train_cr(connectorIndex);
841 	dp_link_train_ce(connectorIndex);
842 
843 	// *** DisplayPort link training finish
844 	snooze(400);
845 
846 	// Disable the training pattern on the sink
847 	dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
848 
849 	// Disable the training pattern on the source
850 	if (info.dceMajor >= 4 || !dp->trainingUseEncoder) {
851 		encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
852 			ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
853 	} else {
854 		ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n",
855 			__func__);
856 	}
857 
858 	return B_OK;
859 }
860 
861 
862 void
863 debug_dp_info()
864 {
865 	ERROR("Current DisplayPort Info =================\n");
866 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
867 		if (gConnector[id]->valid == true) {
868 			dp_info* dp = &gConnector[id]->dpInfo;
869 			ERROR("Connector #%" B_PRIu32 ") DP: %s\n", id,
870 				dp->valid ? "true" : "false");
871 
872 			if (!dp->valid)
873 				continue;
874 			ERROR(" + DP Config Data\n");
875 			ERROR("   - max lane count:          %d\n",
876 				dp->config[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK);
877 			ERROR("   - max link rate:           %d\n",
878 				dp->config[DP_MAX_LINK_RATE]);
879 			ERROR("   - receiver port count:     %d\n",
880 				dp->config[DP_NORP] & DP_NORP_MASK);
881 			ERROR("   - downstream port present: %s\n",
882 				(dp->config[DP_DOWNSTREAMPORT] & DP_DOWNSTREAMPORT_EN)
883 				? "yes" : "no");
884 			ERROR("   - downstream port count:   %d\n",
885 				dp->config[DP_DOWNSTREAMPORT_COUNT]
886 				& DP_DOWNSTREAMPORT_COUNT_MASK);
887 			ERROR(" + Training\n");
888 			ERROR("   - use encoder:             %s\n",
889 				dp->trainingUseEncoder ? "true" : "false");
890 			ERROR("   - attempts:                %" B_PRIu8 "\n",
891 				dp->trainingAttempts);
892 			ERROR("   - delay:                   %d\n",
893 				dp->trainingReadInterval);
894 			ERROR(" + Data\n");
895 			ERROR("   - auxPin:                  0x%" B_PRIX32"\n", dp->auxPin);
896 			ERROR(" + Video\n");
897 			ERROR("   - laneCount:               %d\n", dp->laneCount);
898 			ERROR("   - linkRate:                %" B_PRIu32 "\n",
899 				dp->linkRate);
900 		}
901 	}
902 	ERROR("==========================================\n");
903 }
904