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
34 static 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
FDITransmitter(pipe_index pipeIndex)45 FDITransmitter::FDITransmitter(pipe_index pipeIndex)
46 :
47 fPipeIndex(pipeIndex)
48 {
49 }
50
51
~FDITransmitter()52 FDITransmitter::~FDITransmitter()
53 {
54 }
55
56
57 void
Enable()58 FDITransmitter::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
70 void
Disable()71 FDITransmitter::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
83 bool
IsPLLEnabled()84 FDITransmitter::IsPLLEnabled()
85 {
86 CALLED();
87 return (read32(FDI_TX_CTL(fPipeIndex)) & FDI_TX_PLL_ENABLED) != 0;
88 }
89
90
91 void
EnablePLL(uint32 lanes)92 FDITransmitter::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
116 void
DisablePLL()117 FDITransmitter::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
FDIReceiver(pipe_index pipeIndex)135 FDIReceiver::FDIReceiver(pipe_index pipeIndex)
136 :
137 fPipeIndex(pipeIndex)
138 {
139 }
140
141
~FDIReceiver()142 FDIReceiver::~FDIReceiver()
143 {
144 }
145
146
147 void
Enable()148 FDIReceiver::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
160 void
Disable()161 FDIReceiver::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
173 bool
IsPLLEnabled()174 FDIReceiver::IsPLLEnabled()
175 {
176 CALLED();
177 return (read32(FDI_RX_CTL(fPipeIndex)) & FDI_RX_PLL_ENABLED) != 0;
178 }
179
180
181 void
EnablePLL(uint32 lanes)182 FDIReceiver::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
211 void
DisablePLL()212 FDIReceiver::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
222 void
SwitchClock(bool toPCDClock)223 FDIReceiver::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
FDILink(pipe_index pipeIndex)237 FDILink::FDILink(pipe_index pipeIndex)
238 :
239 fTransmitter(pipeIndex),
240 fReceiver(pipeIndex),
241 fPipeIndex(pipeIndex)
242 {
243 }
244
245
246 status_t
PreTrain(display_timing * target,uint32 * linkBandwidth,uint32 * lanes,uint32 * bitsPerPixel)247 FDILink::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
326 status_t
Train(display_timing * target,uint32 lanes)327 FDILink::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
369 status_t
_NormalTrain(uint32 lanes)370 FDILink::_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
412 status_t
_IlkTrain(uint32 lanes)413 FDILink::_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
506 status_t
_SnbTrain(uint32 lanes)507 FDILink::_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
636 status_t
_ManualTrain(uint32 lanes)637 FDILink::_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
649 status_t
_AutoTrain(uint32 lanes)650 FDILink::_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
~FDILink()726 FDILink::~FDILink()
727 {
728 }
729