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