1/* program the MAVEN in monitor mode */
2
3/* Authors:
4   Mark Watson 6/2000,
5   Rudolf Cornelissen 1/2003-5/2006
6
7   Thanx to Petr Vandrovec for writing matroxfb.
8*/
9
10#define MODULE_BIT 0x00001000
11
12#include "mga_std.h"
13
14status_t g450_g550_maven_set_vid_pll(display_mode target);
15status_t g100_g400max_maven_set_vid_pll(display_mode target);
16
17/* This routine blanks the first 'line' below the screen used if there's memory left
18 * to place it in. This will prevent overscanning rubbish on the MAVEN DAC, but only
19 * if no screen using virtual height is setup.
20 * In the rare event the mode and overlay use up so much RAM there's not enough room
21 * left for one blank line, you will get overscanning rubbish from the overlay as it
22 * will overwrite the blank line placed here.
23 * This 'rectangle fill' is done in software because not all modes are supported by
24 * the acc engine.
25 * This function exists to partly overcome a G400 MAVEN hardware design fault, which
26 * influences output in both monitor and TVout modes. The fault is that the MAVEN
27 * keeps repeatedly displaying the last 8 pixels fetched from memory until fetching
28 * restarts after a vertical retrace.
29 * In order to let the maven fetch black pixels, an extra line has to be added to its
30 * CRTC timing. This line needs to be entirely filled black, so with zeros. This line
31 * will be displayed as last visible line, and the last 8 pixels of it will be
32 * repeated during vertical retrace.
33 * Note that the overscanning rubbish can be suppressed in TVout modes by extending
34 * the vertical sync pulse all the way 'to the end'. */
35status_t gx00_maven_clrline()
36{
37	uint32 x, screensize, pointer_reservation;
38	uint8* adr;
39
40	/* this function is nolonger needed on G450/G550 cards */
41	if (si->ps.card_type > G400MAX) return B_OK;
42
43	/* checkout space needed for hardcursor (if any) */
44	pointer_reservation = 0;
45	/* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */
46	if ((si->ps.card_type >= G100) && si->settings.hardcursor) pointer_reservation = 1024;
47
48	/* calculate actual screensize */
49	screensize = si->fbc.bytes_per_row * si->dm.virtual_height;
50
51	/* check if there's room left for a full blank line following the actual screen */
52	if ((screensize + si->fbc.bytes_per_row + pointer_reservation) <=
53		(si->ps.memory_size * 1024 * 1024))
54	{
55		LOG(4,("MAVEN: clearing line directly below screen\n"));
56
57		/* calculate first adress beyond actual screen */
58		adr = (uint8*)si->fbc.frame_buffer;
59		adr += screensize;
60		/* clear the line */
61		for (x = 0; x < si->fbc.bytes_per_row; x++)
62		{
63			*(adr + x) = 0x00;
64		}
65	}
66	else
67		LOG(4,("MAVEN: not clearing line directly below screen: no memory left\n"));
68
69	return B_OK;
70}
71
72status_t gx00_maven_dpms(bool display, bool h, bool v)
73{
74	/* this function is nolonger needed on G450/G550 cards */
75	if (si->ps.card_type > G400MAX) return B_OK;
76
77	if (display && h && v)
78	{
79		/* turn on screen */
80		if (!(si->dm.flags & TV_BITS))
81		{
82			/* monitor mode */
83			MAVW(MONEN, 0xb2);
84			MAVW(MONSET, 0x20);		/* must be set to this in monitor mode */
85			MAVW(OUTMODE, 0x03);	/* output: monitor mode */
86			MAVW(STABLE, 0x22);		/* makes picture stable? */
87			MAVW(TEST, 0x00);		/* turn off test signal */
88		}
89		else
90		{
91			/* TVout mode */
92			MAVW(MONEN, 0xb3);
93			MAVW(MONSET, 0x20);
94			MAVW(OUTMODE, 0x08);	/* output: SVideo/Composite */
95			MAVW(STABLE, 0x02);		/* makes picture stable? */
96			//fixme? linux uses 0x14...
97			MAVW(TEST, (MAVR(TEST) & 0x10));
98		}
99	}
100	else
101	{
102		/* turn off screen using a few methods! */
103		MAVW(STABLE, 0x6a);
104		MAVW(OUTMODE, 0x00);
105	}
106
107	return B_OK;
108}
109
110/*set a mode line - inputs are in pixels/scanlines*/
111status_t gx00_maven_set_timing(display_mode target)
112{
113	uint8 temp, cnt, offset, loop;
114
115	/* this function is nolonger needed on G450/G550 cards */
116	if (si->ps.card_type > G400MAX) return B_OK;
117
118	LOG(4,("MAVEN: setting timing\n"));
119
120	/*check horizontal timing parameters are to nearest 8 pixels*/
121	if ((target.timing.h_display & 0x07)	|
122		(target.timing.h_sync_start & 0x07)	|
123		(target.timing.h_sync_end & 0x07)	|
124		(target.timing.h_total & 0x07))
125	{
126		LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n"));
127		return B_ERROR;
128	}
129
130	/*program the MAVEN*/
131	MAVWW(LASTLINEL, target.timing.h_total);
132	MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
133	MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
134	MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
135					   target.timing.h_display));
136	MAVWW(HTOTALL, (target.timing.h_total + 1));
137
138	MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
139	MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
140	MAVWW(VDISPLAYL, (target.timing.v_total - 1));
141	MAVWW(VTOTALL, (target.timing.v_total - 1));
142
143	MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
144	MAVWW(VVIDRSTL, (target.timing.v_total - 2));
145
146	/* setup HSYNC & VSYNC polarity */
147	LOG(2,("MAVEN: sync polarity: "));
148	temp = MAVR(LUMA);
149
150	/* find out which offset from the 'reset position' we need */
151	switch (((target.timing.flags & B_POSITIVE_HSYNC) >> (29 - 0)) |
152			((target.timing.flags & B_POSITIVE_VSYNC) >> (30 - 1)))
153	{
154	case 0:
155		/* H neg, V neg */
156		LOG(2,("H:neg V:neg\n"));
157		offset = 2;
158		break;
159	case 1:
160		/* H pos, V neg */
161		LOG(2,("H:pos V:neg\n"));
162		offset = 3;
163		break;
164	case 2:
165		/* H neg, V pos */
166		LOG(2,("H:neg V:pos\n"));
167		offset = 1;
168		break;
169	case 3:
170	default:
171		/* H pos, V pos */
172		LOG(2,("H:pos V:pos\n"));
173		offset = 0;
174		break;
175	}
176	/* calculate the number of steps we need to make from the current 'position' */
177	cnt = 0;
178	if ((offset - ((int)si->maven_syncpol_offset)) < 0) cnt = 4;
179	cnt += offset - si->maven_syncpol_offset;
180	/* note the offset from 'reset position' we will have now */
181	si->maven_syncpol_offset = offset;
182
183	/* program the maven: */
184	/* make sure pulse bit is reset */
185	temp &= ~0x20;
186	MAVW(LUMA, temp);
187	snooze(5);
188	/* enable maven sync polarity programming */
189	temp |= 0x10;
190	MAVW(LUMA, temp);
191	snooze(5);
192	/* pulse sync programming bit until we have the polarities we want */
193	for (loop = 0; loop < cnt; loop++)
194	{
195		MAVW(LUMA, (temp | 0x20));
196		snooze(5);
197		MAVW(LUMA, (temp & ~0x20));
198		snooze(5);
199	}
200	/* disable maven sync polarity programming and reset pulse bit */
201	MAVW(LUMA, (temp & ~0x30));
202
203	return B_OK;
204}
205
206/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
207status_t gx00_maven_mode(int mode,float brightness)
208{
209	uint8 luma;
210
211	/* this function is nolonger needed on G450/G550 cards */
212	if (si->ps.card_type > G400MAX) return B_OK;
213
214	/* set luma to a suitable value for brightness */
215	/* assuming 0x0a is a sensible value */
216	/* fixme:
217	 * it looks like b6 and/or b7 determine the luma: just two values possible. */
218	/* NOTE: b4 and b5 have another function, don't set! (sync polarity programming) */
219	luma = (uint8)(0x0a * brightness);
220	if (luma > 0x0f) luma = 0x0f;
221
222	MAVW(LUMA, luma);
223	LOG(4,("MAVEN: LUMA setting - %x\n", luma));
224
225	return B_OK;
226}
227
228void gx00_maven_shutoff()
229{
230	switch (si->ps.card_type)
231	{
232		case G100:
233		case G200:
234		//fixme: see if this works on G400 too:
235		//case G400:
236		//case G400MAX:
237			/* prevents distortions on CRTC1... */
238			MAVW(TEST, 0x03);
239			MAVW(MONEN, 0x00);
240			MAVW(MONSET, 0x00);
241			break;
242		default:
243			break;
244	}
245}
246
247status_t gx00_maven_set_vid_pll(display_mode target)
248{
249	switch (si->ps.card_type)
250	{
251		case G450:
252		case G550:
253			return g450_g550_maven_set_vid_pll(target);
254			break;
255		default:
256			return g100_g400max_maven_set_vid_pll(target);
257			break;
258	}
259	return B_ERROR;
260}
261
262status_t g450_g550_maven_set_vid_pll(display_mode target)
263{
264	uint8 m=0,n=0,p=0;
265	uint time = 0;
266
267	float pix_setting, req_pclk;
268	status_t result;
269
270	req_pclk = (target.timing.pixel_clock)/1000.0;
271	LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
272
273	result = g450_g550_maven_vid_pll_find(target,&pix_setting,&m,&n,&p, 1);
274	if (result != B_OK)
275	{
276		return result;
277	}
278
279	/*reprogram (disable,select,wait for stability,enable)*/
280	CR2W(CTL, (CR2R(CTL) | 0x08)); 					/* disable the VIDPLL */
281	CR2W(CTL, (CR2R(CTL) | 0x06)); 					/* select the VIDPLL */
282	DXIW(VIDPLLM,(m));								/* set m value */
283	DXIW(VIDPLLN,(n));								/* set n value */
284	DXIW(VIDPLLP,(p));								/* set p value */
285
286	/* Wait for the VIDPLL frequency to lock until timeout occurs */
287	while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 2000))
288	{
289		time++;
290		snooze(1);
291	}
292
293	if (time > 2000)
294		LOG(2,("MAVEN: VID PLL frequency not locked!\n"));
295	else
296		LOG(2,("MAVEN: VID PLL frequency locked\n"));
297	CR2W(CTL, (CR2R(CTL) & ~0x08)); 				/* enable the VIDPLL */
298
299	return B_OK;
300}
301
302/* program the video PLL in the MAVEN */
303status_t g100_g400max_maven_set_vid_pll(display_mode target)
304{
305	uint8 m=0,n=0,p=0;
306
307	float pix_setting, req_pclk;
308	status_t result;
309
310	req_pclk = (target.timing.pixel_clock)/1000.0;
311	LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
312
313	result = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p);
314	if (result != B_OK)
315	{
316		return result;
317	}
318
319	/*reprogram (select,wait for stability)*/
320	MAVW(PIXPLLM,(m));								/* set m value */
321	MAVW(PIXPLLN,(n));								/* set n value */
322	MAVW(PIXPLLP,(p | 0x80));						/* set p value enabling PLL */
323
324	/* Wait for the VIDPLL frequency to lock: detection is not possible it seems */
325	snooze(2000);
326
327	LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
328
329	return B_OK;
330}
331
332
333/* find nearest valid video PLL setting */
334status_t g100_g400max_maven_vid_pll_find(
335	display_mode target, float* calc_pclk, uint8* m_result, uint8* n_result,
336	uint8* p_result)
337{
338	int m = 0, n = 0, p = 0, m_max;
339	float error, error_best = INT_MAX;
340	int best[3] = {0, 0, 0};
341	float f_vco, max_pclk;
342	float req_pclk = target.timing.pixel_clock/1000.0;
343
344	/* determine the max. reference-frequency postscaler setting for the current card */
345	//fixme: check G100 and G200 m_max if possible...
346	switch (si->ps.card_type)
347	{
348	case G100:
349		LOG(4, ("MAVEN: G100 restrictions apply\n"));
350		m_max = 32;
351		break;
352	case G200:
353		LOG(4, ("MAVEN: G200 restrictions apply\n"));
354		m_max = 32;
355		break;
356	default:
357		LOG(4, ("MAVEN: G400/G400MAX restrictions apply\n"));
358		m_max = 32;
359		break;
360	}
361
362	/* determine the max. pixelclock for the current videomode */
363	switch (target.space)
364	{
365		case B_RGB16_LITTLE:
366			max_pclk = si->ps.max_dac2_clock_16;
367			break;
368		case B_RGB32_LITTLE:
369			max_pclk = si->ps.max_dac2_clock_32;
370			break;
371		default:
372			/* use fail-safe value */
373			max_pclk = si->ps.max_dac2_clock_32;
374			break;
375	}
376	/* if some dualhead mode is active, an extra restriction might apply */
377	if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
378		max_pclk = si->ps.max_dac2_clock_32dh;
379
380	/* Make sure the requested pixelclock is within the PLL's operational limits */
381	/* lower limit is min_video_vco divided by highest postscaler-factor */
382	if (req_pclk < (si->ps.min_video_vco / 8.0))
383	{
384		LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
385			req_pclk, (float)(si->ps.min_video_vco / 8.0)));
386		req_pclk = (si->ps.min_video_vco / 8.0);
387	}
388	/* upper limit is given by pins in combination with current active mode */
389	if (req_pclk > max_pclk)
390	{
391		LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
392			req_pclk, (float)max_pclk));
393		req_pclk = max_pclk;
394	}
395
396	/* iterate through all valid PLL postscaler settings */
397	for (p=0x01; p < 0x10; p = p<<1)
398	{
399		/* calculate the needed VCO frequency for this postscaler setting */
400		f_vco = req_pclk * p;
401
402		/* check if this is within range of the VCO specs */
403		if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
404		{
405			/* iterate trough all valid reference-frequency postscaler settings */
406			for (m = 2; m <= m_max; m++)
407			{
408				/* calculate VCO postscaler setting for current setup.. */
409				n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
410				/* ..and check for validity */
411				if ((n < 8) || (n > 128))	continue;
412
413				/* find error in frequency this setting gives */
414				error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
415
416				/* note the setting if best yet */
417				if (error < error_best)
418				{
419					error_best = error;
420					best[0]=m;
421					best[1]=n;
422					best[2]=p;
423				}
424			}
425		}
426	}
427
428	/* setup the scalers programming values for found optimum setting */
429	m=best[0] - 1;
430	n=best[1] - 1;
431	p=best[2] - 1;
432
433	/* calc the needed PLL loopbackfilter setting belonging to current VCO speed */
434	f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
435	LOG(2, ("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
436
437	switch (si->ps.card_type)
438	{
439	case G100:
440	case G200:
441		for (;;)
442		{
443			if (f_vco >= 180) {p |= (0x03 << 3); break;};
444			if (f_vco >= 140) {p |= (0x02 << 3); break;};
445			if (f_vco >= 100) {p |= (0x01 << 3); break;};
446			break;
447		}
448		break;
449	default:
450		for (;;)
451		{
452			if (f_vco >= 240) {p |= (0x03 << 3); break;};
453			if (f_vco >= 170) {p |= (0x02 << 3); break;};
454			if (f_vco >= 110) {p |= (0x01 << 3); break;};
455			break;
456		}
457		break;
458	}
459
460	/* return the results */
461	*calc_pclk = f_vco / ((p & 0x07) + 1);
462	*m_result = m;
463	*n_result = n;
464	*p_result = p;
465
466	/* display the found pixelclock values */
467	LOG(2, ("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
468		req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
469
470	return B_OK;
471}
472
473
474static status_t gx50_maven_check_vid_pll(uint8 m, uint8 n, uint8 p)
475{
476	uint time = 0, count = 0;
477
478	/* reprogram (disable,select,wait for stability,enable) */
479	CR2W(CTL, (CR2R(CTL) | 0x06)); 					/* select the VIDPLL */
480	DXIW(VIDPLLM,(m));								/* set m value */
481	DXIW(VIDPLLN,(n));								/* set n value */
482	DXIW(VIDPLLP,(p));								/* set p value */
483
484	/* give the PLL 1mS at least to get a lock */
485	time = 0;
486	while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 1000))
487	{
488		time++;
489		snooze(1);
490	}
491
492	/* no lock aquired, not useable */
493	if (time > 1000) return B_ERROR;
494
495	/* check if lock holds for at least 90% of the time */
496	for (time = 0, count = 0; time <= 1000; time++)
497	{
498		if(DXIR(VIDPLLSTAT) & 0x40) count++;
499		snooze(1);
500	}
501	/* we have a winner */
502	if (count >= 900) return B_OK;
503
504	/* nogo, the PLL does not stabilize */
505	return B_ERROR;
506}
507
508static status_t gx50_maven_check_vid_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
509{
510	uint8 s=0, p_backup = *p;
511
512	/* preset no candidate, non working setting */
513	*q = 0;
514	/* preset lowest range filter */
515	*p &= 0x47;
516
517	/* iterate through all possible filtersettings */
518	CR2W(CTL, (CR2R(CTL) | 0x08)); /* disable the VIDPLL */
519
520	for (s = 0; s < 8 ;s++)
521	{
522		if (gx50_maven_check_vid_pll(m, n, *p)== B_OK)
523		{
524			/* now check 3 closest lower and higher settings */
525			if ((gx50_maven_check_vid_pll(m, n - 3, *p)== B_OK) &&
526				(gx50_maven_check_vid_pll(m, n - 2, *p)== B_OK) &&
527				(gx50_maven_check_vid_pll(m, n - 1, *p)== B_OK) &&
528				(gx50_maven_check_vid_pll(m, n + 1, *p)== B_OK) &&
529				(gx50_maven_check_vid_pll(m, n + 2, *p)== B_OK) &&
530				(gx50_maven_check_vid_pll(m, n + 3, *p)== B_OK))
531			{
532				LOG(2,("MAVEN: found optimal working VCO filter: #%d\n",s));
533				/* preset first choice setting found */
534				*q = 1;
535				/* we are done */
536				CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */
537				return B_OK;
538			}
539			else
540			{
541				LOG(2,("MAVEN: found critical but working VCO filter: #%d\n",s));
542				/* preset backup setting found */
543				*q = 2;
544				/* remember this setting */
545				p_backup = *p;
546				/* let's continue to see if a better filter exists */
547			}
548		}
549	/* new filtersetting to try */
550	*p += (1 << 3);
551	}
552
553	/* return the (last found) backup result, or the original p value */
554	*p = p_backup;
555	CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */
556	/* we found only a non-optimal value */
557	if (*q == 2) return B_OK;
558
559	/* nothing worked at all */
560	LOG(2,("MAVEN: no working VCO filter found!\n"));
561	return B_ERROR;
562}
563
564
565/* find nearest valid video PLL setting */
566status_t g450_g550_maven_vid_pll_find
567	(display_mode target, float* calc_pclk, uint8* m_result, uint8* n_result,
568	uint8* p_result, uint8 test)
569{
570	int m = 0, n = 0;
571	uint8 p = 0, q = 0;
572	float error, error_best = INFINITY;
573	int best[3] = {0, 0, 0};
574	float f_vco, max_pclk;
575	float req_pclk = target.timing.pixel_clock/1000.0;
576
577	LOG(4, ("MAVEN: G450/G550 restrictions apply\n"));
578
579	/* determine the max. pixelclock for the current videomode */
580	switch (target.space)
581	{
582		case B_RGB16_LITTLE:
583			max_pclk = si->ps.max_dac2_clock_16;
584			break;
585		case B_RGB32_LITTLE:
586			max_pclk = si->ps.max_dac2_clock_32;
587			break;
588		default:
589			/* use fail-safe value */
590			max_pclk = si->ps.max_dac2_clock_32;
591			break;
592	}
593	/* if some dualhead mode is active, an extra restriction might apply */
594	if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
595		max_pclk = si->ps.max_dac2_clock_32dh;
596
597	/* Make sure the requested pixelclock is within the PLL's operational limits */
598	/* lower limit is min_pixel_vco divided by highest postscaler-factor */
599	if (req_pclk < (si->ps.min_video_vco / 16.0))
600	{
601		LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
602			req_pclk, (float)(si->ps.min_video_vco / 16.0)));
603		req_pclk = (si->ps.min_video_vco / 16.0);
604	}
605	/* upper limit is given by pins in combination with current active mode */
606	if (req_pclk > max_pclk)
607	{
608		LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
609			req_pclk, (float)max_pclk));
610		req_pclk = max_pclk;
611	}
612
613	/* iterate through all valid PLL postscaler settings */
614	for (p=0x01; p < 0x20; p = p<<1)
615	{
616		/* calculate the needed VCO frequency for this postscaler setting */
617		f_vco = req_pclk * p;
618
619		/* check if this is within range of the VCO specs */
620		if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
621		{
622			/* iterate trough all valid reference-frequency postscaler settings */
623			for (m = 2; m <= 32; m++)
624			{
625				/* calculate VCO postscaler setting for current setup.. */
626				n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5);
627				/* ..and check for validity, BUT:
628				 * Keep in mind that we need to be able to test n-3 ... n+3! */
629				if ((n < (8 + 3)) || (n > (128 - 3)))	continue;
630
631				/* find error in frequency this setting gives */
632				error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p));
633
634				/* note the setting if best yet */
635				if (error < error_best)
636				{
637					error_best = error;
638					best[0]=m;
639					best[1]=n;
640					best[2]=p;
641				}
642			}
643		}
644	}
645
646	/* setup the scalers programming values for found optimum setting */
647	m=best[0] - 1;
648	n=best[1] - 2;
649	switch (best[2])
650	{
651	case 1:
652		p = 0x40;
653		break;
654	case 2:
655		p = 0x00;
656		break;
657	case 4:
658		p = 0x01;
659		break;
660	case 8:
661		p = 0x02;
662		break;
663	case 16:
664		p = 0x03;
665		break;
666	}
667
668	/* log the closest VCO speed found */
669	f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2);
670	LOG(2, ("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
671
672	/* now find the filtersetting that matches best with this frequency by testing.
673	 * for now we assume this routine succeeds to get us a stable setting */
674	if (test)
675		gx50_maven_check_vid_pll_range(m, n, &p, &q);
676	else
677		LOG(2, ("MAVEN: Not testing G450/G550 VCO feedback filters\n"));
678
679	/* return the results */
680	*calc_pclk = f_vco / best[2];
681	*m_result = m;
682	*n_result = n;
683	*p_result = p;
684
685	/* display the found pixelclock values */
686	LOG(2, ("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
687		req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
688
689	return B_OK;
690}
691