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