xref: /haiku/src/add-ons/accelerants/intel_extreme/pll.cpp (revision 385ee03ba83b7a40d315e17b03031b3ca37820c0)
1 /*
2  * Copyright 2006-2016, 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  *
9  * PLL TEST MODE
10  *  pll's on Intel can be extremely difficult. After
11  *  making any changes, it is advised to run PLL_TEST_MODE
12  *  to simulate your pll calculations on every card.
13  *  Example:
14  *  gcc pll.cpp \
15  *    -I $TOP/headers/private/graphics/intel_extreme/
16  *    -I $TOP/headers/private/graphics/common/
17  *    -I $TOP/headers/private/graphics/ -D PLL_TEST_MODE
18  */
19 
20 
21 #include "pll.h"
22 
23 #include <math.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <Debug.h>
28 
29 #include <create_display_modes.h>
30 #include <ddc.h>
31 #include <edid.h>
32 #include <validate_display_mode.h>
33 
34 #include "accelerant_protos.h"
35 #include "accelerant.h"
36 #include "utility.h"
37 
38 
39 #undef TRACE
40 #define TRACE_MODE
41 #ifdef TRACE_MODE
42 #	define TRACE(x...) _sPrintf("intel_extreme: " x)
43 #else
44 #	define TRACE(x...)
45 #endif
46 
47 #define ERROR(x...) _sPrintf("intel_extreme: " x)
48 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
49 
50 
51 #ifdef PLL_TEST_MODE
52 #undef ERROR
53 #undef CALLED
54 #undef TRACE
55 
56 #define TRACE(x...) printf("intel_extreme: " x)
57 #define ERROR(x...) printf("intel_extreme: " x)
58 #define CALLED(X...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
59 struct accelerant_info* gInfo;
60 #endif
61 
62 // Static pll limits taken from Linux kernel KMS
63 
64 static pll_limits kLimitsIlkDac = {
65 	// p, p1, p2, n,   m, m1, m2
66 	{  5,  2, 14, 1,  79, 12,  5}, // min
67 	{ 80,  8, 14, 3, 118, 22,  9}, // max
68 	225000, 1760000, 3510000
69 };
70 
71 static pll_limits kLimitsIlkLvdsSingle = {
72 	// p, p1, p2, n,   m, m1, m2
73 	{ 28,  2, 14, 1,  79, 12,  5}, // min
74 	{112,  8, 14, 3, 118, 22,  9}, // max
75 	225000, 1760000, 3510000
76 };
77 
78 static pll_limits kLimitsIlkLvdsDual = {
79 	// p, p1, p2, n,   m, m1, m2
80 	{ 14,  2,  7, 1,  79, 12,  5}, // min
81 	{ 56,  8,  7, 3, 127, 22,  9}, // max
82 	225000, 1760000, 3510000
83 };
84 
85 // 100Mhz RefClock
86 static pll_limits kLimitsIlkLvdsSingle100 = {
87 	// p, p1, p2, n,   m, m1, m2
88 	{ 28,  2, 14, 1,  79, 12,  5}, // min
89 	{112,  8, 14, 2, 126, 22,  9}, // max
90 	225000, 1760000, 3510000
91 };
92 
93 static pll_limits kLimitsIlkLvdsDual100 = {
94 	// p, p1, p2, n,   m, m1, m2
95 	{ 14,  2,  7, 1,  79, 12,  5}, // min
96 	{ 42,  6,  7, 3, 126, 22,  9}, // max
97 	225000, 1760000, 3510000
98 };
99 
100 #if 0
101 static pll_limits kLimitsChv = {
102 	// p, p1, p2, n,   m, m1, m2
103 	{  0,  2, 14, 1,  79, 2,   24 << 22}, // min
104 	{  0,  4,  1, 1, 127, 2,  175 << 22}, // max
105 	0, 4800000, 6480000
106 };
107 
108 static pll_limits kLimitsVlv = {
109 	// p, p1, p2, n,   m, m1, m2
110 	{  0,  2, 20, 1,  79, 2,   11},	// min
111 	{  0,  3,  2, 7, 127, 3,  156},	// max
112 	0, 4000000, 6000000
113 };
114 
115 static pll_limits kLimitsBxt = {
116 	// p, p1, p2, n,  m, m1, m2
117 	{  0,  2,  1, 1,  0,  2,   2 << 22}, // min
118 	{  0,  4, 20, 1,  0,  2, 255 << 22}, // max
119 	0, 4800000, 6700000
120 };
121 #endif
122 
123 static pll_limits kLimits9xxSdvo = {
124 	// p, p1, p2,  n,   m, m1, m2
125 	{  5,  1, 10,  5,  70, 12,  7},	// min
126 	{ 80,  8,  5, 10, 120, 22, 11},	// max
127 	200000, 1400000, 2800000
128 };
129 
130 static pll_limits kLimits9xxLvds = {
131 	// p, p1, p2,  n,   m, m1, m2
132 	{  7,  1, 14,  1,  70,  8,  3},	// min
133 	{ 98,  8,  7,  6, 120, 18,  7},	// max
134 	112000, 1400000, 2800000
135 };
136 
137 static pll_limits kLimitsG4xSdvo = {
138 	// p, p1, p2, n,   m, m1, m2
139 	{ 10,  1, 10, 1, 104, 17,  5},	// min
140 	{ 30,  3, 10, 4, 138, 23, 11},	// max
141 	270000, 1750000, 3500000
142 };
143 
144 #if 0
145 static pll_limits kLimitsG4xHdmi = {
146 	// p, p1, p2, n,   m, m1, m2
147 	{  5,  1, 10, 1, 104, 16,  5},	// min
148 	{ 80,  8,  5, 4, 138, 23, 11},	// max
149 	165000, 1750000, 3500000
150 };
151 #endif
152 
153 static pll_limits kLimitsG4xLvdsSingle = {
154 	// p,  p1, p2, n,   m, m1, m2
155 	{ 28,   2, 14, 1, 104, 17,  5},	// min
156 	{ 112,  8, 14, 3, 138, 23, 11},	// max
157 	0, 1750000, 3500000
158 };
159 
160 static pll_limits kLimitsG4xLvdsDual = {
161 	// p, p1, p2, n,   m, m1, m2
162 	{ 14,  2,  7, 1, 104, 17,  5},	// min
163 	{ 42,  6,  7, 3, 138, 23, 11},	// max
164 	0, 1750000, 3500000
165 };
166 
167 static pll_limits kLimitsPinSdvo = {
168 	// p, p1, p2, n,   m, m1,  m2
169 	{  5,  1, 10, 3,   2,  0,   0},	// min
170 	{ 80,  8,  5, 6, 256,  0, 254},	// max
171 	200000, 1700000, 3500000
172 };
173 
174 static pll_limits kLimitsPinLvds = {
175 	// p, p1, p2, n,   m, m1,  m2
176 	{  7,  1, 14, 3,   2,  0,   0},	// min
177 	{112,  8, 14, 6, 256,  0, 254},	// max
178 	112000, 1700000, 3500000
179 };
180 
181 #if 0
182 static pll_limits kLimits = {
183 	// p, p1, p2,  n,   m, m1, m2
184 	{  4,  2,  4,  5,  96, 20,  8},
185 	{128, 33,  2, 18, 140, 28, 18},
186 	165000, 930000, 1400000
187 };
188 #endif
189 
190 
191 static bool
192 lvds_dual_link(display_mode* current)
193 {
194 	float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
195 	if (requestedPixelClock > 112.999)
196 		return true;
197 
198 	// TODO: Force dual link on MacBookPro6,2  MacBookPro8,2  MacBookPro9,1
199 
200 	return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
201 		== LVDS_CLKB_POWER_UP);
202 }
203 
204 
205 bool
206 valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
207 {
208 	pll_info &info = gInfo->shared_info->pll_info;
209 	uint32 vco = info.reference_frequency * divisors->m / divisors->n;
210 	uint32 frequency = vco / divisors->p;
211 
212 	if (divisors->p < limits->min.p || divisors->p > limits->max.p
213 		|| divisors->m < limits->min.m || divisors->m > limits->max.m
214 		|| vco < limits->min_vco || vco > limits->max_vco
215 		|| frequency < info.min_frequency || frequency > info.max_frequency)
216 		return false;
217 
218 	return true;
219 }
220 
221 
222 static void
223 compute_pll_p2(display_mode* current, pll_divisors* divisors,
224 	pll_limits* limits, bool isLVDS)
225 {
226 	if (isLVDS) {
227 		if (lvds_dual_link(current)) {
228 			// fast DAC timing via 2 channels (dual link LVDS)
229 			divisors->p2 = limits->max.p2;
230 		} else {
231 			// slow DAC timing
232 			divisors->p2 = limits->min.p2;
233 		}
234 	} else {
235 		if (current->timing.pixel_clock < limits->dot_limit) {
236 			// slow DAC timing
237 			divisors->p2 = limits->min.p2;
238 		} else {
239 			// fast DAC timing
240 			divisors->p2 = limits->max.p2;
241 		}
242 	}
243 }
244 
245 
246 static uint32
247 compute_pll_m(pll_divisors* divisors)
248 {
249 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)
250 		|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
251 		return divisors->m1 * divisors->m2;
252 	}
253 
254 	// Pineview, m1 is reserved
255 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN))
256 		return divisors->m2 + 2;
257 
258 	if (gInfo->shared_info->device_type.Generation() >= 3)
259 		return 5 * (divisors->m1 + 2) + (divisors->m2 + 2);
260 
261 	// TODO: This logic needs validated... PLL's were calculated differently
262 	// on 8xx chipsets
263 
264 	return 5 * divisors->m1 + divisors->m2;
265 }
266 
267 
268 static uint32
269 compute_pll_p(pll_divisors* divisors)
270 {
271 	return divisors->p1 * divisors->p2;
272 }
273 
274 
275 static void
276 compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
277 {
278 	float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
279 	float referenceClock
280 		= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
281 
282 	TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
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 		if (isLVDS) {
298 			if (lvds_dual_link(current)) {
299 				if (referenceClock == 100.0)
300 					memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits));
301 				else
302 					memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits));
303 			} else {
304 				if (referenceClock == 100.0) {
305 					memcpy(&limits, &kLimitsIlkLvdsSingle100,
306 						sizeof(pll_limits));
307 				} else {
308 					memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits));
309 				}
310 			}
311 		} else {
312 			memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits));
313 		}
314 	}
315 
316 	compute_pll_p2(current, divisors, &limits, isLVDS);
317 
318 	TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
319 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
320 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
321 		limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
322 		limits.min.m1, limits.min.m2);
323 	TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
324 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
325 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
326 		limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
327 		limits.max.m1, limits.max.m2);
328 
329 	float best = requestedPixelClock;
330 	pll_divisors bestDivisors;
331 
332 	uint32 maxn = limits.max.n;
333 	for (divisors->n = limits.min.n; divisors->n <= maxn; divisors->n++) {
334 		for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1;
335 				divisors->m1--) {
336 			for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2;
337 					divisors->m2--) {
338 				for (divisors->p1 = limits.max.p1;
339 						divisors->p1 >= limits.min.p1; divisors->p1--) {
340 					divisors->m = compute_pll_m(divisors);
341 					divisors->p = compute_pll_p(divisors);
342 
343 					if (!valid_pll_divisors(divisors, &limits))
344 						continue;
345 
346 					float error = fabs(requestedPixelClock
347 						- ((referenceClock * divisors->m) / divisors->n)
348 						/ divisors->p);
349 					if (error < best) {
350 						best = error;
351 						bestDivisors = *divisors;
352 						maxn = divisors->n;
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 {
384 		if (isLVDS)
385 			memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits));
386 		else
387 			memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits));
388 	}
389 
390 	compute_pll_p2(current, divisors, &limits, isLVDS);
391 
392 	TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
393 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
394 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
395 		limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
396 		limits.min.m1, limits.min.m2);
397 	TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
398 		"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
399 		"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
400 		limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
401 		limits.max.m1, limits.max.m2);
402 
403 	bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN);
404 
405 	float best = requestedPixelClock;
406 	pll_divisors 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) / divisors->n)
424 						/ 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 	TRACE("%s: best MHz: %g (error: %g)\n", __func__,
440 		((referenceClock * divisors->m) / divisors->n) / divisors->p,
441 		best);
442 }
443 
444 
445 void
446 compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS)
447 {
448 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
449 		|| (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) {
450 		compute_dpll_g4x(current, divisors, isLVDS);
451 	} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
452 		ERROR("%s: TODO: CherryView\n", __func__);
453 	} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
454 		ERROR("%s: TODO: VallyView\n", __func__);
455 	} else
456 		compute_dpll_9xx(current, divisors, isLVDS);
457 
458 	TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
459 		"p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " "
460 		"(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__,
461 		divisors->p, divisors->p1, divisors->p2, divisors->n,
462 		divisors->m, divisors->m1, divisors->m2);
463 }
464 
465 
466 void
467 refclk_activate_ilk(bool hasPanel)
468 {
469 	CALLED();
470 
471 	// aka, our engineers hate you
472 
473 	bool wantsSSC;
474 	bool hasCK505;
475 	if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) {
476 		//XXX: This should be == vbt display_clock_mode
477 		hasCK505 = true;
478 		wantsSSC = hasCK505;
479 	} else {
480 		hasCK505 = false;
481 		wantsSSC = true;
482 	}
483 
484 	uint32 clkRef = read32(PCH_DREF_CONTROL);
485 	uint32 newRef = clkRef;
486 
487 	newRef &= ~DREF_NONSPREAD_SOURCE_MASK;
488 
489 	if (hasCK505)
490 		newRef |= DREF_NONSPREAD_CK505_ENABLE;
491 	else
492 		newRef |= DREF_NONSPREAD_SOURCE_ENABLE;
493 
494 	newRef &= ~DREF_SSC_SOURCE_MASK;
495 	newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
496 	newRef &= ~DREF_SSC1_ENABLE;
497 
498 	if (newRef == clkRef) {
499 		TRACE("%s: No changes to reference clock.\n", __func__);
500 		return;
501 	}
502 
503 	if (hasPanel) {
504 		newRef &= ~DREF_SSC_SOURCE_MASK;
505 		newRef |= DREF_SSC_SOURCE_ENABLE;
506 
507 		if (wantsSSC)
508 			newRef |= DREF_SSC1_ENABLE;
509 		else
510 			newRef &= ~DREF_SSC1_ENABLE;
511 
512 		// Power up SSC before enabling outputs
513 		write32(PCH_DREF_CONTROL, newRef);
514 		read32(PCH_DREF_CONTROL);
515 		spin(200);
516 
517 		newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
518 
519 		bool hasEDP = true;
520 		if (hasEDP) {
521 			if (wantsSSC)
522 				newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
523 			else
524 				newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
525 		} else
526 			newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
527 
528 		write32(PCH_DREF_CONTROL, newRef);
529 		read32(PCH_DREF_CONTROL);
530 		spin(200);
531 	} else {
532 		newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
533 		newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
534 
535 		write32(PCH_DREF_CONTROL, newRef);
536 		read32(PCH_DREF_CONTROL);
537 		spin(200);
538 
539 		if (!wantsSSC) {
540 			newRef &= ~DREF_SSC_SOURCE_MASK;
541 			newRef |= DREF_SSC_SOURCE_DISABLE;
542 			newRef &= ~DREF_SSC1_ENABLE;
543 
544 			write32(PCH_DREF_CONTROL, newRef);
545 			read32(PCH_DREF_CONTROL);
546 			spin(200);
547 		}
548 	}
549 }
550 
551 
552 #ifdef PLL_TEST_MODE
553 
554 const struct  test_device {
555 	uint32 type;
556 	const char* name;
557 } kTestDevices[] = {
558 	{INTEL_MODEL_915, "915"},
559 	{INTEL_MODEL_945, "945"},
560 	{INTEL_MODEL_965, "965"},
561 	{INTEL_MODEL_G33, "G33"},
562 	{INTEL_MODEL_G45, "G45"},
563 	{INTEL_MODEL_PINE, "PineView"},
564 	{INTEL_MODEL_ILKG, "IronLake"},
565 	{INTEL_MODEL_SNBG, "SandyBridge"},
566 	{INTEL_MODEL_IVBG, "IvyBridge"}
567 };
568 
569 
570 static void
571 simulate_mode(display_mode* mode)
572 {
573 	mode->timing.flags = 0;
574 	mode->timing.pixel_clock = uint32(75.2 * 1000);
575 	mode->timing.h_display = 1366;
576 	mode->timing.h_sync_start = 1414;
577 	mode->timing.h_sync_end = 1478;
578 	mode->timing.h_total = 1582;
579 
580 	mode->timing.v_display = 768;
581 	mode->timing.v_sync_start = 772;
582 	mode->timing.v_sync_end = 779;
583 	mode->timing.v_total = 792;
584 
585 	mode->virtual_width = 1366;
586 	mode->virtual_height = 768;
587 }
588 
589 
590 int
591 main(void)
592 {
593 	display_mode fakeMode;
594 	simulate_mode(&fakeMode);
595 
596 	// First we simulate our global card info structs
597 	gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
598 	if (gInfo == NULL) {
599 		ERROR("Unable to malloc artificial gInfo!\n");
600 		return 1;
601 	}
602 	gInfo->shared_info = (intel_shared_info*)malloc(sizeof(intel_shared_info));
603 
604 	for (uint32 index = 0; index < (sizeof(kTestDevices) / sizeof(test_device));
605 		index++) {
606 		gInfo->shared_info->device_type = kTestDevices[index].type;
607 		ERROR("=== %s (Generation %d)\n",  kTestDevices[index].name,
608 			gInfo->shared_info->device_type.Generation());
609 
610 		if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)
611 			| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)) {
612 			gInfo->shared_info->pll_info.reference_frequency = 96000;
613 			gInfo->shared_info->pll_info.max_frequency = 400000;
614 			gInfo->shared_info->pll_info.min_frequency = 20000;
615 		} else {
616 			gInfo->shared_info->pll_info.reference_frequency = 96000;
617 			gInfo->shared_info->pll_info.max_frequency = 400000;
618 			gInfo->shared_info->pll_info.min_frequency = 20000;
619 		}
620 
621 		pll_divisors output;
622 		compute_pll_divisors(&fakeMode, &output, false);
623 	}
624 
625 	free(gInfo->shared_info);
626 	free(gInfo);
627 	return 0;
628 }
629 #endif
630