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