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