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