xref: /haiku/src/add-ons/accelerants/intel_extreme/pll.cpp (revision 610f99c838cb661ff85377789ffd3ad4ff672a08) !
1 /*
2  * Copyright 2006-2018, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Alexander von Gluck IV, kallisti5@unixzen.com
8  *		Adrien Destugues, pulkomandy@pulkomandy.tk
9  */
10 
11 
12 #include "pll.h"
13 
14 #include <math.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <Debug.h>
19 
20 #include <create_display_modes.h>
21 #include <ddc.h>
22 #include <edid.h>
23 #include <validate_display_mode.h>
24 
25 #include "accelerant_protos.h"
26 #include "accelerant.h"
27 #include "utility.h"
28 
29 
30 #undef TRACE
31 #define TRACE_MODE
32 #ifdef TRACE_MODE
33 #	define TRACE(x...) _sPrintf("intel_extreme: " x)
34 #else
35 #	define TRACE(x...)
36 #endif
37 
38 #define ERROR(x...) _sPrintf("intel_extreme: " x)
39 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
40 
41 
42 // PLL limits, taken from i915 DRM driver. However, note that we use the values of
43 // N+2, M1+2 and M2+2 here, the - 2 being applied when we write the values to the registers.
44 
45 static pll_limits kLimits85x = {
46 	// p, p1, p2,  n,   m, m1, m2
47 	{  4,  2,  2,  4,  96, 20,  8},
48 	{128, 33,  4, 18, 140, 28, 18},
49 	165000, 908000, 1512000
50 };
51 
52 // For Iron Lake, a new set of timings is introduced along with the FDI system,
53 // and carried on to later cards with just one further change (to the P2 cutoff
54 // frequency) in Sandy Bridge.
55 
56 static pll_limits kLimits9xxSdvo = {
57 	// p, p1, p2,  n,   m, m1, m2
58 	{  5,  1,  5,  3,  70, 10,  5},	// min
59 	{ 80,  8, 10,  8, 120, 20,  9},	// max
60 	200000, 1400000, 2800000
61 };
62 
63 static pll_limits kLimits9xxLvds = {
64 	// p, p1, p2,  n,   m, m1, m2
65 	{  7,  1,  7,  3,  70, 10,  5},	// min
66 	{ 98,  8, 14,  8, 120, 20,  9},	// max
67 	112000, 1400000, 2800000
68 };
69 
70 // Limits for G45 cards taken from i915 DRM driver, mixed with old setup
71 // plus tests to accomodate lower resolutions with still correct refresh.
72 // Note that n here is actually n+2, same applies to m1 and m2.
73 
74 static pll_limits kLimitsG4xSdvo = {
75 	// p, p1, p2,  n,   m, m1, m2
76 	{ 10,  1, 10,  3, 104, 19,  7},	// min
77 	{ 80,  8, 10,  8, 138, 25, 13},	// max
78 	270000, 1750000, 3500000
79 };
80 
81 #if 0
82 static pll_limits kLimitsG4xHdmi = {
83 	// p, p1, p2,  n,   m, m1, m2
84 	{  5,  1,  5,  3, 104, 18,  7},	// min
85 	{ 80,  8, 10,  8, 138, 25, 13},	// max
86 	165000, 1750000, 3500000
87 };
88 #endif
89 
90 static pll_limits kLimitsG4xLvdsSingle = {
91 	// p, p1, p2,  n,   m, m1, m2
92 	{ 28,  2, 14,  3, 104, 19,  7},	// min
93 	{112,  8, 14,  8, 138, 25, 13},	// max
94 	0, 1750000, 3500000
95 };
96 
97 static pll_limits kLimitsG4xLvdsDual = {
98 	// p, p1, p2,  n,   m, m1, m2
99 	{ 14,  2,  7,  3, 104, 19,  7},	// min
100 	{ 42,  6,  7,  8, 138, 25, 13},	// max
101 	0, 1750000, 3500000
102 };
103 
104 static pll_limits kLimitsIlkDac = {
105 	// p, p1, p2, n,   m, m1, m2
106 	{  5,  1,  5, 3,  79, 14,  7}, // min
107 	{ 80,  8, 10, 7, 127, 24, 11}, // max
108 	225000, 1760000, 3510000
109 };
110 
111 static pll_limits kLimitsIlkLvdsSingle = {
112 	// p, p1, p2, n,   m, m1, m2
113 	{ 28,  2, 14, 3,  79, 14,  7}, // min
114 	{112,  8, 14, 5, 118, 24, 11}, // max
115 	225000, 1760000, 3510000
116 };
117 
118 static pll_limits kLimitsIlkLvdsDual = {
119 	// p, p1, p2, n,   m, m1, m2
120 	{ 14,  2,  7, 3,  79, 14,  7}, // min
121 	{ 56,  8,  7, 5, 127, 24, 11}, // max
122 	225000, 1760000, 3510000
123 };
124 
125 // 100Mhz RefClock
126 static pll_limits kLimitsIlkLvdsSingle100 = {
127 	// p, p1, p2, n,   m, m1, m2
128 	{ 28,  2, 14, 3,  79, 14,  7}, // min
129 	{112,  8, 14, 4, 126, 24, 11}, // max
130 	225000, 1760000, 3510000
131 };
132 
133 static pll_limits kLimitsIlkLvdsDual100 = {
134 	// p, p1, p2, n,   m, m1, m2
135 	{ 14,  2,  7, 3,  79, 14,  7}, // min
136 	{ 42,  6,  7, 5, 126, 24, 11}, // max
137 	225000, 1760000, 3510000
138 };
139 
140 // TODO From haswell onwards, a completely different PLL design is used
141 // (intel_gfx-prm-osrc-hsw-display_0.pdf, page 268 for VGA). It uses a "virtual
142 // root frequency" and one just has to set a single divider (integer and
143 // fractional parts), so it makes no sense to reuse the same code and limit
144 // structures there.
145 //
146 // For other display connections, the clock is handled differently, as there is
147 // no need for a precise timing to send things in sync with the display.
148 #if 0
149 static pll_limits kLimitsChv = {
150 	// p, p1, p2, n,   m, m1, m2
151 	{  0,  2,  1, 1,  79, 2,   24 << 22}, // min
152 	{  0,  4, 14, 1, 127, 2,  175 << 22}, // max
153 	0, 4800000, 6480000
154 };
155 
156 static pll_limits kLimitsVlv = {
157 	// p, p1, p2, n,   m, m1, m2
158 	{  0,  2,  2, 1,  79, 2,   11},	// min
159 	{  0,  3, 20, 7, 127, 3,  156},	// max
160 	0, 4000000, 6000000
161 };
162 
163 static pll_limits kLimitsBxt = {
164 	// p, p1, p2, n,  m, m1, m2
165 	{  0,  2,  1, 1,  0,  2,   2 << 22}, // min
166 	{  0,  4, 20, 1,  0,  2, 255 << 22}, // max
167 	0, 4800000, 6700000
168 };
169 #endif
170 
171 static pll_limits kLimitsPinSdvo = {
172 	// p, p1, p2, n,   m, m1,  m2
173 	{  5,  1,  5, 3,   2,  0,   0},	// min
174 	{ 80,  8, 10, 6, 256,  0, 254},	// max
175 	200000, 1700000, 3500000
176 };
177 
178 static pll_limits kLimitsPinLvds = {
179 	// p, p1, p2, n,   m, m1,  m2
180 	{  7,  1, 14, 3,   2,  0,   0},	// min
181 	{112,  8, 14, 6, 256,  0, 254},	// max
182 	112000, 1700000, 3500000
183 };
184 
185 
186 static bool
187 lvds_dual_link(display_mode* current)
188 {
189 	float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
190 	if (requestedPixelClock > 112.999)
191 		return true;
192 
193 	// TODO: Force dual link on MacBookPro6,2  MacBookPro8,2  MacBookPro9,1
194 
195 	return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
196 		== LVDS_CLKB_POWER_UP);
197 }
198 
199 
200 bool
201 valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
202 {
203 	pll_info &info = gInfo->shared_info->pll_info;
204 	uint32 vco = info.reference_frequency * divisors->m / divisors->n;
205 	uint32 frequency = vco / divisors->p;
206 
207 	if (divisors->p < limits->min.p || divisors->p > limits->max.p
208 		|| divisors->m < limits->min.m || divisors->m > limits->max.m
209 		|| vco < limits->min_vco || vco > limits->max_vco
210 		|| frequency < info.min_frequency || frequency > info.max_frequency)
211 		return false;
212 
213 	return true;
214 }
215 
216 
217 static void
218 compute_pll_p2(display_mode* current, pll_divisors* divisors,
219 	pll_limits* limits, bool isLVDS)
220 {
221 	if (isLVDS) {
222 		if (lvds_dual_link(current)) {
223 			// fast DAC timing via 2 channels (dual link LVDS)
224 			divisors->p2 = limits->min.p2;
225 		} else {
226 			// slow DAC timing
227 			divisors->p2 = limits->max.p2;
228 		}
229 	} else {
230 		if (current->timing.pixel_clock < limits->dot_limit) {
231 			// slow DAC timing
232 			divisors->p2 = limits->max.p2;
233 		} else {
234 			// fast DAC timing
235 			divisors->p2 = limits->min.p2;
236 		}
237 	}
238 }
239 
240 
241 // TODO we can simplify this computation, with the way the dividers are set, we
242 // know that all values in the valid range for M are reachable. M1 allows to
243 // generate any multiple of 5 in the range and M2 allows to reach the 4 next
244 // values. Therefore, we don't need to loop over the range of values for M1 and
245 // M2 separately, we could instead just loop over possible values for M.
246 // For this to work, the logic of this function must be reversed: for a given M,
247 // it should give the resulting M1 and M2 values for programming the registers.
248 static uint32
249 compute_pll_m(pll_divisors* divisors)
250 {
251 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)
252 		|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
253 		return divisors->m1 * divisors->m2;
254 	}
255 
256 	// Pineview, m1 is reserved
257 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN))
258 		return divisors->m2;
259 
260 	return 5 * divisors->m1 + divisors->m2;
261 }
262 
263 
264 static uint32
265 compute_pll_p(pll_divisors* divisors)
266 {
267 	return divisors->p1 * divisors->p2;
268 }
269 
270 
271 static void
272 compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
273 {
274 	float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
275 	float referenceClock
276 		= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
277 
278 	TRACE("%s: required MHz: %g, reference clock: %g\n", __func__,
279 		requestedPixelClock, referenceClock);
280 
281 	pll_limits limits;
282 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) {
283 		// TODO: Pass port type via video_configuration
284 		if (isLVDS) {
285 			if (lvds_dual_link(current))
286 				memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits));
287 			else
288 				memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits));
289 		//} else if (type == INTEL_PORT_TYPE_HDMI) {
290 		//	memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits));
291 		} else
292 			memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits));
293 	} else {
294 		// There must be a PCH, so this is ivy bridge or later
295 		if (isLVDS) {
296 			if (lvds_dual_link(current)) {
297 				if (referenceClock == 100.0)
298 					memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits));
299 				else
300 					memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits));
301 			} else {
302 				if (referenceClock == 100.0) {
303 					memcpy(&limits, &kLimitsIlkLvdsSingle100,
304 						sizeof(pll_limits));
305 				} else {
306 					memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits));
307 				}
308 			}
309 		} else {
310 			memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits));
311 		}
312 	}
313 
314 	compute_pll_p2(current, divisors, &limits, isLVDS);
315 
316 	TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
317 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
318 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
319 		limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
320 		limits.min.m1, limits.min.m2);
321 	TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
322 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
323 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
324 		limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
325 		limits.max.m1, limits.max.m2);
326 
327 	float best = requestedPixelClock;
328 	pll_divisors bestDivisors;
329 
330 	for (divisors->n = limits.min.n; divisors->n <= limits.max.n;
331 			divisors->n++) {
332 		for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1;
333 				divisors->m1--) {
334 			for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2;
335 					divisors->m2--) {
336 				for (divisors->p1 = limits.max.p1;
337 						divisors->p1 >= limits.min.p1; divisors->p1--) {
338 					divisors->m = compute_pll_m(divisors);
339 					divisors->p = compute_pll_p(divisors);
340 
341 					if (!valid_pll_divisors(divisors, &limits))
342 						continue;
343 
344 					float error = fabs(requestedPixelClock
345 						- (referenceClock * divisors->m)
346 						/ (divisors->n * divisors->p));
347 					if (error < best) {
348 						best = error;
349 						bestDivisors = *divisors;
350 
351 						if (error == 0)
352 							break;
353 					}
354 				}
355 			}
356 		}
357 	}
358 	*divisors = bestDivisors;
359 	TRACE("%s: best MHz: %g (error: %g)\n", __func__,
360 		(referenceClock * divisors->m) / (divisors->n * divisors->p),
361 		best);
362 }
363 
364 
365 static void
366 compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
367 {
368 	float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
369 	float referenceClock
370 		= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
371 
372 	TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
373 
374 	pll_limits limits;
375 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
376 		if (isLVDS)
377 			memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits));
378 		else
379 			memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits));
380 	} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_85x)) {
381 		memcpy(&limits, &kLimits85x, sizeof(pll_limits));
382 	} else {
383 		if (isLVDS)
384 			memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits));
385 		else
386 			memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits));
387 	}
388 
389 	compute_pll_p2(current, divisors, &limits, isLVDS);
390 
391 	TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
392 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
393 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
394 		limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
395 		limits.min.m1, limits.min.m2);
396 	TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
397 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
398 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
399 		limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
400 		limits.max.m1, limits.max.m2);
401 
402 	bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN);
403 
404 	float best = requestedPixelClock;
405 	pll_divisors bestDivisors;
406 	memset(&bestDivisors, 0, sizeof(bestDivisors));
407 
408 	for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1;
409 			divisors->m1++) {
410 		for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2
411 				&& ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) {
412 			for (divisors->n = limits.min.n; divisors->n <= limits.max.n;
413 					divisors->n++) {
414 				for (divisors->p1 = limits.min.p1;
415 						divisors->p1 <= limits.max.p1; divisors->p1++) {
416 					divisors->m = compute_pll_m(divisors);
417 					divisors->p = compute_pll_p(divisors);
418 
419 					if (!valid_pll_divisors(divisors, &limits))
420 						continue;
421 
422 					float error = fabs(requestedPixelClock
423 						- (referenceClock * divisors->m)
424 						/ (divisors->n * divisors->p));
425 					if (error < best) {
426 						best = error;
427 						bestDivisors = *divisors;
428 
429 						if (error == 0)
430 							break;
431 					}
432 				}
433 			}
434 		}
435 	}
436 
437 	*divisors = bestDivisors;
438 
439 	if (best == requestedPixelClock)
440 		debugger("No valid PLL configuration found");
441 	else {
442 		TRACE("%s: best MHz: %g (error: %g)\n", __func__,
443 			(referenceClock * divisors->m) / (divisors->n * divisors->p),
444 			best);
445 	}
446 }
447 
448 
449 void
450 compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS)
451 {
452 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
453 		|| (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) {
454 		compute_dpll_g4x(current, divisors, isLVDS);
455 	} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
456 		ERROR("%s: TODO: CherryView\n", __func__);
457 	} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
458 		ERROR("%s: TODO: VallyView\n", __func__);
459 	} else
460 		compute_dpll_9xx(current, divisors, isLVDS);
461 
462 	TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
463 		"p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " "
464 		"(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__,
465 		divisors->p, divisors->p1, divisors->p2, divisors->n,
466 		divisors->m, divisors->m1, divisors->m2);
467 }
468 
469 
470 void
471 refclk_activate_ilk(bool hasPanel)
472 {
473 	CALLED();
474 
475 	// aka, our engineers hate you
476 
477 	bool wantsSSC;
478 	bool hasCK505;
479 	if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) {
480 		//XXX: This should be == vbt display_clock_mode
481 		hasCK505 = false;
482 		wantsSSC = hasCK505;
483 	} else {
484 		hasCK505 = false;
485 		wantsSSC = true;
486 	}
487 
488 	uint32 clkRef = read32(PCH_DREF_CONTROL);
489 	uint32 newRef = clkRef;
490 
491 	newRef &= ~DREF_NONSPREAD_SOURCE_MASK;
492 
493 	if (hasCK505)
494 		newRef |= DREF_NONSPREAD_CK505_ENABLE;
495 	else
496 		newRef |= DREF_NONSPREAD_SOURCE_ENABLE;
497 
498 	newRef &= ~DREF_SSC_SOURCE_MASK;
499 	newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
500 	newRef &= ~DREF_SSC1_ENABLE;
501 
502 	if (newRef == clkRef) {
503 		TRACE("%s: No changes to reference clock.\n", __func__);
504 		return;
505 	}
506 
507 	if (hasPanel) {
508 		newRef &= ~DREF_SSC_SOURCE_MASK;
509 		newRef |= DREF_SSC_SOURCE_ENABLE;
510 
511 		if (wantsSSC)
512 			newRef |= DREF_SSC1_ENABLE;
513 		else
514 			newRef &= ~DREF_SSC1_ENABLE;
515 
516 		// Power up SSC before enabling outputs
517 		write32(PCH_DREF_CONTROL, newRef);
518 		read32(PCH_DREF_CONTROL);
519 		spin(200);
520 
521 		newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
522 
523 		bool hasEDP = true;
524 		if (hasEDP) {
525 			if (wantsSSC)
526 				newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
527 			else
528 				newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
529 		} else
530 			newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
531 
532 		write32(PCH_DREF_CONTROL, newRef);
533 		read32(PCH_DREF_CONTROL);
534 		spin(200);
535 	} else {
536 		newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
537 		newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
538 
539 		write32(PCH_DREF_CONTROL, newRef);
540 		read32(PCH_DREF_CONTROL);
541 		spin(200);
542 
543 		if (!wantsSSC) {
544 			newRef &= ~DREF_SSC_SOURCE_MASK;
545 			newRef |= DREF_SSC_SOURCE_DISABLE;
546 			newRef &= ~DREF_SSC1_ENABLE;
547 
548 			write32(PCH_DREF_CONTROL, newRef);
549 			read32(PCH_DREF_CONTROL);
550 			spin(200);
551 		}
552 	}
553 }
554 
555