xref: /haiku/src/add-ons/accelerants/radeon_hd/displayport.cpp (revision 7bdeef54a24d3417300f251af891df962b638b9b)
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 static uint8
409 dp_encoder_service(int action, int linkRate, uint8 lane, uint8 config)
410 {
411 	DP_ENCODER_SERVICE_PARAMETERS args;
412 	int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
413 
414 	memset(&args, 0, sizeof(args));
415 	args.ucLinkClock = linkRate / 10;
416 	args.ucConfig = config;
417 	args.ucAction = action;
418 	args.ucLaneNum = lane;
419 	args.ucStatus = 0;
420 
421 	atom_execute_table(gAtomContext, index, (uint32*)&args);
422 	return args.ucStatus;
423 }
424 
425 
426 uint8
427 dp_get_sink_type(uint32 connectorIndex)
428 {
429 	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
430 	return dp_encoder_service(ATOM_DP_ACTION_GET_SINK_TYPE, 0, 0,
431 		dpInfo->auxPin);
432 }
433 
434 
435 void
436 dp_setup_connectors()
437 {
438 	TRACE("%s\n", __func__);
439 
440 	for (uint32 index = 0; index < ATOM_MAX_SUPPORTED_DEVICE; index++) {
441 		dp_info* dpInfo = &gConnector[index]->dpInfo;
442 		dpInfo->valid = false;
443 		if (gConnector[index]->valid == false
444 			|| connector_is_dp(index) == false) {
445 			dpInfo->config[0] = 0;
446 			continue;
447 		}
448 
449 		TRACE("%s: found dp connector on index %" B_PRIu32 "\n",
450 			__func__, index);
451 		uint32 i2cPinIndex = gConnector[index]->i2cPinIndex;
452 
453 		uint32 auxPin = gGPIOInfo[i2cPinIndex]->hwPin;
454 		dpInfo->auxPin = auxPin;
455 
456 		dp_aux_msg message;
457 		memset(&message, 0, sizeof(message));
458 
459 		message.address = DP_DPCD_REV;
460 		message.request = DP_AUX_NATIVE_READ;
461 			// TODO: validate
462 		message.size = DP_DPCD_SIZE;
463 		message.buffer = dpInfo->config;
464 
465 		status_t result = dp_aux_transaction(index, &message);
466 
467 		if (result == B_OK) {
468 			dpInfo->valid = true;
469 			TRACE("%s: connector(%" B_PRIu32 "): successful read of DPCD\n",
470 				__func__, index);
471 		} else {
472 			TRACE("%s: connector(%" B_PRIu32 "): failed read of DPCD\n",
473 				__func__, index);
474 		}
475 		/*
476 		TRACE("%s: DPCD is ", __func__);
477 		uint32 position;
478 		for (position = 0; position < message.size; position++)
479 			_sPrintf("%02x ", message.buffer + position);
480 		_sPrintf("\n");
481 		*/
482 	}
483 }
484 
485 
486 bool
487 dp_get_link_status(uint32 connectorIndex)
488 {
489 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
490 
491 	dp_aux_msg message;
492 	memset(&message, 0, sizeof(message));
493 
494 	message.request = DP_AUX_NATIVE_READ;
495 	message.address = DP_LANE_STATUS_0_1;
496 	message.size = DP_LINK_STATUS_SIZE;
497 	message.buffer = dp->linkStatus;
498 
499 	// TODO: Delay 100? Newer AMD code doesn't care about link status
500 	status_t result = dp_aux_transaction(connectorIndex, &message);
501 
502 	if (result != B_OK) {
503 		ERROR("%s: DisplayPort link status failed\n", __func__);
504 		return false;
505 	}
506 
507 	return true;
508 }
509 
510 
511 static uint8
512 dp_get_lane_status(dp_info* dp, int lane)
513 {
514 	int i = DP_LANE_STATUS_0_1 + (lane >> 1);
515 	int s = (lane & 1) * 4;
516 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
517 	return (l >> s) & 0xf;
518 }
519 
520 
521 static bool
522 dp_clock_recovery_ok(dp_info* dp)
523 {
524 	int lane;
525 	uint8 laneStatus;
526 
527 	for (lane = 0; lane < dp->laneCount; lane++) {
528 		laneStatus = dp_get_lane_status(dp, lane);
529 		if ((laneStatus & DP_LANE_STATUS_CR_DONE_A) == 0)
530 			return false;
531 	}
532 	return true;
533 }
534 
535 
536 static bool
537 dp_clock_equalization_ok(dp_info* dp)
538 {
539 	uint8 laneAlignment
540 		= dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1];
541 
542 	if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0)
543 		return false;
544 
545 	int lane;
546 	for (lane = 0; lane < dp->laneCount; lane++) {
547 		uint8 laneStatus = dp_get_lane_status(dp, lane);
548 		if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A)
549 			!= DP_LANE_STATUS_EQUALIZED_A) {
550 			return false;
551 		}
552 	}
553 	return true;
554 }
555 
556 
557 static void
558 dp_update_vs_emph(uint32 connectorIndex)
559 {
560 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
561 
562 	// Set initial vs and emph on source
563 	transmitter_dig_setup(connectorIndex, dp->linkRate, 0,
564 		dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH);
565 
566 	dp_aux_msg message;
567 	memset(&message, 0, sizeof(message));
568 
569 	message.request = DP_AUX_NATIVE_WRITE;
570 	message.address = DP_TRAIN_LANE0;
571 	message.buffer = dp->trainingSet;
572 	message.size = dp->laneCount;
573 		// TODO: Review laneCount as it sounds strange.
574 	dp_aux_transaction(connectorIndex, &message);
575 }
576 
577 
578 static uint8
579 dp_get_adjust_request_voltage(dp_info* dp, int lane)
580 {
581 	int i = DP_ADJ_REQUEST_0_1 + (lane >> 1);
582 	int s = (((lane & 1) != 0) ? DP_ADJ_VCC_SWING_LANEB_SHIFT
583 		: DP_ADJ_VCC_SWING_LANEA_SHIFT);
584 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
585 
586 	return ((l >> s) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT;
587 }
588 
589 
590 static uint8
591 dp_get_adjust_request_pre_emphasis(dp_info* dp, int lane)
592 {
593 	int i = DP_ADJ_REQUEST_0_1 + (lane >> 1);
594 	int s = (((lane & 1) != 0) ? DP_ADJ_PRE_EMPHASIS_LANEB_SHIFT
595 		: DP_ADJ_PRE_EMPHASIS_LANEA_SHIFT);
596 	uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1];
597 
598 	return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
599 }
600 
601 
602 static void
603 dp_get_adjust_train(dp_info* dp)
604 {
605 	TRACE("%s\n", __func__);
606 
607 	const char* voltageNames[] = {
608 		"0.4V", "0.6V", "0.8V", "1.2V"
609 	};
610 	const char* preEmphasisNames[] = {
611 		"0dB", "3.5dB", "6dB", "9.5dB"
612 	};
613 
614 	uint8 voltage = 0;
615 	uint8 preEmphasis = 0;
616 	int lane;
617 
618 	for (lane = 0; lane < dp->laneCount; lane++) {
619 		uint8 laneVoltage = dp_get_adjust_request_voltage(dp, lane);
620 		uint8 lanePreEmphasis = dp_get_adjust_request_pre_emphasis(dp, lane);
621 
622 		TRACE("%s: Requested %s at %s for lane %d\n", __func__,
623 			preEmphasisNames[lanePreEmphasis >> DP_TRAIN_PRE_EMPHASIS_SHIFT],
624 			voltageNames[laneVoltage >> DP_TRAIN_VCC_SWING_SHIFT],
625 			lane);
626 
627 		if (laneVoltage > voltage)
628 			voltage = laneVoltage;
629 		if (lanePreEmphasis > preEmphasis)
630 			preEmphasis = lanePreEmphasis;
631 	}
632 
633 	// Check for maximum voltage and toggle max if reached
634 	if (voltage >= DP_TRAIN_VCC_SWING_1200)
635 		voltage |= DP_TRAIN_MAX_SWING_EN;
636 
637 	// Check for maximum pre-emphasis and toggle max if reached
638 	if (preEmphasis >= DP_TRAIN_PRE_EMPHASIS_9_5)
639 		preEmphasis |= DP_TRAIN_MAX_EMPHASIS_EN;
640 
641 	for (lane = 0; lane < 4; lane++)
642 		dp->trainingSet[lane] = voltage | preEmphasis;
643 }
644 
645 
646 static void
647 dp_set_tp(uint32 connectorIndex, int trainingPattern)
648 {
649 	TRACE("%s\n", __func__);
650 	pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
651 
652 	int rawTrainingPattern = 0;
653 
654 	/* set training pattern on the source */
655 	TRACE("%s: Training with encoder...\n", __func__);
656 	switch (trainingPattern) {
657 		case DP_TRAIN_PATTERN_1:
658 			rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
659 			break;
660 		case DP_TRAIN_PATTERN_2:
661 			rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
662 			break;
663 		case DP_TRAIN_PATTERN_3:
664 			rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
665 			break;
666 	}
667 	encoder_dig_setup(connectorIndex, pll->pixelClock, rawTrainingPattern);
668 
669 	// Enable training pattern on the sink
670 	dpcd_reg_write(connectorIndex, DP_TRAIN, trainingPattern);
671 }
672 
673 
674 status_t
675 dp_link_train_cr(uint32 connectorIndex)
676 {
677 	TRACE("%s\n", __func__);
678 
679 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
680 
681 	// Display Port Clock Recovery Training
682 
683 	bool clockRecovery = false;
684 	uint8 voltage = 0xff;
685 	int lane;
686 
687 	dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1);
688 	memset(dp->trainingSet, 0, 4);
689 	dp_update_vs_emph(connectorIndex);
690 	snooze(400);
691 
692 	while (1) {
693 		if (dp->trainingReadInterval == 0)
694 			snooze(100);
695 		else
696 			snooze(1000 * 4 * dp->trainingReadInterval);
697 
698 		if (!dp_get_link_status(connectorIndex))
699 			break;
700 
701 		if (dp_clock_recovery_ok(dp)) {
702 			clockRecovery = true;
703 			break;
704 		}
705 
706 		for (lane = 0; lane < dp->laneCount; lane++) {
707 			if ((dp->trainingSet[lane] & DP_TRAIN_MAX_SWING_EN) == 0)
708 				break;
709 		}
710 
711 		if (lane == dp->laneCount) {
712 			ERROR("%s: clock recovery reached max voltage\n", __func__);
713 			break;
714 		}
715 
716 		if ((dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK) == voltage) {
717 			dp->trainingAttempts++;
718 			if (dp->trainingAttempts >= 5) {
719 				ERROR("%s: clock recovery tried 5 times\n", __func__);
720 				break;
721 			}
722 		} else
723 			dp->trainingAttempts = 0;
724 
725 		voltage = dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK;
726 
727 		// Compute new trainingSet as requested by sink
728 		dp_get_adjust_train(dp);
729 
730 		dp_update_vs_emph(connectorIndex);
731 	}
732 
733 	if (!clockRecovery) {
734 		ERROR("%s: clock recovery failed\n", __func__);
735 		return B_ERROR;
736 	}
737 
738 	TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n",
739 		__func__, dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK,
740 		(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
741 		>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
742 	return B_OK;
743 }
744 
745 
746 status_t
747 dp_link_train_ce(uint32 connectorIndex, bool tp3Support)
748 {
749 	TRACE("%s\n", __func__);
750 
751 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
752 
753 	if (tp3Support)
754 		dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_3);
755 	else
756 		dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2);
757 
758 	dp->trainingAttempts = 0;
759 	bool channelEqual = false;
760 
761 	while (1) {
762 		if (dp->trainingReadInterval == 0)
763 			snooze(400);
764 		else
765 			snooze(1000 * 4 * dp->trainingReadInterval);
766 
767 		if (!dp_get_link_status(connectorIndex)) {
768 			ERROR("%s: ERROR: Unable to get link status!\n", __func__);
769 			break;
770 		}
771 
772 		if (dp_clock_equalization_ok(dp)) {
773 			channelEqual = true;
774 			break;
775 		}
776 
777 		if (dp->trainingAttempts > 5) {
778 			ERROR("%s: ERROR: failed > 5 times!\n", __func__);
779 			break;
780 		}
781 
782 		dp_get_adjust_train(dp);
783 
784 		dp_update_vs_emph(connectorIndex);
785 		dp->trainingAttempts++;
786 	}
787 
788 	if (!channelEqual) {
789 		ERROR("%s: ERROR: failed\n", __func__);
790 		return B_ERROR;
791 	}
792 
793 	TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n",
794 		__func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK,
795 		(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
796 		>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
797 
798 	return B_OK;
799 }
800 
801 
802 status_t
803 dp_link_train(uint8 crtcID)
804 {
805 	TRACE("%s\n", __func__);
806 
807 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
808 	dp_info* dp = &gConnector[connectorIndex]->dpInfo;
809 	display_mode* mode = &gDisplay[crtcID]->currentMode;
810 
811 	if (dp->valid != true) {
812 		ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n",
813 			__func__, connectorIndex);
814 		return B_ERROR;
815 	}
816 
817 	dp->trainingReadInterval
818 		= dpcd_reg_read(connectorIndex, DP_TRAINING_AUX_RD_INTERVAL);
819 
820 	uint8 sandbox = dpcd_reg_read(connectorIndex, DP_MAX_LANE_COUNT);
821 
822 	radeon_shared_info &info = *gInfo->shared_info;
823 	bool dpTPS3Supported = false;
824 	if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0)
825 		dpTPS3Supported = true;
826 
827 	// *** DisplayPort link training initialization
828 
829 	// Power up the DP sink
830 	if (dp->config[0] >= DP_DPCD_REV_11)
831 		dpcd_reg_write(connectorIndex, DP_SET_POWER, DP_SET_POWER_D0);
832 
833 	// Possibly enable downspread on the sink
834 	if ((dp->config[3] & 0x1) != 0) {
835 		dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL,
836 			DP_DOWNSPREAD_CTRL_AMP_EN);
837 	} else
838 		dpcd_reg_write(connectorIndex, DP_DOWNSPREAD_CTRL, 0);
839 
840 	encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
841 		ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
842 
843 	// TODO: Doesn't this overwrite important dpcd info?
844 	sandbox = dp->laneCount;
845 	if ((dp->config[0] >= DP_DPCD_REV_11)
846 		&& (dp->config[2] & DP_ENHANCED_FRAME_CAP_EN))
847 		sandbox |= DP_ENHANCED_FRAME_EN;
848 	dpcd_reg_write(connectorIndex, DP_LANE_COUNT, sandbox);
849 
850 	// Set the link rate on the DP sink
851 	sandbox = dp_encode_link_rate(dp->linkRate);
852 	dpcd_reg_write(connectorIndex, DP_LINK_RATE, sandbox);
853 
854 	// Start link training on source
855 	encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
856 		ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
857 
858 	// Disable the training pattern on the sink
859 	dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
860 
861 	dp_link_train_cr(connectorIndex);
862 	dp_link_train_ce(connectorIndex, dpTPS3Supported);
863 
864 	// *** DisplayPort link training finish
865 	snooze(400);
866 
867 	// Disable the training pattern on the sink
868 	dpcd_reg_write(connectorIndex, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
869 
870 	// Disable the training pattern on the source
871 	encoder_dig_setup(connectorIndex, mode->timing.pixel_clock,
872 		ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
873 
874 	return B_OK;
875 }
876 
877 
878 bool
879 ddc2_dp_read_edid1(uint32 connectorIndex, edid1_info* edid)
880 {
881 	TRACE("%s\n", __func__);
882 
883 	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
884 
885 	if (!dpInfo->valid) {
886 		ERROR("%s: connector(%" B_PRIu32 ") missing valid DisplayPort data!\n",
887 			__func__, connectorIndex);
888 		return false;
889 	}
890 
891 	edid1_raw raw;
892 	uint8* rdata = (uint8*)&raw;
893 	uint8 sdata = 0;
894 
895 	// The following sequence is from a trace of the Linux kernel
896 	// radeon code; not sure if the initial writes to address 0 are
897 	// requried.
898 	// TODO: This surely cane be cleaned up
899 	dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, true, false);
900 	dp_aux_set_i2c_byte(connectorIndex, 0x00, &sdata, false, true);
901 
902 	dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false);
903 	dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
904 	dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
905 	dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, false);
906 	dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, false, true);
907 
908 	dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, true, false);
909 	dp_aux_set_i2c_byte(connectorIndex, 0x50, &sdata, false, false);
910 	dp_aux_get_i2c_byte(connectorIndex, 0x50, rdata, true, false);
911 
912 	for (uint32 i = 0; i < sizeof(raw); i++) {
913 		status_t result = dp_aux_get_i2c_byte(connectorIndex, 0x50,
914 			rdata++, false, false);
915 		if (result != B_OK) {
916 			TRACE("%s: error reading EDID data at index %" B_PRIu32 ", "
917 				"result = 0x%" B_PRIx32 "\n", __func__, i, result);
918 			dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true);
919 			return false;
920 		}
921 	}
922 	dp_aux_get_i2c_byte(connectorIndex, 0x50, &sdata, false, true);
923 
924 	if (raw.version.version != 1 || raw.version.revision > 4) {
925 		ERROR("%s: EDID version or revision out of range\n", __func__);
926 		return false;
927 	}
928 
929 	edid_decode(edid, &raw);
930 
931 	return true;
932 }
933 
934 
935 status_t
936 dp_get_pixel_size_for(color_space space, size_t *pixelChunk,
937 	size_t *rowAlignment, size_t *pixelsPerChunk)
938 {
939 	status_t result = get_pixel_size_for(space, pixelChunk, NULL,
940 		pixelsPerChunk);
941 
942 	if ((space == B_RGB32) || (space == B_RGBA32) || (space == B_RGB32_BIG)
943 		|| (space == B_RGBA32_BIG)) {
944 		*pixelChunk = 3;
945 	}
946 
947 	return result;
948 }
949 
950 
951 bool
952 dp_is_dp12_capable(uint32 connectorIndex)
953 {
954 	TRACE("%s\n", __func__);
955 	radeon_shared_info &info = *gInfo->shared_info;
956 
957 	uint32 capabilities = gConnector[connectorIndex]->encoder.capabilities;
958 
959 	if (info.dceMajor >= 5
960 		&& gInfo->dpExternalClock >= 539000
961 		&& (capabilities & ATOM_ENCODER_CAP_RECORD_HBR2) != 0) {
962 		return true;
963 	}
964 
965 	return false;
966 }
967 
968 
969 void
970 debug_dp_info()
971 {
972 	ERROR("Current DisplayPort Info =================\n");
973 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
974 		if (gConnector[id]->valid == true) {
975 			dp_info* dp = &gConnector[id]->dpInfo;
976 			ERROR("Connector #%" B_PRIu32 ") DP: %s\n", id,
977 				dp->valid ? "true" : "false");
978 
979 			if (!dp->valid)
980 				continue;
981 			ERROR(" + DP Config Data\n");
982 			ERROR("   - max lane count:          %d\n",
983 				dp->config[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK);
984 			ERROR("   - max link rate:           %d\n",
985 				dp->config[DP_MAX_LINK_RATE]);
986 			ERROR("   - receiver port count:     %d\n",
987 				dp->config[DP_NORP] & DP_NORP_MASK);
988 			ERROR("   - downstream port present: %s\n",
989 				(dp->config[DP_DOWNSTREAMPORT] & DP_DOWNSTREAMPORT_EN)
990 				? "yes" : "no");
991 			ERROR("   - downstream port count:   %d\n",
992 				dp->config[DP_DOWNSTREAMPORT_COUNT]
993 				& DP_DOWNSTREAMPORT_COUNT_MASK);
994 			ERROR(" + Training\n");
995 			ERROR("   - attempts:                %" B_PRIu8 "\n",
996 				dp->trainingAttempts);
997 			ERROR("   - delay:                   %d\n",
998 				dp->trainingReadInterval);
999 			ERROR(" + Data\n");
1000 			ERROR("   - auxPin:                  0x%" B_PRIX32"\n", dp->auxPin);
1001 			ERROR(" + Video\n");
1002 			ERROR("   - laneCount:               %d\n", dp->laneCount);
1003 			ERROR("   - linkRate:                %" B_PRIu32 "\n",
1004 				dp->linkRate);
1005 		}
1006 	}
1007 	ERROR("==========================================\n");
1008 }
1009