vmodes.c revision 0b661123
1/*
2 * file vmodes.c
3 *
4 * Routines that handle mode setting.
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11/*
12 * includes
13 */
14
15#include "rendition.h"
16#include "vmodes.h"
17#include "vos.h"
18#include "vramdac.h"
19#include "v1krisc.h"
20#include "v1kregs.h"
21#include "v2kregs.h"
22
23
24#undef DEBUG
25
26
27/*
28 * defines
29 */
30
31#define combineNMP(N, M, P) \
32    (((vu32)(M-2)<<10) | ((vu32)P<<8) | (vu32)(N-2))
33
34#define v2kcombineNMP(N, M, P) (((vu32)N<<13) | ((vu32)P<<9) | (vu32)M)
35
36/* defines for doubled clock */
37#define CLK_DOUBLE		1
38#define NO_CLK_DOUBLE	0
39
40/* video FIFO is set to 64 or 128 entries based on req.d bandwidth in bytes/s */
41#define FIFOSIZE_THRESH 	100000000 	 /* set thresh to 100MB/s */
42
43/* compute desired video FIFO size given total bandwidth in bytes/s. */
44#define FIFOSIZE(vclk, Bpp) (((vclk * Bpp) > FIFOSIZE_THRESH)  ? 128 : 64)
45
46/* Bt485A RAMDAC control bits */
47#define PALETTEDISABLE		0x10
48
49/* Hold memory refresh cycles until video blank */
50#define HOLD_MEMREFRESHCYCLE 0x2000
51
52/* memCtl bits [16..23] */
53#define DEFAULT_WREFRESH	0x330000
54
55/* Disable memory refresh cycles */
56#define DISABLE_MEMREFRESHCYCLE		0x8000
57
58#define CTL(ldbl, hsynchi, vsynchi) \
59  (((ldbl) ? CRTCCTL_LINEDOUBLE : 0) \
60  |((hsynchi) ? CRTCCTL_HSYNCHI : 0) \
61  |((vsynchi) ? CRTCCTL_VSYNCHI : 0) \
62  |(CRTCCTL_VSYNCENABLE | CRTCCTL_HSYNCENABLE))
63
64#define HORZ(fp, sy, bp, ac) \
65  (((((vu32)(((fp)>>3)-1))&7)<<21)|((((vu32)(((sy)>>3)-1))&0x1F)<<16)|((((vu32)(((bp)>>3)-1))&0x3f)<<9)|((((vu32)(((ac)>>3)-1))&0xff)))
66
67#define VERT(fp, sy, bp, ac) \
68  (((((vu32)(fp-1))&0x3f)<<20)|((((vu32)(sy-1))&0x7)<<17)|((((vu32)(bp-1))&0x3f)<<11)|((((vu32)(ac-1))&0x7ff)))
69
70#define HORZAC(crtchorz) \
71  (((((vu32)crtchorz)&CRTCHORZ_ACTIVE_MASK)+1)<<3)
72
73#define HORZBP(crtchorz) \
74  ((((((vu32)crtchorz)&CRTCHORZ_BACKPORCH_MASK)>>9)+1)<<3)
75
76#define HORZSY(crtchorz) \
77  ((((((vu32)crtchorz)&CRTCHORZ_SYNC_MASK)>>16)+1)<<3)
78
79#define HORZFP(crtchorz) \
80  ((((((vu32)crtchorz)&CRTCHORZ_FRONTPORCH_MASK)>>21)+1)<<3)
81
82#define VERTAC(crtcvert) \
83  ((((vu32)crtcvert)&CRTCVERT_ACTIVE_MASK)+1)
84
85#define VERTBP(crtcvert) \
86  (((((vu32)crtcvert)&CRTCVERT_BACKPORCH_MASK)>>11)+1)
87
88#define VERTSY(crtcvert) \
89  (((((vu32)crtcvert)&CRTCVERT_SYNC_MASK)>>17)+1)
90
91#define VERTFP(crtcvert) \
92  (((((vu32)crtcvert)&CRTCVERT_FRONTPORCH_MASK)>>20)+1)
93
94#define PCLK(N, M, P) (N),(M),(P)
95
96#define TIMING_MASK	(CRTCCTL_VIDEOFIFOSIZE128|CRTCCTL_LINEDOUBLE|\
97			         CRTCCTL_VSYNCHI|CRTCCTL_HSYNCHI|CRTCCTL_VSYNCENABLE|\
98                     CRTCCTL_HSYNCENABLE)
99
100/* addr&7 == 5, 6, 7 are bad */
101#define BADADDR(x)	(((x)&(((x)<<1)|((x)<<2)))&0x4)
102
103#define V1_MIN_VCO_FREQ  25
104#define V1_MAX_VCO_FREQ  135
105#define V1_REF_FREQ      14.318
106#define V1_MIN_PCF_FREQ  0.2
107#define V1_MAX_PCF_FREQ  5
108
109#define V2_MIN_VCO_FREQ  125
110#define V2_MAX_VCO_FREQ  250
111#define V2_REF_FREQ      14.31818 /* Eh, is this right? */
112#define V2_MIN_PCF_FREQ  1
113#define V2_MAX_PCF_FREQ  3
114
115
116
117/*
118 * global data
119 */
120
121static struct width_to_stride_t {
122    vu32 width8bpp;
123    vu8 stride0;
124    vu8 stride1;
125    vu16 chip;
126} width_to_stride_table[]={
127/*  {    0, 0, 0, V1000_DEVICE }, */
128    {    4, 4, 0, V1000_DEVICE },
129    {   16, 0, 1, V1000_DEVICE },
130    {   20, 4, 1, V1000_DEVICE },
131    {   32, 0, 2, V1000_DEVICE },
132    {   36, 4, 2, V1000_DEVICE },
133    {   64, 0, 3, V1000_DEVICE },
134    {   68, 4, 3, V1000_DEVICE },
135    {  128, 0, 4, V1000_DEVICE },
136    {  132, 4, 4, V1000_DEVICE },
137    {  256, 1, 0, V1000_DEVICE },
138    {  272, 1, 1, V1000_DEVICE },
139    {  288, 1, 2, V1000_DEVICE },
140    {  320, 1, 3, V1000_DEVICE },
141    {  384, 1, 4, V1000_DEVICE },
142    {  512, 2, 0, V1000_DEVICE },
143    {  528, 2, 1, V1000_DEVICE },
144    {  544, 2, 2, V1000_DEVICE },
145    {  576, 2, 3, V1000_DEVICE },
146    {  592, 6, 1, V2000_DEVICE },
147    {  608, 6, 2, V2000_DEVICE },
148    {  640, 2, 4, V1000_DEVICE },
149    {  704, 6, 4, V2000_DEVICE },
150    {  768, 5, 0, V2000_DEVICE },
151    {  784, 5, 1, V2000_DEVICE },
152    {  800, 5, 2, V2000_DEVICE },
153    {  832, 5, 3, V2000_DEVICE },
154    {  896, 5, 4, V2000_DEVICE },
155    { 1024, 3, 0, V1000_DEVICE },
156    { 1028, 4, 5, V1000_DEVICE },
157    { 1040, 3, 1, V1000_DEVICE },
158    { 1056, 3, 2, V1000_DEVICE },
159    { 1088, 3, 3, V1000_DEVICE },
160    { 1152, 3, 4, V1000_DEVICE },
161    { 1168, 7, 1, V2000_DEVICE },
162    { 1184, 7, 2, V2000_DEVICE },
163    { 1216, 7, 3, V2000_DEVICE },
164    { 1280, 1, 5, V1000_DEVICE },
165    { 1536, 2, 5, V1000_DEVICE },
166    { 1600, 6, 5, V2000_DEVICE },
167    { 1792, 5, 5, V2000_DEVICE },
168    { 2048, 0, 6, V1000_DEVICE },
169    { 2052, 4, 6, V1000_DEVICE },
170    { 2176, 7, 5, V2000_DEVICE },
171    { 2304, 1, 6, V1000_DEVICE },
172    { 2560, 2, 6, V1000_DEVICE },
173    { 2624, 6, 6, V2000_DEVICE },
174    { 2816, 5, 6, V2000_DEVICE },
175    { 3072, 3, 6, V1000_DEVICE },
176    { 3200, 7, 6, V2000_DEVICE },
177    { 4096, 0, 7, V1000_DEVICE },
178    { 4100, 4, 7, V1000_DEVICE },
179    { 4352, 1, 7, V1000_DEVICE },
180    { 4608, 2, 7, V1000_DEVICE },
181    { 4672, 6, 7, V2000_DEVICE },
182    { 4864, 5, 7, V2000_DEVICE },
183    { 5120, 3, 7, V1000_DEVICE },
184    { 5248, 7, 7, V2000_DEVICE },
185    {    0, 0, 0, 0 }
186};
187
188struct V1000ClocksStr {
189    int h_size;
190    int pll_val;
191} V1000Clocks [] = {
192    { 72, 0x40000 }, /* For Textmode */
193    { 640, 0x2408 },   /*  31500  MHz */
194    { 800, 0x1583D },  /*  40000  MHz */
195    { 1024, 0x14823 }, /*  65000  MHz */
196    { 1280, 0x14414 }, /*  108000 MHz */
197    { 0, 0 }
198};
199
200/*
201 * local function prototypes
202 */
203
204static void set_PLL(IOADDRESS iob, vu32 value);
205static double V1000CalcClock(double target, int *M, int *N, int *P);
206static double V2200CalcClock(double target, int *m, int *n, int *p);
207
208
209
210/*
211 * functions
212 */
213
214int
215verite_setmode(ScrnInfoPtr pScreenInfo, struct verite_modeinfo_t *mode)
216{
217    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
218
219    int tmp;
220    int doubleclock=0;
221    int M, N, P;
222    int iob=pRendition->board.io_base;
223
224#ifdef DEBUG
225    ErrorF ("Rendition: Debug verite_setmode called\n");
226#endif
227
228    /* switching to native mode */
229    verite_out8(iob+MODEREG, NATIVE_MODE|VESA_MODE);
230
231    /* flipping some bytes */
232    /* Must be something better to do than this -- FIX */
233    switch (mode->bitsperpixel) {
234    case 32:
235      verite_out8(iob+MEMENDIAN, MEMENDIAN_NO);
236      break;
237    case 16:
238      verite_out8(iob+MEMENDIAN, MEMENDIAN_HW);
239      break;
240    case 8:
241      verite_out8(iob+MEMENDIAN, MEMENDIAN_END);
242      break;
243    }
244
245    if (pRendition->board.chip != V1000_DEVICE) {
246      if(!pRendition->board.overclock_mem){
247	verite_out32(iob+SCLKPLL, 0xa484d);  /* mclk=110 sclk=50 */
248                                        /* M/N/P/P = 77/5/2/4 */
249      }
250      else{
251	xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG,
252		   (" *** OVERCLOCKING MEM/CLK mclk=125 sclk=60 ***\n"));
253	/* increase Mem/Sys clock on request */
254	verite_out32(iob+SCLKPLL, 0xa4854);  /* mclk=125 sclk=60 */
255                                        /* M/N/P/P = 84/5/2/4 */
256      }
257      usleep(500);
258    }
259
260    /* this has something to do with memory */
261    tmp=verite_in32(iob+DRAMCTL)&0xdfff;              /* reset bit 13 */
262    verite_out32(iob+DRAMCTL, tmp|0x330000);
263
264    /* program pixel clock */
265    if (pRendition->board.chip == V1000_DEVICE) {
266        if (110.0 < V1000CalcClock(mode->clock/1000.0, &M, &N, &P)) {
267            P++;
268            doubleclock=1;
269        }
270        set_PLL(iob, combineNMP(N, M, P));
271    }
272    else {
273	tmp = (~0x1800) & verite_in32(iob+DRAMCTL);
274        verite_out32(iob+DRAMCTL, tmp);
275        V2200CalcClock(mode->clock/1000.0, &M, &N, &P);
276        verite_out32(iob+PCLKPLL, v2kcombineNMP(N, M, P));
277    }
278    usleep(500);
279
280    /* init the ramdac */
281    verite_initdac(pScreenInfo, mode->bitsperpixel, doubleclock);
282
283    verite_out32(iob+CRTCHORZ, HORZ(mode->hsyncstart - mode->hdisplay,
284                               mode->hsyncend - mode->hsyncstart,
285                               mode->htotal - mode->hsyncend,
286                               mode->hdisplay));
287    verite_out32(iob+CRTCVERT, VERT(mode->vsyncstart-mode->vdisplay,
288                               mode->vsyncend-mode->vsyncstart,
289                               mode->vtotal-mode->vsyncend,
290                               mode->vdisplay));
291
292    /* fill in the mode parameters */
293    memcpy(&(pRendition->board.mode), mode, sizeof(struct verite_modeinfo_t));
294    pRendition->board.mode.fifosize=128;
295    pRendition->board.mode.pll_m=M;
296    pRendition->board.mode.pll_n=N;
297    pRendition->board.mode.pll_p=P;
298    pRendition->board.mode.doubleclock=doubleclock;
299    if (0 == pRendition->board.mode.virtualwidth)
300        pRendition->board.mode.virtualwidth=pRendition->board.mode.screenwidth;
301
302    pRendition->board.init=1;
303    (*pScreenInfo->AdjustFrame)(pScreenInfo->scrnIndex,
304        pScreenInfo->frameX0, pScreenInfo->frameY0, 0);
305
306    /* Need to fix up syncs */
307
308    /* enable the display */
309    verite_out32(iob+CRTCCTL, CTL(0, mode->hsynchi, mode->vsynchi)
310                        |mode->pixelformat
311                        |CRTCCTL_VIDEOFIFOSIZE128
312                        |CRTCCTL_HSYNCENABLE
313                        |CRTCCTL_VSYNCENABLE
314                        |CRTCCTL_VIDEOENABLE);
315
316#ifdef DEBUG
317    ErrorF ("Interlace mode -> %d\n", mode->flags);
318    xf86sleep(10);ErrorF ("...Exit SetMode...\n");
319#endif
320
321   return 0;
322}
323
324static double
325verite_findtextclock(int width)
326{
327    int i = 0, val;
328    while ((val = V1000Clocks[i].h_size) > 0) {
329	if (val > width)
330	    break;
331	else
332	    i++;
333    }
334    if (i > 0) i--;
335    return V1000Clocks[i].pll_val;
336}
337
338void
339verite_save(ScrnInfoPtr pScreenInfo)
340{
341    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
342    int iob=pRendition->board.io_base;
343    RenditionRegPtr reg = &pRendition->saveRegs;
344
345    reg->memendian = verite_in8(iob+MEMENDIAN);
346    reg->mode = verite_in8(iob+MODEREG);
347    reg->sclkpll = verite_in32(iob+SCLKPLL);
348    reg->dramctl = verite_in32(iob+DRAMCTL);
349    reg->crtch = verite_in32(iob+CRTCHORZ);
350    reg->crtcv = verite_in32(iob+CRTCVERT);
351    /* clock */
352    if (V1000_DEVICE ==pRendition->board.chip) {
353	int width;
354	/*
355	 * I have no idea how to read back the clock from
356	 * V1000. Therefore we pick a VESA Mode clock from
357	 * a list for the width found.
358	 */
359	width = ((reg->crtch & 0xff) + 1) << 3;
360        reg->pclkpll = verite_findtextclock(width);
361	reg->plldev= verite_in8(iob+PLLDEV);
362    } else {
363	reg->pclkpll = verite_in32(iob+PCLKPLL);
364    }
365    /* initdac */
366    verite_out8(iob+MODEREG,NATIVE_MODE);
367    verite_savedac(pScreenInfo);
368    verite_out8(iob+MODEREG,reg->mode);
369
370    reg->vbasea = verite_in32(iob+FRAMEBASEA);
371    reg->crtcoff = verite_in32(iob+CRTCOFFSET);
372    reg->crtcctl = verite_in32(iob+CRTCCTL);
373}
374
375void
376verite_restore(ScrnInfoPtr pScreenInfo, RenditionRegPtr reg)
377{
378    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
379    int iob=pRendition->board.io_base;
380
381    verite_restoredac (pScreenInfo, reg);
382    /*
383     * If this is a Verite 1000, restore the MODEREG
384     * register now.  The MODEREG gets restored later
385     * for the Verite 2x00 because restoring it here
386     * has been confirmed to cause intermittent
387     * system locks.
388     */
389    if (pRendition->board.chip == V1000_DEVICE) {
390	verite_out32(iob+MODEREG,reg->mode);
391    }
392    verite_out8(iob+MEMENDIAN,reg->memendian);
393    verite_out32(iob+DRAMCTL,reg->dramctl);
394    verite_out32(iob+SCLKPLL,reg->sclkpll);
395    if (pRendition->board.chip == V1000_DEVICE) {
396	/* fixme */
397        set_PLL(iob, reg->pclkpll);
398	usleep(10000);
399    } else {
400	verite_out32(iob+PCLKPLL,reg->pclkpll);
401	/*
402	 * Need to wait 200uS for PLL to stabilize --
403	 * let's play it safe with 500
404	 */
405	usleep(10000);
406	/* wait until VBLANK */
407	while ((verite_in32(iob+CRTCSTATUS)&CRTCSTATUS_VERT_MASK) !=
408	       CRTCSTATUS_VERT_ACTIVE);
409	while ((verite_in32(iob+CRTCSTATUS)&CRTCSTATUS_VERT_MASK) ==
410	       CRTCSTATUS_VERT_ACTIVE);
411    }
412
413    /*
414     * If this is a Verite 2x00, restore the MODEREG
415     * register now.  The MODEREG register is restored
416     * earlier for the Verite 1000, but is restored
417     * here for the Verite 2x00 to prevent system
418     * locks.
419     */
420    if (pRendition->board.chip != V1000_DEVICE) {
421	verite_out32(iob+MODEREG,reg->mode);
422    }
423
424    verite_out32(iob+CRTCHORZ,reg->crtch);
425    verite_out32(iob+CRTCVERT,reg->crtcv);
426    verite_out32(iob+FRAMEBASEA, reg->vbasea);
427    verite_out32(iob+CRTCOFFSET,reg->crtcoff);
428    verite_out32(iob+CRTCCTL,reg->crtcctl);
429}
430
431void
432verite_setframebase(ScrnInfoPtr pScreenInfo, vu32 framebase)
433{
434    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
435
436    vu32 offset;
437
438    int iob=pRendition->board.io_base;
439    int swidth=pRendition->board.mode.screenwidth;
440    int vwidth=  pRendition->board.mode.virtualwidth;
441    int bytespp=pRendition->board.mode.bitsperpixel>>3;
442    int fifo_size=pRendition->board.mode.fifosize;
443
444#ifdef DEBUG
445    ErrorF( "Rendition: Debug verite_setframebase w=%d v=%d b=%d f=%d\n",
446        swidth, vwidth, bytespp, fifo_size);
447#endif
448
449    /* CRTCOFFSET */
450    offset=vwidth*bytespp               /* virtual width in bytes */
451          -swidth*bytespp               /* screen width in bytes */
452          +((swidth*bytespp)%fifo_size) /* width in bytes modulo fifo size */
453        ;
454
455    if (!(   framebase&7            /* framebase multiple of 8? */
456          || (swidth*bytespp)%128)) /* screenwidth multiple of fifo size */
457      offset+=fifo_size;            /* increment offset by fifosize */
458
459    /* wait for vertical retrace */
460#ifndef DEBUG
461    if (!pRendition->board.init) {
462        while ((verite_in32(iob+CRTCSTATUS) & CRTCSTATUS_VERT_MASK) !=
463               CRTCSTATUS_VERT_ACTIVE) ;
464        while ((verite_in32(iob+CRTCSTATUS) & CRTCSTATUS_VERT_MASK) ==
465               CRTCSTATUS_VERT_ACTIVE) ;
466    }
467    else
468        pRendition->board.init=0;
469#endif
470
471    /* framebase */
472    verite_out32(iob+FRAMEBASEA, framebase);
473
474    /* crtc offset */
475    verite_out32(iob+CRTCOFFSET, offset&0xffff);
476}
477
478int
479verite_getstride(ScrnInfoPtr pScreenInfo, int *width,
480		 vu16 *stride0, vu16 *stride1)
481{
482    renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
483    int bytesperline;
484    int c = 0;
485
486    bytesperline
487	= pRendition->board.mode.virtualwidth
488	* (pRendition->board.mode.bitsperpixel >> 3);
489#ifdef DEBUG
490    ErrorF("RENDITION: %d bytes per line\n", bytesperline);
491#endif
492
493    /* for now, I implemented a linear search only, should be fixed <ml> */
494    while (0 != width_to_stride_table[c].width8bpp) {
495	if (width_to_stride_table[c].width8bpp == bytesperline
496	    && ((width_to_stride_table[c].chip == pRendition->board.chip)
497		|| (V2000_DEVICE == pRendition->board.chip))) {
498            *stride0 = width_to_stride_table[c].stride0;
499            *stride1 = width_to_stride_table[c].stride1;
500            return 1;
501        }
502        c++;
503    }
504    return 0;
505}
506
507/*
508 * local functions
509 */
510
511/*
512 * void set_PLL(IOADDRESS iob, vu32 value)
513 *
514 * Set PLL clock to desired frequency for the V1000.
515 */
516
517void
518set_PLL(IOADDRESS iob, vu32 value)
519{
520    vu32 ulD;
521    int b;
522
523    /* shift out the 20 serial bits */
524    for (b=19; b>=0; b--) {
525        ulD=(value>>b)&1;
526        verite_out8(iob+PLLDEV, (vu8)ulD);
527    }
528
529    /* read PLL device so the latch is filled with the previously
530     * written value */
531    (void)verite_in8(iob+PLLDEV);
532}
533
534
535
536/* Vxx00CalcClock -- finds PLL parameters to match target
537 *                   frequency (in megahertz)
538 *
539 *                   Brute force, but takes less than a tenth
540 *                   of a second and the function is only called
541 *                   O(1) times during program execution.
542 */
543static double
544V1000CalcClock(double target, int *M, int *N, int *P)
545{
546    double mindiff = 1e10;
547    double vco, pcf, diff, freq;
548    int mm, nn, pp;
549
550    for (pp=0; pp<4; pp++)
551        for (nn=1; nn<=129; nn++)
552            for (mm=1; mm<=129; mm++) {
553                vco=V1_REF_FREQ*2.0*mm/nn;
554                if ((vco<V1_MIN_VCO_FREQ) || (vco>V1_MAX_VCO_FREQ))
555                    continue;
556            	pcf = V1_REF_FREQ/nn;
557            	if ((pcf<V1_MIN_PCF_FREQ) || (pcf>V1_MAX_PCF_FREQ))
558                    continue;
559            	freq=vco/(1<<pp);
560            	diff=fabs(target-freq);
561            	if (diff < mindiff) {
562                    *M=mm;
563                    *N=nn;
564                    *P=pp;
565                    mindiff=diff;
566                }
567            }
568
569    vco=V1_REF_FREQ*2*(*M)/(*N);
570    pcf=V1_REF_FREQ/(*N);
571    freq=vco/(1<<(*P));
572
573#ifdef DEBUG
574    ErrorF(
575        "RENDITION: target=%f freq=%f vco=%f pcf=%f n=%d m=%d p=%d\n",
576        target, freq, vco, pcf, *N, *M, *P);
577#endif
578
579    return freq;
580}
581
582
583
584static double
585V2200CalcClock(double target, int *m, int *n, int *p)
586{
587    double mindiff = 1e10;
588    double vco, pcf, diff, freq;
589    int mm, nn, pp;
590
591    for (pp=1; pp<=0x0f; pp++)
592        for (nn=1; nn<=0x3f; nn++)
593            for (mm=1; mm<=0xff; mm++) {
594                vco = V2_REF_FREQ*mm/nn;
595                if ((vco < V2_MIN_VCO_FREQ) || (vco > V2_MAX_VCO_FREQ))
596                    continue;
597            	pcf = V2_REF_FREQ*mm/nn;
598                if ((vco < V2_MIN_VCO_FREQ) || (vco > V2_MAX_VCO_FREQ))
599                    continue;
600            	pcf = V2_REF_FREQ/nn;
601            	if ((pcf < V2_MIN_PCF_FREQ) || (pcf > V2_MAX_PCF_FREQ))
602                    continue;
603            	freq = vco/pp;
604            	diff = fabs(target-freq);
605            	if (diff < mindiff) {
606                    *m = mm; *n = nn; *p = pp;
607                    mindiff = diff;
608                }
609            }
610
611    vco = V2_REF_FREQ * *m / *n;
612    pcf = V2_REF_FREQ / *n;
613    freq = vco / *p;
614
615#ifdef DEBUG
616    ErrorF(
617        "RENDITION: target=%f freq=%f vco=%f pcf=%f n=%d m=%d p=%d\n",
618        target, freq, vco, pcf, *n, *m, *p);
619#endif
620
621    return freq;
622}
623
624
625/*
626 * end of file vmodes.c
627 */
628
629