1/*
2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz, mmlr@mlotz.ch
7 *		Alexander von Gluck IV, kallisti5@unixzen.com
8 */
9
10
11#include "FlexibleDisplayInterface.h"
12
13#include <stdlib.h>
14#include <string.h>
15#include <Debug.h>
16#include <KernelExport.h>
17
18#include "accelerant.h"
19#include "intel_extreme.h"
20
21
22#undef TRACE
23#define TRACE_FDI
24#ifdef TRACE_FDI
25#   define TRACE(x...) _sPrintf("intel_extreme: " x)
26#else
27#   define TRACE(x...)
28#endif
29
30#define ERROR(x...) _sPrintf("intel_extreme: " x)
31#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
32
33
34static const int gSnbBFDITrainParam[] = {
35	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
36	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
37	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
38	FDI_LINK_TRAIN_800MV_0DB_SNB_B,
39};
40
41
42// #pragma mark - FDITransmitter
43
44
45FDITransmitter::FDITransmitter(pipe_index pipeIndex)
46	:
47	fPipeIndex(pipeIndex)
48{
49}
50
51
52FDITransmitter::~FDITransmitter()
53{
54}
55
56
57void
58FDITransmitter::Enable()
59{
60	CALLED();
61	uint32 targetRegister = FDI_TX_CTL(fPipeIndex);
62	uint32 value = read32(targetRegister);
63
64	write32(targetRegister, value | FDI_TX_ENABLE);
65	read32(targetRegister);
66	spin(150);
67}
68
69
70void
71FDITransmitter::Disable()
72{
73	CALLED();
74	uint32 targetRegister = FDI_TX_CTL(fPipeIndex);
75	uint32 value = read32(targetRegister);
76
77	write32(targetRegister, value & ~FDI_TX_ENABLE);
78	read32(targetRegister);
79	spin(150);
80}
81
82
83bool
84FDITransmitter::IsPLLEnabled()
85{
86	CALLED();
87	return (read32(FDI_TX_CTL(fPipeIndex)) & FDI_TX_PLL_ENABLED) != 0;
88}
89
90
91void
92FDITransmitter::EnablePLL(uint32 lanes)
93{
94	CALLED();
95	uint32 targetRegister = FDI_TX_CTL(fPipeIndex);
96	uint32 value = read32(targetRegister);
97	if ((value & FDI_TX_PLL_ENABLED) != 0) {
98		// already enabled, possibly IronLake where it always is
99		TRACE("%s: Already enabled.\n", __func__);
100		return;
101	}
102
103	value &= ~FDI_DP_PORT_WIDTH_MASK;
104	value |= FDI_DP_PORT_WIDTH(lanes);
105
106	//first update config, -then- enable PLL to be sure config is indeed updated
107	write32(targetRegister, value);
108	read32(targetRegister);
109
110	write32(targetRegister, value | FDI_TX_PLL_ENABLED);
111	read32(targetRegister);
112	spin(100); // warmup 10us + dmi delay 20us, be generous
113}
114
115
116void
117FDITransmitter::DisablePLL()
118{
119	CALLED();
120	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_ILK)) {
121		// on IronLake the FDI PLL is always enabled, so no point in trying...
122		return;
123	}
124
125	uint32 targetRegister = FDI_TX_CTL(fPipeIndex);
126	write32(targetRegister, read32(targetRegister) & ~FDI_TX_PLL_ENABLED);
127	read32(targetRegister);
128	spin(100);
129}
130
131
132// #pragma mark - FDIReceiver
133
134
135FDIReceiver::FDIReceiver(pipe_index pipeIndex)
136	:
137	fPipeIndex(pipeIndex)
138{
139}
140
141
142FDIReceiver::~FDIReceiver()
143{
144}
145
146
147void
148FDIReceiver::Enable()
149{
150	CALLED();
151	uint32 targetRegister = FDI_RX_CTL(fPipeIndex);
152	uint32 value = read32(targetRegister);
153
154	write32(targetRegister, value | FDI_RX_ENABLE);
155	read32(targetRegister);
156	spin(150);
157}
158
159
160void
161FDIReceiver::Disable()
162{
163	CALLED();
164	uint32 targetRegister = FDI_RX_CTL(fPipeIndex);
165	uint32 value = read32(targetRegister);
166
167	write32(targetRegister, value & ~FDI_RX_ENABLE);
168	read32(targetRegister);
169	spin(150);
170}
171
172
173bool
174FDIReceiver::IsPLLEnabled()
175{
176	CALLED();
177	return (read32(FDI_RX_CTL(fPipeIndex)) & FDI_RX_PLL_ENABLED) != 0;
178}
179
180
181void
182FDIReceiver::EnablePLL(uint32 lanes)
183{
184	CALLED();
185	uint32 targetRegister = FDI_RX_CTL(fPipeIndex);
186	uint32 value = read32(targetRegister);
187	if ((value & FDI_RX_PLL_ENABLED) != 0) {
188		// already enabled, possibly IronLake where it always is
189		TRACE("%s: Already enabled.\n", __func__);
190		return;
191	}
192
193	//Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8)
194	//currently using BIOS preconfigured setup
195	//value &= ~FDI_DP_PORT_WIDTH_MASK;
196	//value |= FDI_RX_LINK_BPC(INTEL_PIPE_8BPC);
197
198	value &= ~FDI_DP_PORT_WIDTH_MASK;
199	value |= FDI_DP_PORT_WIDTH(lanes);
200
201	//first update config, -then- enable PLL to be sure config is indeed updated
202	write32(targetRegister, value);
203	read32(targetRegister);
204
205	write32(targetRegister, value | FDI_RX_PLL_ENABLED);
206	read32(targetRegister);
207	spin(200); // warmup 10us + dmi delay 20us, be generous
208}
209
210
211void
212FDIReceiver::DisablePLL()
213{
214	CALLED();
215	uint32 targetRegister = FDI_RX_CTL(fPipeIndex);
216	write32(targetRegister, read32(targetRegister) & ~FDI_RX_PLL_ENABLED);
217	read32(targetRegister);
218	spin(100);
219}
220
221
222void
223FDIReceiver::SwitchClock(bool toPCDClock)
224{
225	CALLED();
226	uint32 targetRegister = FDI_RX_CTL(fPipeIndex);
227	write32(targetRegister, (read32(targetRegister) & ~FDI_RX_CLOCK_MASK)
228		| (toPCDClock ? FDI_RX_CLOCK_PCD : FDI_RX_CLOCK_RAW));
229	read32(targetRegister);
230	spin(200);
231}
232
233
234// #pragma mark - FDILink
235
236
237FDILink::FDILink(pipe_index pipeIndex)
238	:
239	fTransmitter(pipeIndex),
240	fReceiver(pipeIndex),
241	fPipeIndex(pipeIndex)
242{
243}
244
245
246status_t
247FDILink::PreTrain(display_timing* target, uint32* linkBandwidth, uint32* lanes, uint32* bitsPerPixel)
248{
249	CALLED();
250
251	uint32 txControl = FDI_TX_CTL(fPipeIndex);
252	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
253
254	//Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8)
255	*bitsPerPixel = ((read32(rxControl) & FDI_RX_LINK_BPC_MASK) >> FDI_RX_LINK_COLOR_SHIFT);
256	switch (*bitsPerPixel) {
257		case INTEL_PIPE_8BPC:
258			*bitsPerPixel = 24;
259			break;
260		case INTEL_PIPE_10BPC:
261			*bitsPerPixel = 30;
262			break;
263		case INTEL_PIPE_6BPC:
264			*bitsPerPixel = 18;
265			break;
266		case INTEL_PIPE_12BPC:
267			*bitsPerPixel = 36;
268			break;
269		default:
270			*bitsPerPixel = 0;
271			ERROR("%s: FDI illegal link colordepth set.\n", __func__);
272			return B_ERROR;
273	}
274	TRACE("%s: FDI Link %s:\n", __func__, (fPipeIndex == INTEL_PIPE_A) ? "A" : "B");
275	TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, *bitsPerPixel);
276
277	// Khz / 10. ( each output octet encoded as 10 bits.
278	*linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10;
279	//Reserving 5% bandwidth for possible spread spectrum clock use
280	uint32 bps = target->pixel_clock * *bitsPerPixel * 21 / 20;
281
282	//use DIV_ROUND_UP:
283	*lanes = (bps + (*linkBandwidth * 8) - 1) / (*linkBandwidth * 8);
284	//remove below line when link training is to be done
285	*lanes = ((read32(txControl) & FDI_DP_PORT_WIDTH_MASK) >> FDI_DP_PORT_WIDTH_SHIFT) + 1;
286
287	TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, *lanes);
288	//assuming we'll only use link A and B (not C)
289	if (*lanes > 4) {
290		ERROR("%s: FDI not enough lanes in hardware.\n", __func__);
291		return B_ERROR;
292	}
293
294	TRACE("%s: FDI TX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(txControl));
295	TRACE("%s: FDI RX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(rxControl));
296
297#if 0
298	//when link training is to be done re-enable this code
299
300	//The order of handling things is important here..
301	write32(txControl, read32(txControl) & ~FDI_TX_ENABLE);
302	read32(txControl);
303	write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE);
304	read32(rxControl);
305
306	write32(txControl, (read32(txControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1);
307	read32(txControl);
308	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
309		write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_PATTERN_MASK_CPT) | FDI_LINK_TRAIN_PATTERN_1_CPT);
310	} else {
311		write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1);
312	}
313	read32(rxControl);
314	spin(100);
315
316	// Disable FDI clocks
317	Receiver().SwitchClock(false);
318	Transmitter().DisablePLL();
319	Receiver().DisablePLL();
320#endif
321
322	return B_OK;
323}
324
325
326status_t
327FDILink::Train(display_timing* target, uint32 lanes)
328{
329	CALLED();
330
331	status_t result = B_OK;
332
333	uint32 txControl = FDI_TX_CTL(fPipeIndex);
334	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
335
336	//Set receiving end TU size bits to match sending end's setting
337	write32(FDI_RX_TUSIZE1(fPipeIndex), FDI_RX_TRANS_UNIT_MASK);
338	write32(FDI_RX_TUSIZE2(fPipeIndex), FDI_RX_TRANS_UNIT_MASK);
339
340#if 0
341	//when link training is to be done re-enable this code
342	// Enable FDI clocks
343	Receiver().EnablePLL(lanes);
344	Receiver().SwitchClock(true);
345	Transmitter().EnablePLL(lanes);
346
347	// TODO: Only _AutoTrain on IVYB Stepping B or later
348	// otherwise, _ManualTrain
349	if (gInfo->shared_info->device_type.Generation() >= 7)
350		result = _AutoTrain(lanes);
351	else if (gInfo->shared_info->device_type.Generation() == 6)
352		result = _SnbTrain(lanes);
353	else if (gInfo->shared_info->device_type.Generation() == 5)
354		result = _IlkTrain(lanes);
355	else
356		result = _NormalTrain(lanes);
357#endif
358
359	TRACE("%s: FDI TX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(txControl));
360	TRACE("%s: FDI RX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(rxControl));
361
362	if (result != B_OK)
363		ERROR("%s: FDI training fault.\n", __func__);
364
365	return result;
366}
367
368
369status_t
370FDILink::_NormalTrain(uint32 lanes)
371{
372	CALLED();
373	uint32 txControl = FDI_TX_CTL(fPipeIndex);
374	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
375
376	// Enable normal link training
377	uint32 tmp = read32(txControl);
378	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) {
379		tmp &= ~FDI_LINK_TRAIN_NONE_IVB;
380		tmp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
381	} else {
382		tmp &= ~FDI_LINK_TRAIN_NONE;
383		tmp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
384	}
385	write32(txControl, tmp);
386
387	tmp = read32(rxControl);
388	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
389		tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
390		tmp |= FDI_LINK_TRAIN_NORMAL_CPT;
391	} else {
392		tmp &= ~FDI_LINK_TRAIN_NONE;
393		tmp |= FDI_LINK_TRAIN_NONE;
394	}
395	write32(rxControl, tmp | FDI_RX_ENHANCE_FRAME_ENABLE);
396
397	// Wait 1x idle pattern
398	read32(rxControl);
399	spin(1000);
400
401	// Enable ecc on IVB
402	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) {
403		write32(rxControl, read32(rxControl)
404			| FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
405		read32(rxControl);
406	}
407
408	return B_OK;
409}
410
411
412status_t
413FDILink::_IlkTrain(uint32 lanes)
414{
415	CALLED();
416	uint32 txControl = FDI_TX_CTL(fPipeIndex);
417	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
418
419	// Train 1: unmask FDI RX Interrupt symbol_lock and bit_lock
420	uint32 tmp = read32(FDI_RX_IMR(fPipeIndex));
421	tmp &= ~FDI_RX_SYMBOL_LOCK;
422	tmp &= ~FDI_RX_BIT_LOCK;
423	write32(FDI_RX_IMR(fPipeIndex), tmp);
424	spin(150);
425
426	// Enable CPU FDI TX and RX
427	tmp = read32(txControl);
428	tmp &= ~FDI_DP_PORT_WIDTH_MASK;
429	tmp |= FDI_DP_PORT_WIDTH(lanes);
430	tmp &= ~FDI_LINK_TRAIN_NONE;
431	tmp |= FDI_LINK_TRAIN_PATTERN_1;
432	write32(txControl, tmp);
433	Transmitter().Enable();
434
435	tmp = read32(rxControl);
436	tmp &= ~FDI_LINK_TRAIN_NONE;
437	tmp |= FDI_LINK_TRAIN_PATTERN_1;
438	write32(rxControl, tmp);
439	Receiver().Enable();
440
441	// ILK Workaround, enable clk after FDI enable
442	if (fPipeIndex == INTEL_PIPE_B) {
443		write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR);
444		write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR
445			| FDI_RX_PHASE_SYNC_POINTER_EN);
446	} else {
447		write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR);
448		write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR
449			| FDI_RX_PHASE_SYNC_POINTER_EN);
450	}
451
452	uint32 iirControl = FDI_RX_IIR(fPipeIndex);
453	TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl);
454
455	int tries = 0;
456	for (tries = 0; tries < 5; tries++) {
457		tmp = read32(iirControl);
458		TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp);
459
460		if ((tmp & FDI_RX_BIT_LOCK)) {
461			TRACE("%s: FDI train 1 done\n", __func__);
462			write32(iirControl, tmp | FDI_RX_BIT_LOCK);
463			break;
464		}
465	}
466
467	if (tries == 5) {
468		ERROR("%s: FDI train 1 failure!\n", __func__);
469		return B_ERROR;
470	}
471
472	// Train 2
473	tmp = read32(txControl);
474	tmp &= ~FDI_LINK_TRAIN_NONE;
475	tmp |= FDI_LINK_TRAIN_PATTERN_2;
476	write32(txControl, tmp);
477
478	tmp = read32(rxControl);
479	tmp &= ~FDI_LINK_TRAIN_NONE;
480	tmp |= FDI_LINK_TRAIN_PATTERN_2;
481	write32(rxControl, tmp);
482
483	read32(rxControl);
484	spin(150);
485
486	for (tries = 0; tries < 5; tries++) {
487		tmp = read32(iirControl);
488		TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp);
489
490		if (tmp & FDI_RX_SYMBOL_LOCK) {
491			TRACE("%s: FDI train 2 done\n", __func__);
492			write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK);
493			break;
494		}
495	}
496
497	if (tries == 5) {
498		ERROR("%s: FDI train 2 failure!\n", __func__);
499		return B_ERROR;
500	}
501
502	return B_OK;
503}
504
505
506status_t
507FDILink::_SnbTrain(uint32 lanes)
508{
509	CALLED();
510	uint32 txControl = FDI_TX_CTL(fPipeIndex);
511	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
512
513	// Train 1
514	uint32 imrControl = FDI_RX_IMR(fPipeIndex);
515	uint32 tmp = read32(imrControl);
516	tmp &= ~FDI_RX_SYMBOL_LOCK;
517	tmp &= ~FDI_RX_BIT_LOCK;
518	write32(imrControl, tmp);
519	read32(imrControl);
520	spin(150);
521
522	tmp = read32(txControl);
523	tmp &= ~FDI_DP_PORT_WIDTH_MASK;
524	tmp |= FDI_DP_PORT_WIDTH(lanes);
525	tmp &= ~FDI_LINK_TRAIN_NONE;
526	tmp |= FDI_LINK_TRAIN_PATTERN_1;
527	tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
528
529	tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
530	write32(txControl, tmp);
531
532	write32(FDI_RX_MISC(fPipeIndex),
533		FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
534
535	tmp = read32(rxControl);
536	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
537		tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
538		tmp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
539	} else {
540		tmp &= ~FDI_LINK_TRAIN_NONE;
541		tmp |= FDI_LINK_TRAIN_PATTERN_1;
542	}
543	write32(rxControl, tmp);
544	Receiver().Enable();
545
546	uint32 iirControl = FDI_RX_IIR(fPipeIndex);
547	TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl);
548
549	int i = 0;
550	for (i = 0; i < 4; i++) {
551		tmp = read32(txControl);
552		tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
553		tmp |= gSnbBFDITrainParam[i];
554		write32(txControl, tmp);
555
556		read32(txControl);
557		spin(500);
558
559		int retry = 0;
560		for (retry = 0; retry < 5; retry++) {
561			tmp = read32(iirControl);
562			TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp);
563			if (tmp & FDI_RX_BIT_LOCK) {
564				TRACE("%s: FDI train 1 done\n", __func__);
565				write32(iirControl, tmp | FDI_RX_BIT_LOCK);
566				break;
567			}
568			spin(50);
569		}
570		if (retry < 5)
571			break;
572	}
573
574	if (i == 4) {
575		ERROR("%s: FDI train 1 failure!\n", __func__);
576		return B_ERROR;
577	}
578
579	// Train 2
580	tmp = read32(txControl);
581	tmp &= ~FDI_LINK_TRAIN_NONE;
582	tmp |= FDI_LINK_TRAIN_PATTERN_2;
583
584	// if gen6? It's always gen6
585	tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
586	tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
587	write32(txControl, tmp);
588
589	tmp = read32(rxControl);
590	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
591		tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
592		tmp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
593	} else {
594		tmp &= ~FDI_LINK_TRAIN_NONE;
595		tmp |= FDI_LINK_TRAIN_PATTERN_2;
596	}
597	write32(rxControl, tmp);
598
599	read32(rxControl);
600	spin(150);
601
602	for (i = 0; i < 4; i++) {
603		tmp = read32(txControl);
604		tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
605		tmp |= gSnbBFDITrainParam[i];
606		write32(txControl, tmp);
607
608		read32(txControl);
609		spin(500);
610
611		int retry = 0;
612		for (retry = 0; retry < 5; retry++) {
613			tmp = read32(iirControl);
614			TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp);
615
616			if (tmp & FDI_RX_SYMBOL_LOCK) {
617				TRACE("%s: FDI train 2 done\n", __func__);
618				write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK);
619				break;
620			}
621			spin(50);
622		}
623		if (retry < 5)
624			break;
625	}
626
627	if (i == 4) {
628		ERROR("%s: FDI train 1 failure!\n", __func__);
629		return B_ERROR;
630	}
631
632	return B_OK;
633}
634
635
636status_t
637FDILink::_ManualTrain(uint32 lanes)
638{
639	CALLED();
640	//uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL;
641	//uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL;
642
643	ERROR("%s: TODO\n", __func__);
644
645	return B_ERROR;
646}
647
648
649status_t
650FDILink::_AutoTrain(uint32 lanes)
651{
652	CALLED();
653	uint32 txControl = FDI_TX_CTL(fPipeIndex);
654	uint32 rxControl = FDI_RX_CTL(fPipeIndex);
655
656	uint32 buffer = read32(txControl);
657
658	// Clear port width selection and set number of lanes
659	// fixme: does not belong in the train routines (?), (now) sits in FDI EnablePLL() routines
660	buffer &= ~(7 << 19);
661	buffer |= (lanes - 1) << 19;
662
663	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB))
664		buffer &= ~FDI_LINK_TRAIN_NONE_IVB;
665	else
666		buffer &= ~FDI_LINK_TRAIN_NONE;
667	write32(txControl, buffer);
668
669	write32(FDI_RX_MISC(fPipeIndex), FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
670
671	bool trained = false;
672
673	for (uint32 i = 0; i < (sizeof(gSnbBFDITrainParam)
674		/ sizeof(gSnbBFDITrainParam[0])); i++) {
675		for (int j = 0; j < 2; j++) {
676			buffer = read32(txControl);
677			buffer |= FDI_AUTO_TRAINING;
678			buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
679			buffer |= gSnbBFDITrainParam[i];
680			write32(txControl, buffer | FDI_TX_ENABLE);
681			read32(txControl);
682			write32(rxControl, read32(rxControl) | FDI_RX_ENABLE);
683			read32(rxControl);
684
685			spin(50);//looks like datasheet specified 5uS is not enough..?
686
687			buffer = read32(txControl);
688			if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) {
689				TRACE("%s: FDI auto train complete!\n", __func__);
690				trained = true;
691				break;
692			}
693
694			write32(txControl, read32(txControl) & ~FDI_TX_ENABLE);
695			read32(txControl);
696			write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE);
697			read32(rxControl);
698
699			spin(31);
700		}
701
702		// If Trained, we fall out of autotraining
703		if (trained)
704			break;
705	}
706
707	if (!trained) {
708		ERROR("%s: FDI auto train failed!\n", __func__);
709		return B_ERROR;
710	}
711
712	// Enable ecc on IVB (and disable test pattern at sending and receiving end)
713	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) {
714		write32(rxControl, read32(rxControl)
715			| FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
716		read32(rxControl);
717		//enable normal pixels (kill testpattern)
718		write32(txControl, read32(txControl) | (0x3 << 8));
719		read32(txControl);
720	}
721
722	return B_OK;
723}
724
725
726FDILink::~FDILink()
727{
728}
729