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
37void
38program_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
62Pipe::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
114Pipe::~Pipe()
115{
116}
117
118
119bool
120Pipe::IsEnabled()
121{
122	CALLED();
123
124	return (read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset)
125		& INTEL_PIPE_ENABLED) != 0;
126}
127
128
129void
130Pipe::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
159void
160Pipe::_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 timing is already done in ConfigureTimings()
197
198		TRACE("%s: trans conf reg: 0x%" B_PRIx32"\n", __func__,
199			read32(DDI_SKL_TRANS_CONF_A + fPipeOffset));
200		TRACE("%s: trans DDI func ctl reg: 0x%" B_PRIx32"\n", __func__,
201			read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset));
202		switch ((read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset) & PIPE_DDI_MODESEL_MASK)
203				>> PIPE_DDI_MODESEL_SHIFT) {
204			case PIPE_DDI_MODE_DVI:
205				TRACE("%s: Transcoder uses DVI mode\n", __func__);
206				break;
207			case PIPE_DDI_MODE_DP_SST:
208				TRACE("%s: Transcoder uses DP SST mode\n", __func__);
209				break;
210			case PIPE_DDI_MODE_DP_MST:
211				TRACE("%s: Transcoder uses DP MST mode\n", __func__);
212				break;
213			default:
214				TRACE("%s: Transcoder uses HDMI mode\n", __func__);
215				break;
216		}
217	}
218}
219
220
221status_t
222Pipe::SetFDILink(const display_timing& timing, uint32 linkBandwidth, uint32 lanes, uint32 bitsPerPixel)
223{
224	TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset);
225	TRACE("%s: FDI/PIPE link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f);
226	TRACE("%s: FDI/PIPE M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset));
227	TRACE("%s: FDI/PIPE N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset));
228	TRACE("%s: FDI/PIPE M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset));
229	TRACE("%s: FDI/PIPE N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset));
230
231	if ((bitsPerPixel < 18) || (bitsPerPixel > 36)) {
232		ERROR("%s: FDI/PIPE illegal colordepth set.\n", __func__);
233		return B_ERROR;
234	}
235	TRACE("%s: FDI/PIPE link colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel);
236
237	if (lanes > 4) {
238		ERROR("%s: FDI/PIPE illegal number of lanes set.\n", __func__);
239		return B_ERROR;
240	}
241	TRACE("%s: FDI/PIPE link with %" B_PRIx32 " lane(s) in use\n", __func__, lanes);
242
243	//Setup Data M/N
244	uint64 linkspeed = lanes * linkBandwidth * 8;
245	uint64 ret_n = 1;
246	while(ret_n < linkspeed) {
247		ret_n *= 2;
248	}
249	if (ret_n > 0x800000) {
250		ret_n = 0x800000;
251	}
252	uint64 ret_m = timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
253	while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
254		ret_m >>= 1;
255		ret_n >>= 1;
256	}
257	//Set TU size bits (to default, max) before link training so that error detection works
258	write32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK);
259	write32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset, ret_n);
260
261	//Setup Link M/N
262	linkspeed = linkBandwidth;
263	ret_n = 1;
264	while(ret_n < linkspeed) {
265		ret_n *= 2;
266	}
267	if (ret_n > 0x800000) {
268		ret_n = 0x800000;
269	}
270	ret_m = timing.pixel_clock * ret_n / linkspeed;
271	while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
272		ret_m >>= 1;
273		ret_n >>= 1;
274	}
275	write32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset, ret_m);
276	//Writing Link N triggers all four registers to be activated also (on next VBlank)
277	write32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset, ret_n);
278
279	TRACE("%s: FDI/PIPE M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset));
280	TRACE("%s: FDI/PIPE N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset));
281	TRACE("%s: FDI/PIPE M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset));
282	TRACE("%s: FDI/PIPE N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset));
283
284	return B_OK;
285}
286
287
288void
289Pipe::ConfigureScalePos(display_mode* target)
290{
291	CALLED();
292
293	TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset);
294
295	if (target == NULL) {
296		ERROR("%s: Invalid display mode!\n", __func__);
297		return;
298	}
299
300	if (gInfo->shared_info->device_type.Generation() < 6) {
301		// FIXME check on which generations this register exists
302		// (it appears it would be available only for cursor planes, not
303		// display planes)
304		// Since we set the plane to be the same size as the display, we can
305		// just show it starting at top-left.
306		write32(INTEL_DISPLAY_A_POS + fPipeOffset, 0);
307	}
308
309	// The only thing that really matters: set the image size and let the
310	// panel fitter or the transcoder worry about the rest
311	write32(INTEL_DISPLAY_A_PIPE_SIZE + fPipeOffset,
312		((uint32)(target->timing.h_display - 1) << 16)
313			| ((uint32)target->timing.v_display - 1));
314
315	// Set the plane size as well while we're at it (this is independant, we
316	// could have a larger plane and scroll through it).
317	if ((gInfo->shared_info->device_type.Generation() <= 4)
318		|| gInfo->shared_info->device_type.HasDDI()) {
319		// This is "reserved" on G35 and GMA965, but needed on 945 (for which
320		// there is no public documentation), and I assume earlier devices as
321		// well.
322		//
323		// IMPORTANT WARNING: height and width are swapped when compared to the other registers!
324		// Be careful when editing this code and don't accidentally swap them!
325		write32(INTEL_DISPLAY_A_IMAGE_SIZE + fPipeOffset,
326			((uint32)(target->timing.v_display - 1) << 16)
327			| ((uint32)target->timing.h_display - 1));
328	}
329}
330
331
332void
333Pipe::ConfigureTimings(display_mode* target, bool hardware, port_index portIndex)
334{
335	CALLED();
336
337	TRACE("%s(%d): fPipeOffset: 0x%" B_PRIxADDR"\n", __func__, hardware,
338		fPipeOffset);
339
340	if (target == NULL) {
341		ERROR("%s: Invalid display mode!\n", __func__);
342		return;
343	}
344
345	/* If using the transcoder, leave the display at its native resolution,
346	 * and configure only the transcoder (panel fitting will match them
347	 * together). */
348	if (!fHasTranscoder || hardware)
349	{
350		// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
351		// Note: on Skylake below registers are part of the transcoder
352		write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset,
353			((uint32)(target->timing.h_total - 1) << 16)
354			| ((uint32)target->timing.h_display - 1));
355		write32(INTEL_DISPLAY_A_HBLANK + fPipeOffset,
356			((uint32)(target->timing.h_total - 1) << 16)
357			| ((uint32)target->timing.h_display - 1));
358		write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset,
359			((uint32)(target->timing.h_sync_end - 1) << 16)
360			| ((uint32)target->timing.h_sync_start - 1));
361
362		write32(INTEL_DISPLAY_A_VTOTAL + fPipeOffset,
363			((uint32)(target->timing.v_total - 1) << 16)
364			| ((uint32)target->timing.v_display - 1));
365		write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset,
366			((uint32)(target->timing.v_total - 1) << 16)
367			| ((uint32)target->timing.v_display - 1));
368		write32(INTEL_DISPLAY_A_VSYNC + fPipeOffset,
369			((uint32)(target->timing.v_sync_end - 1) << 16)
370			| ((uint32)target->timing.v_sync_start - 1));
371	}
372
373	ConfigureScalePos(target);
374
375	// transcoder is not applicable if eDP is targeted on Sandy- and IvyBridge
376	if ((gInfo->shared_info->device_type.InGroup(INTEL_GROUP_SNB) ||
377		 gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) &&
378		(portIndex == INTEL_PORT_A)) {
379		return;
380	}
381
382	if (fHasTranscoder && hardware) {
383		_ConfigureTranscoder(target);
384	}
385}
386
387
388void
389Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,
390	uint32 extraFlags)
391{
392	CALLED();
393
394	addr_t pllDivisorA = INTEL_DISPLAY_A_PLL_DIVISOR_0;
395	addr_t pllDivisorB = INTEL_DISPLAY_A_PLL_DIVISOR_1;
396	addr_t pllControl = INTEL_DISPLAY_A_PLL;
397	addr_t pllMD = INTEL_DISPLAY_A_PLL_MD;
398
399	if (fPipeIndex == INTEL_PIPE_B) {
400		pllDivisorA = INTEL_DISPLAY_B_PLL_DIVISOR_0;
401		pllDivisorB = INTEL_DISPLAY_B_PLL_DIVISOR_1;
402		pllControl = INTEL_DISPLAY_B_PLL;
403		pllMD = INTEL_DISPLAY_B_PLL_MD;
404	}
405
406	// Disable DPLL first
407	write32(pllControl, read32(pllControl) & ~DISPLAY_PLL_ENABLED);
408	spin(150);
409
410	float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
411
412	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
413		float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.p;
414		uint32 pixelMultiply = uint32(adjusted / (pixelClock / 1000.0f));
415		write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8));
416	}
417
418	// XXX: For now we assume no LVDS downclocking and program the same divisor
419	// value to both divisor 0 (standard) and 1 (reduced divisor)
420	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
421		write32(pllDivisorA, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
422				& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
423			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
424				& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
425		write32(pllDivisorB, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
426				& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
427			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
428				& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
429	} else {
430		write32(pllDivisorA, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
431				& DISPLAY_PLL_N_DIVISOR_MASK)
432			| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
433				& DISPLAY_PLL_M1_DIVISOR_MASK)
434			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
435				& DISPLAY_PLL_M2_DIVISOR_MASK));
436		write32(pllDivisorB, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
437				& DISPLAY_PLL_N_DIVISOR_MASK)
438			| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
439				& DISPLAY_PLL_M1_DIVISOR_MASK)
440			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
441				& DISPLAY_PLL_M2_DIVISOR_MASK));
442	}
443
444	//note: bit DISPLAY_PLL_NO_VGA_CONTROL does not exist on IvyBridge and should be left
445	//      zero there. It does not influence it though.
446	uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags;
447
448	if (gInfo->shared_info->device_type.Generation() >= 3) {
449		// p1 divisor << 1 , 1-8
450		if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
451			pll |= ((1 << (divisors.p1 - 1))
452					<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
453				& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
454		} else {
455			pll |= ((1 << (divisors.p1 - 1))
456					<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
457				& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
458		//	pll |= ((divisors.p1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
459		//		& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
460		}
461
462		// Also configure the FP0 divisor on SandyBridge
463		if (gInfo->shared_info->device_type.Generation() == 6) {
464			pll |= ((1 << (divisors.p1 - 1))
465					<< DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_SHIFT)
466				& DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_MASK;
467		}
468
469		if (divisors.p2 == 5 || divisors.p2 == 7)
470			pll |= DISPLAY_PLL_DIVIDE_HIGH;
471
472		if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
473			pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
474	} else {
475		if (divisors.p2 != 5 && divisors.p2 != 7)
476			pll |= DISPLAY_PLL_DIVIDE_4X;
477
478		pll |= DISPLAY_PLL_2X_CLOCK;
479
480		// TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK??
481		if (divisors.p1 > 2) {
482			pll |= ((divisors.p1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
483				& DISPLAY_PLL_POST1_DIVISOR_MASK;
484		} else
485			pll |= DISPLAY_PLL_POST1_DIVIDE_2;
486	}
487
488	// Configure PLL while -keeping- it disabled
489	//note: on older chipsets DISPLAY_PLL_NO_VGA_CONTROL probably enables the PLL and locks regs;
490	//      on newer chipsets DISPLAY_PLL_ENABLED does this.
491	write32(pllControl, pll & ~DISPLAY_PLL_ENABLED & ~DISPLAY_PLL_NO_VGA_CONTROL);
492	read32(pllControl);
493	spin(150);
494
495	// enable pre-configured PLL (locks PLL settings directly blocking changes in this write even)
496	write32(pllControl, pll);
497	read32(pllControl);
498
499	// Allow the PLL to warm up.
500	spin(150);
501
502	if (gInfo->shared_info->device_type.Generation() >= 6) {
503		// SandyBridge has 3 transcoders, but only 2 PLLs. So there is a new
504		// register which routes the PLL output to the transcoder that we need
505		// to configure
506		uint32 pllSel = read32(SNB_DPLL_SEL);
507		TRACE("Old PLL selection: 0x%" B_PRIx32 "\n", pllSel);
508		uint32 shift = 0;
509		uint32 pllIndex = 0;
510
511		// FIXME we assume that pipe A is used with transcoder A, and pipe B
512		// with transcoder B, that may not always be the case
513		if (fPipeIndex == INTEL_PIPE_A) {
514			shift = 0;
515			pllIndex = 0;
516			TRACE("Route PLL A to transcoder A\n");
517		} else if (fPipeIndex == INTEL_PIPE_B) {
518			shift = 4;
519			pllIndex = 1;
520			TRACE("Route PLL B to transcoder B\n");
521		} else {
522			ERROR("Attempting to configure PLL for unhandled pipe");
523			return;
524		}
525
526		// Mask out the previous PLL configuration for this transcoder
527		pllSel &= ~(0xF << shift);
528
529		// Set up the new configuration for this transcoder and enable it
530		pllSel |= (8 | pllIndex) << shift;
531
532		TRACE("New PLL selection: 0x%" B_PRIx32 "\n", pllSel);
533		write32(SNB_DPLL_SEL, pllSel);
534	}
535}
536
537void
538Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock,
539	port_index pllForPort, uint32* pllSel)
540{
541	CALLED();
542
543	//find our PLL as set by the BIOS
544	uint32 portSel = read32(SKL_DPLL_CTRL2);
545	*pllSel = 0xff;
546	switch (pllForPort) {
547	case INTEL_PORT_A:
548		*pllSel = (portSel & 0x0006) >> 1;
549		break;
550	case INTEL_PORT_B:
551		*pllSel = (portSel & 0x0030) >> 4;
552		break;
553	case INTEL_PORT_C:
554		*pllSel = (portSel & 0x0180) >> 7;
555		break;
556	case INTEL_PORT_D:
557		*pllSel = (portSel & 0x0c00) >> 10;
558		break;
559	case INTEL_PORT_E:
560		*pllSel = (portSel & 0x6000) >> 13;
561		break;
562	default:
563		TRACE("No port selected!\n");
564		return;
565	}
566	TRACE("PLL selected is %" B_PRIx32 "\n", *pllSel);
567
568	TRACE("Skylake DPLL_CFGCR1 0x%" B_PRIx32 "\n",
569		read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8));
570	TRACE("Skylake DPLL_CFGCR2 0x%" B_PRIx32 "\n",
571		read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8));
572
573	// only program PLL's that are in non-DP mode (otherwise the linkspeed sets refresh)
574	portSel = read32(SKL_DPLL_CTRL1);
575	if ((portSel & (1 << (*pllSel * 6 + 5))) && *pllSel) { // DPLL0 might only know DP mode
576		// enable pgm on our PLL in case that's currently disabled
577		write32(SKL_DPLL_CTRL1, portSel | (1 << (*pllSel * 6)));
578
579		write32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8,
580			1 << 31 |
581			wrpll_params.dco_fraction << 9 |
582			wrpll_params.dco_integer);
583		write32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8,
584			 wrpll_params.qdiv_ratio << 8 |
585			 wrpll_params.qdiv_mode << 7 |
586			 wrpll_params.kdiv << 5 |
587			 wrpll_params.pdiv << 2 |
588			 wrpll_params.central_freq);
589		read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8);
590		read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8);
591
592		//assuming DPLL0 and 1 are already enabled by the BIOS if in use (LCPLL1,2 regs)
593
594		spin(5);
595		if (read32(SKL_DPLL_STATUS) & (1 << (*pllSel * 8))) {
596			TRACE("Programmed PLL; PLL is locked\n");
597		} else {
598			TRACE("Programmed PLL; PLL did not lock\n");
599		}
600		TRACE("Skylake DPLL_CFGCR1 now: 0x%" B_PRIx32 "\n",
601			read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8));
602		TRACE("Skylake DPLL_CFGCR2 now: 0x%" B_PRIx32 "\n",
603			read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8));
604	} else {
605		TRACE("PLL programming not needed, skipping.\n");
606	}
607
608	TRACE("Skylake DPLL_CTRL1: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL1));
609	TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2));
610	TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS));
611}
612
613void
614Pipe::Enable(bool enable)
615{
616	CALLED();
617
618	addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset;
619	addr_t planeReg = INTEL_DISPLAY_A_CONTROL + fPlaneOffset;
620
621	// Planes always have to operate on an enabled pipe
622
623	if (enable) {
624		write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED);
625		wait_for_vblank();
626		write32(planeReg, read32(planeReg) | DISPLAY_CONTROL_ENABLED);
627
628		//Enable default display main watermarks
629		if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
630			if (fPipeOffset == 0)
631				write32(INTEL_DISPLAY_A_PIPE_WATERMARK, 0x0783818);
632			else
633				write32(INTEL_DISPLAY_B_PIPE_WATERMARK, 0x0783818);
634		}
635	} else {
636		write32(planeReg, read32(planeReg) & ~DISPLAY_CONTROL_ENABLED);
637		wait_for_vblank();
638		//Sandy+: when link training is to be done re-enable this line but otherwise don't touch!
639		//GMA(Q45): must disable PIPE or DPLL programming fails.
640		if (gInfo->shared_info->device_type.Generation() <= 5) {
641			write32(pipeReg, read32(pipeReg) & ~INTEL_PIPE_ENABLED);
642		}
643	}
644
645	// flush the eventually cached PCI bus writes
646	read32(INTEL_DISPLAY_A_BASE);
647}
648