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