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
14 status_t g450_g550_maven_set_vid_pll(display_mode target);
15 status_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'. */
gx00_maven_clrline()35 status_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
gx00_maven_dpms(bool display,bool h,bool v)72 status_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*/
gx00_maven_set_timing(display_mode target)111 status_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)*/
gx00_maven_mode(int mode,float brightness)207 status_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
gx00_maven_shutoff()228 void 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
gx00_maven_set_vid_pll(display_mode target)247 status_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
g450_g550_maven_set_vid_pll(display_mode target)262 status_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 */
g100_g400max_maven_set_vid_pll(display_mode target)303 status_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 */
g100_g400max_maven_vid_pll_find(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)334 status_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
gx50_maven_check_vid_pll(uint8 m,uint8 n,uint8 p)474 static 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
gx50_maven_check_vid_pll_range(uint8 m,uint8 n,uint8 * p,uint8 * q)508 static 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 */
g450_g550_maven_vid_pll_find(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result,uint8 test)566 status_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