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 #include "Pipes.h"
10
11 #include "accelerant.h"
12 #include "accelerant_protos.h"
13 #include "intel_extreme.h"
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include <new>
19
20
21 #undef TRACE
22 #define TRACE_PIPE
23 #ifdef TRACE_PIPE
24 # define TRACE(x...) _sPrintf("intel_extreme: " x)
25 #else
26 # define TRACE(x...) ;
27 #endif
28
29 #define ERROR(x...) _sPrintf("intel_extreme: " x)
30 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
31
32
33 // PIPE: 6
34 // PLANE: 7
35
36
37 void
program_pipe_color_modes(uint32 colorMode)38 program_pipe_color_modes(uint32 colorMode)
39 {
40 // All pipes get the same color mode
41 if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_LAKE)) {
42 write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
43 & ~(DISPLAY_CONTROL_COLOR_MASK_SKY | DISPLAY_CONTROL_GAMMA))
44 | colorMode);
45 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
46 & ~(DISPLAY_CONTROL_COLOR_MASK_SKY | DISPLAY_CONTROL_GAMMA))
47 | colorMode);
48 } else {
49 write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
50 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
51 | colorMode);
52 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
53 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
54 | colorMode);
55 }
56 }
57
58
59 // #pragma mark - Pipe
60
61
Pipe(pipe_index pipeIndex)62 Pipe::Pipe(pipe_index pipeIndex)
63 :
64 fHasTranscoder(false),
65 fFDILink(NULL),
66 fPanelFitter(NULL),
67 fPipeIndex(pipeIndex),
68 fPipeOffset(0),
69 fPlaneOffset(0)
70 {
71 switch (pipeIndex) {
72 case INTEL_PIPE_B:
73 TRACE("Pipe B.\n");
74 fPipeOffset = 0x1000;
75 fPlaneOffset = INTEL_PLANE_OFFSET;
76 break;
77 case INTEL_PIPE_C:
78 TRACE("Pipe C.\n");
79 fPipeOffset = 0x2000;
80 fPlaneOffset = INTEL_PLANE_OFFSET * 2;
81 break;
82 case INTEL_PIPE_D:
83 TRACE("Pipe D.\n");
84 fPipeOffset = 0xf000;
85 //no fPlaneOffset..
86 break;
87 default:
88 TRACE("Pipe A.\n");
89 break;
90 }
91
92 // IvyBridge: Analog + Digital Ports behind FDI (on northbridge)
93 // Haswell: Only VGA behind FDI (on northbridge)
94 // SkyLake: FDI gone. No more northbridge video.
95 if ((gInfo->shared_info->pch_info != INTEL_PCH_NONE) &&
96 (gInfo->shared_info->device_type.Generation() <= 8)) {
97 TRACE("%s: Pipe is routed through FDI\n", __func__);
98
99 // Program FDILink if PCH
100 fFDILink = new(std::nothrow) FDILink(pipeIndex);
101 }
102 if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
103 // DDI also has transcoders
104 fHasTranscoder = true;
105 // Program gen5(+) style panelfitter as well (DDI has this as well..)
106 fPanelFitter = new(std::nothrow) PanelFitter(pipeIndex);
107 }
108
109 TRACE("Pipe Base: 0x%" B_PRIxADDR " Plane Base: 0x%" B_PRIxADDR "\n",
110 fPipeOffset, fPlaneOffset);
111 }
112
113
~Pipe()114 Pipe::~Pipe()
115 {
116 }
117
118
119 bool
IsEnabled()120 Pipe::IsEnabled()
121 {
122 CALLED();
123
124 return (read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset)
125 & INTEL_PIPE_ENABLED) != 0;
126 }
127
128
129 void
Configure(display_mode * mode)130 Pipe::Configure(display_mode* mode)
131 {
132 uint32 pipeControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset);
133
134 // TODO: Haswell+ dithering changes.
135 //if (gInfo->shared_info->device_type.Generation() >= 4) {
136 // pipeControl |= (INTEL_PIPE_DITHER_EN | INTEL_PIPE_DITHER_TYPE_SP);
137
138 //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8)
139 //currently using BIOS preconfigured setup
140 //pipeControl = (pipeControl & ~INTEL_PIPE_BPC_MASK) | INTEL_PIPE_BPC(INTEL_PIPE_8BPC);
141
142 // TODO: CxSR downclocking?
143
144 // TODO: Interlaced modes
145 pipeControl = (pipeControl & ~(0x7 << 21)) | INTEL_PIPE_PROGRESSIVE;
146
147 write32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset, pipeControl);
148 read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset);
149
150 if (gInfo->shared_info->device_type.Generation() >= 6) {
151 // According to SandyBridge modesetting sequence, pipe must be enabled
152 // before PLL are configured.
153 addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset;
154 write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED);
155 }
156 }
157
158
159 void
_ConfigureTranscoder(display_mode * target)160 Pipe::_ConfigureTranscoder(display_mode* target)
161 {
162 CALLED();
163
164 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR"\n", __func__, fPipeOffset);
165
166 if (gInfo->shared_info->device_type.Generation() < 9) {
167 // update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
168 write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset,
169 ((uint32)(target->timing.h_total - 1) << 16)
170 | ((uint32)target->timing.h_display - 1));
171 write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset,
172 ((uint32)(target->timing.h_total - 1) << 16)
173 | ((uint32)target->timing.h_display - 1));
174 write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset,
175 ((uint32)(target->timing.h_sync_end - 1) << 16)
176 | ((uint32)target->timing.h_sync_start - 1));
177
178 write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset,
179 ((uint32)(target->timing.v_total - 1) << 16)
180 | ((uint32)target->timing.v_display - 1));
181 write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset,
182 ((uint32)(target->timing.v_total - 1) << 16)
183 | ((uint32)target->timing.v_display - 1));
184 write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset,
185 ((uint32)(target->timing.v_sync_end - 1) << 16)
186 | ((uint32)target->timing.v_sync_start - 1));
187
188 #if 0
189 // XXX: Is it ok to do these on non-digital?
190 write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0);
191 write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset,
192 ((uint32)(target->timing.h_display - 1) << 16)
193 | ((uint32)target->timing.v_display - 1));
194 #endif
195 } else {
196 // on Skylake and later, timing is already done in ConfigureTimings()
197 }
198 }
199
200
201 uint32
TranscoderMode()202 Pipe::TranscoderMode()
203 {
204 if (gInfo->shared_info->device_type.Generation() < 9) {
205 ERROR("%s: Don't know how to get transcoder mode on older generations\n", __func__);
206 return 0;
207 }
208
209 TRACE("%s: trans conf reg: 0x%" B_PRIx32 "\n", __func__,
210 read32(DDI_SKL_TRANS_CONF_A + fPipeOffset));
211 TRACE("%s: trans DDI func ctl reg: 0x%" B_PRIx32 "\n", __func__,
212 read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset));
213 uint32 value = (read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset) & PIPE_DDI_MODESEL_MASK)
214 >> PIPE_DDI_MODESEL_SHIFT;
215 switch (value) {
216 case PIPE_DDI_MODE_DVI:
217 TRACE("%s: Transcoder uses DVI mode\n", __func__);
218 break;
219 case PIPE_DDI_MODE_DP_SST:
220 TRACE("%s: Transcoder uses DP SST mode\n", __func__);
221 break;
222 case PIPE_DDI_MODE_DP_MST:
223 TRACE("%s: Transcoder uses DP MST mode\n", __func__);
224 break;
225 default:
226 TRACE("%s: Transcoder uses HDMI mode\n", __func__);
227 break;
228 }
229 return value;
230 }
231
232
233 status_t
SetFDILink(const display_timing & timing,uint32 linkBandwidth,uint32 lanes,uint32 bitsPerPixel)234 Pipe::SetFDILink(const display_timing& timing, uint32 linkBandwidth, uint32 lanes, uint32 bitsPerPixel)
235 {
236 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset);
237 TRACE("%s: FDI/PIPE link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f);
238 TRACE("%s: FDI/PIPE M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset));
239 TRACE("%s: FDI/PIPE N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset));
240 TRACE("%s: FDI/PIPE M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset));
241 TRACE("%s: FDI/PIPE N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset));
242
243 if ((bitsPerPixel < 18) || (bitsPerPixel > 36)) {
244 ERROR("%s: FDI/PIPE illegal colordepth set.\n", __func__);
245 return B_ERROR;
246 }
247 TRACE("%s: FDI/PIPE link colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel);
248
249 if (lanes > 4) {
250 ERROR("%s: FDI/PIPE illegal number of lanes set.\n", __func__);
251 return B_ERROR;
252 }
253 TRACE("%s: FDI/PIPE link with %" B_PRIx32 " lane(s) in use\n", __func__, lanes);
254
255 //Setup Data M/N
256 uint64 linkspeed = lanes * linkBandwidth * 8;
257 uint64 ret_n = 1;
258 while(ret_n < linkspeed) {
259 ret_n *= 2;
260 }
261 if (ret_n > 0x800000) {
262 ret_n = 0x800000;
263 }
264 uint64 ret_m = timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
265 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
266 ret_m >>= 1;
267 ret_n >>= 1;
268 }
269 //Set TU size bits (to default, max) before link training so that error detection works
270 write32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK);
271 write32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset, ret_n);
272
273 //Setup Link M/N
274 linkspeed = linkBandwidth;
275 ret_n = 1;
276 while(ret_n < linkspeed) {
277 ret_n *= 2;
278 }
279 if (ret_n > 0x800000) {
280 ret_n = 0x800000;
281 }
282 ret_m = timing.pixel_clock * ret_n / linkspeed;
283 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
284 ret_m >>= 1;
285 ret_n >>= 1;
286 }
287 write32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset, ret_m);
288 //Writing Link N triggers all four registers to be activated also (on next VBlank)
289 write32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset, ret_n);
290
291 TRACE("%s: FDI/PIPE M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset));
292 TRACE("%s: FDI/PIPE N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset));
293 TRACE("%s: FDI/PIPE M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset));
294 TRACE("%s: FDI/PIPE N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset));
295
296 return B_OK;
297 }
298
299
300 void
ConfigureScalePos(display_mode * target)301 Pipe::ConfigureScalePos(display_mode* target)
302 {
303 CALLED();
304
305 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset);
306
307 if (target == NULL) {
308 ERROR("%s: Invalid display mode!\n", __func__);
309 return;
310 }
311
312 if (gInfo->shared_info->device_type.Generation() < 6) {
313 // FIXME check on which generations this register exists
314 // (it appears it would be available only for cursor planes, not
315 // display planes)
316 // Since we set the plane to be the same size as the display, we can
317 // just show it starting at top-left.
318 write32(INTEL_DISPLAY_A_POS + fPipeOffset, 0);
319 }
320
321 // The only thing that really matters: set the image size and let the
322 // panel fitter or the transcoder worry about the rest
323 write32(INTEL_DISPLAY_A_PIPE_SIZE + fPipeOffset,
324 ((uint32)(target->timing.h_display - 1) << 16)
325 | ((uint32)target->timing.v_display - 1));
326
327 // Set the plane size as well while we're at it (this is independant, we
328 // could have a larger plane and scroll through it).
329 if ((gInfo->shared_info->device_type.Generation() <= 4)
330 || gInfo->shared_info->device_type.HasDDI()) {
331 // This is "reserved" on G35 and GMA965, but needed on 945 (for which
332 // there is no public documentation), and I assume earlier devices as
333 // well.
334 //
335 // IMPORTANT WARNING: height and width are swapped when compared to the other registers!
336 // Be careful when editing this code and don't accidentally swap them!
337 write32(INTEL_DISPLAY_A_IMAGE_SIZE + fPipeOffset,
338 ((uint32)(target->timing.v_display - 1) << 16)
339 | ((uint32)target->timing.h_display - 1));
340 }
341 }
342
343
344 void
ConfigureTimings(display_mode * target,bool hardware,port_index portIndex)345 Pipe::ConfigureTimings(display_mode* target, bool hardware, port_index portIndex)
346 {
347 CALLED();
348
349 TRACE("%s(%d): fPipeOffset: 0x%" B_PRIxADDR"\n", __func__, hardware,
350 fPipeOffset);
351
352 if (target == NULL) {
353 ERROR("%s: Invalid display mode!\n", __func__);
354 return;
355 }
356
357 /* If using the transcoder, leave the display at its native resolution,
358 * and configure only the transcoder (panel fitting will match them
359 * together). */
360 if (!fHasTranscoder || hardware)
361 {
362 // update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
363 // Note: on Skylake below registers are part of the transcoder
364 write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset,
365 ((uint32)(target->timing.h_total - 1) << 16)
366 | ((uint32)target->timing.h_display - 1));
367 write32(INTEL_DISPLAY_A_HBLANK + fPipeOffset,
368 ((uint32)(target->timing.h_total - 1) << 16)
369 | ((uint32)target->timing.h_display - 1));
370 write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset,
371 ((uint32)(target->timing.h_sync_end - 1) << 16)
372 | ((uint32)target->timing.h_sync_start - 1));
373
374 write32(INTEL_DISPLAY_A_VTOTAL + fPipeOffset,
375 ((uint32)(target->timing.v_total - 1) << 16)
376 | ((uint32)target->timing.v_display - 1));
377 write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset,
378 ((uint32)(target->timing.v_total - 1) << 16)
379 | ((uint32)target->timing.v_display - 1));
380 write32(INTEL_DISPLAY_A_VSYNC + fPipeOffset,
381 ((uint32)(target->timing.v_sync_end - 1) << 16)
382 | ((uint32)target->timing.v_sync_start - 1));
383 }
384
385 ConfigureScalePos(target);
386
387 // transcoder is not applicable if eDP is targeted on Sandy- and IvyBridge
388 if ((gInfo->shared_info->device_type.InGroup(INTEL_GROUP_SNB) ||
389 gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) &&
390 (portIndex == INTEL_PORT_A)) {
391 return;
392 }
393
394 if (fHasTranscoder && hardware) {
395 _ConfigureTranscoder(target);
396 }
397 }
398
399
400 void
ConfigureClocks(const pll_divisors & divisors,uint32 pixelClock,uint32 extraFlags)401 Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,
402 uint32 extraFlags)
403 {
404 CALLED();
405
406 addr_t pllDivisorA = INTEL_DISPLAY_A_PLL_DIVISOR_0;
407 addr_t pllDivisorB = INTEL_DISPLAY_A_PLL_DIVISOR_1;
408 addr_t pllControl = INTEL_DISPLAY_A_PLL;
409 addr_t pllMD = INTEL_DISPLAY_A_PLL_MD;
410
411 if (fPipeIndex == INTEL_PIPE_B) {
412 pllDivisorA = INTEL_DISPLAY_B_PLL_DIVISOR_0;
413 pllDivisorB = INTEL_DISPLAY_B_PLL_DIVISOR_1;
414 pllControl = INTEL_DISPLAY_B_PLL;
415 pllMD = INTEL_DISPLAY_B_PLL_MD;
416 }
417
418 // Disable DPLL first
419 write32(pllControl, read32(pllControl) & ~DISPLAY_PLL_ENABLED);
420 spin(150);
421
422 float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
423
424 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
425 float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.p;
426 uint32 pixelMultiply = uint32(adjusted / (pixelClock / 1000.0f));
427 write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8));
428 }
429
430 // XXX: For now we assume no LVDS downclocking and program the same divisor
431 // value to both divisor 0 (standard) and 1 (reduced divisor)
432 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
433 write32(pllDivisorA, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
434 & DISPLAY_PLL_IGD_N_DIVISOR_MASK)
435 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
436 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
437 write32(pllDivisorB, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
438 & DISPLAY_PLL_IGD_N_DIVISOR_MASK)
439 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
440 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
441 } else {
442 write32(pllDivisorA, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
443 & DISPLAY_PLL_N_DIVISOR_MASK)
444 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
445 & DISPLAY_PLL_M1_DIVISOR_MASK)
446 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
447 & DISPLAY_PLL_M2_DIVISOR_MASK));
448 write32(pllDivisorB, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
449 & DISPLAY_PLL_N_DIVISOR_MASK)
450 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
451 & DISPLAY_PLL_M1_DIVISOR_MASK)
452 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
453 & DISPLAY_PLL_M2_DIVISOR_MASK));
454 }
455
456 //note: bit DISPLAY_PLL_NO_VGA_CONTROL does not exist on IvyBridge and should be left
457 // zero there. It does not influence it though.
458 uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags;
459
460 if (gInfo->shared_info->device_type.Generation() >= 3) {
461 // p1 divisor << 1 , 1-8
462 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
463 pll |= ((1 << (divisors.p1 - 1))
464 << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
465 & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
466 } else {
467 pll |= ((1 << (divisors.p1 - 1))
468 << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
469 & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
470 // pll |= ((divisors.p1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
471 // & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
472 }
473
474 // Also configure the FP0 divisor on SandyBridge
475 if (gInfo->shared_info->device_type.Generation() == 6) {
476 pll |= ((1 << (divisors.p1 - 1))
477 << DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_SHIFT)
478 & DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_MASK;
479 }
480
481 if (divisors.p2 == 5 || divisors.p2 == 7)
482 pll |= DISPLAY_PLL_DIVIDE_HIGH;
483
484 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
485 pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
486 } else {
487 if (divisors.p2 != 5 && divisors.p2 != 7)
488 pll |= DISPLAY_PLL_DIVIDE_4X;
489
490 pll |= DISPLAY_PLL_2X_CLOCK;
491
492 // TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK??
493 if (divisors.p1 > 2) {
494 pll |= ((divisors.p1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
495 & DISPLAY_PLL_POST1_DIVISOR_MASK;
496 } else
497 pll |= DISPLAY_PLL_POST1_DIVIDE_2;
498 }
499
500 // Configure PLL while -keeping- it disabled
501 //note: on older chipsets DISPLAY_PLL_NO_VGA_CONTROL probably enables the PLL and locks regs;
502 // on newer chipsets DISPLAY_PLL_ENABLED does this.
503 write32(pllControl, pll & ~DISPLAY_PLL_ENABLED & ~DISPLAY_PLL_NO_VGA_CONTROL);
504 read32(pllControl);
505 spin(150);
506
507 // enable pre-configured PLL (locks PLL settings directly blocking changes in this write even)
508 write32(pllControl, pll);
509 read32(pllControl);
510
511 // Allow the PLL to warm up.
512 spin(150);
513
514 if (gInfo->shared_info->device_type.Generation() >= 6) {
515 // SandyBridge has 3 transcoders, but only 2 PLLs. So there is a new
516 // register which routes the PLL output to the transcoder that we need
517 // to configure
518 uint32 pllSel = read32(SNB_DPLL_SEL);
519 TRACE("Old PLL selection: 0x%" B_PRIx32 "\n", pllSel);
520 uint32 shift = 0;
521 uint32 pllIndex = 0;
522
523 // FIXME we assume that pipe A is used with transcoder A, and pipe B
524 // with transcoder B, that may not always be the case
525 if (fPipeIndex == INTEL_PIPE_A) {
526 shift = 0;
527 pllIndex = 0;
528 TRACE("Route PLL A to transcoder A\n");
529 } else if (fPipeIndex == INTEL_PIPE_B) {
530 shift = 4;
531 pllIndex = 1;
532 TRACE("Route PLL B to transcoder B\n");
533 } else {
534 ERROR("Attempting to configure PLL for unhandled pipe");
535 return;
536 }
537
538 // Mask out the previous PLL configuration for this transcoder
539 pllSel &= ~(0xF << shift);
540
541 // Set up the new configuration for this transcoder and enable it
542 pllSel |= (8 | pllIndex) << shift;
543
544 TRACE("New PLL selection: 0x%" B_PRIx32 "\n", pllSel);
545 write32(SNB_DPLL_SEL, pllSel);
546 }
547 }
548
549 void
ConfigureClocksSKL(const skl_wrpll_params & wrpll_params,uint32 pixelClock,port_index pllForPort,uint32 * pllSel)550 Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock,
551 port_index pllForPort, uint32* pllSel)
552 {
553 CALLED();
554
555 //find our PLL as set by the BIOS
556 uint32 portSel = read32(SKL_DPLL_CTRL2);
557 *pllSel = 0xff;
558 switch (pllForPort) {
559 case INTEL_PORT_A:
560 *pllSel = (portSel & 0x0006) >> 1;
561 break;
562 case INTEL_PORT_B:
563 *pllSel = (portSel & 0x0030) >> 4;
564 break;
565 case INTEL_PORT_C:
566 *pllSel = (portSel & 0x0180) >> 7;
567 break;
568 case INTEL_PORT_D:
569 *pllSel = (portSel & 0x0c00) >> 10;
570 break;
571 case INTEL_PORT_E:
572 *pllSel = (portSel & 0x6000) >> 13;
573 break;
574 default:
575 TRACE("No port selected!\n");
576 return;
577 }
578 TRACE("PLL selected is %" B_PRIx32 "\n", *pllSel);
579
580 TRACE("Skylake DPLL_CFGCR1 0x%" B_PRIx32 "\n",
581 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8));
582 TRACE("Skylake DPLL_CFGCR2 0x%" B_PRIx32 "\n",
583 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8));
584
585 // only program PLL's that are in non-DP mode (otherwise the linkspeed sets refresh)
586 portSel = read32(SKL_DPLL_CTRL1);
587 if ((portSel & (1 << (*pllSel * 6 + 5))) && *pllSel) { // DPLL0 might only know DP mode
588 // enable pgm on our PLL in case that's currently disabled
589 write32(SKL_DPLL_CTRL1, portSel | (1 << (*pllSel * 6)));
590
591 write32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8,
592 1 << 31 |
593 wrpll_params.dco_fraction << 9 |
594 wrpll_params.dco_integer);
595 write32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8,
596 wrpll_params.qdiv_ratio << 8 |
597 wrpll_params.qdiv_mode << 7 |
598 wrpll_params.kdiv << 5 |
599 wrpll_params.pdiv << 2 |
600 wrpll_params.central_freq);
601 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8);
602 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8);
603
604 //assuming DPLL0 and 1 are already enabled by the BIOS if in use (LCPLL1,2 regs)
605
606 spin(5);
607 if (read32(SKL_DPLL_STATUS) & (1 << (*pllSel * 8))) {
608 TRACE("Programmed PLL; PLL is locked\n");
609 } else {
610 TRACE("Programmed PLL; PLL did not lock\n");
611 }
612 TRACE("Skylake DPLL_CFGCR1 now: 0x%" B_PRIx32 "\n",
613 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8));
614 TRACE("Skylake DPLL_CFGCR2 now: 0x%" B_PRIx32 "\n",
615 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8));
616 } else {
617 TRACE("PLL programming not needed, skipping.\n");
618 }
619
620 TRACE("Skylake DPLL_CTRL1: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL1));
621 TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2));
622 TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS));
623 }
624
625 void
Enable(bool enable)626 Pipe::Enable(bool enable)
627 {
628 CALLED();
629
630 addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset;
631 addr_t planeReg = INTEL_DISPLAY_A_CONTROL + fPlaneOffset;
632
633 // Planes always have to operate on an enabled pipe
634
635 if (enable) {
636 write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED);
637 wait_for_vblank();
638 write32(planeReg, read32(planeReg) | DISPLAY_CONTROL_ENABLED);
639
640 //Enable default display main watermarks
641 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
642 if (fPipeOffset == 0)
643 write32(INTEL_DISPLAY_A_PIPE_WATERMARK, 0x0783818);
644 else
645 write32(INTEL_DISPLAY_B_PIPE_WATERMARK, 0x0783818);
646 }
647 } else {
648 write32(planeReg, read32(planeReg) & ~DISPLAY_CONTROL_ENABLED);
649 wait_for_vblank();
650 //Sandy+: when link training is to be done re-enable this line but otherwise don't touch!
651 //GMA(Q45): must disable PIPE or DPLL programming fails.
652 if (gInfo->shared_info->device_type.Generation() <= 5) {
653 write32(pipeReg, read32(pipeReg) & ~INTEL_PIPE_ENABLED);
654 }
655 }
656
657 // flush the eventually cached PCI bus writes
658 read32(INTEL_DISPLAY_A_BASE);
659 }
660