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