edt_vco.c

00001 /* #pragma ident "@(#)edt_vco.c 1.11 11/13/00 EDT" */
00002 
00003 /*
00004  * edt_vco.c
00005  * 
00006  * library routine to find settings for VCO frequencies for the AV9110 as used
00007  * on the PCI CD20/40/60.
00008  */
00009 
00010 #include <math.h>
00011 #include "edtinc.h"
00012 
00013 #include "edt_vco.h"
00014 #include <assert.h>
00015 
00016 static int loops = 0;
00017 
00018 struct target
00019 {
00020     double  target;
00021     double  actual;
00022 
00023     edt_pll *pll;
00024 
00025 
00026     int     hits;
00027     int     finished;
00028 };
00029 
00030 #define freq_calc(n,m,v,r,h,l,x,xtal) ((n * v * xtal) / (m * r * h * l * x * 2))
00031 
00032 
00033 /* all possible factorings */
00034 
00035 static int factors[64 * 256 + 1];
00036 
00037 static int factorsfilled = 0;
00038 
00039 static void 
00040 fill_factors()
00041 
00042 {
00043     int     l;
00044     int     x;
00045     int     product;
00046     int     lshift;
00047 
00048     /* store factors as l << 16 + x */
00049 
00050     memset(&factors[0], 0, sizeof(factors));
00051 
00052     for (l = 1; l <= 64; l++)
00053     {
00054         product = l;
00055         lshift = (l << 16);
00056 
00057         for (x = 1; x <= 256; x++)
00058         {
00059 
00060             factors[product] = lshift | x;
00061 
00062             product += l;
00063         }
00064     }
00065 
00066     factorsfilled = 1;
00067 }
00068 
00069 
00070 /*
00071  * foreach possible setting of the L (1 to 64) and X (1 to 256) dividers
00072  * check if the output frequency is closer to the target than the last
00073  * closest. Notice the last divide by 2 is fixed for clock symetry. note that
00074  * the F_LOW restriction only applies when either X or L is greater than 1.
00075  */
00076 
00077 static void
00078 div_out(h, r, n, v, m, xtal, vco, ref, av_out, targ)
00079     int     h, r, n, v, m;
00080     double  xtal, vco, ref, av_out;
00081     struct target *targ;
00082 {
00083     int     val;
00084     double  oddclkout;
00085     double  serialclk;
00086     double  xl;
00087     int     minx = 1;
00088     int     maxx = 64 * 256;
00089 
00090 
00091 
00092     oddclkout = av_out / h;
00093 
00094     /* target xl value */
00095 
00096     xl = oddclkout / (targ->target * 2);
00097 
00098     minx = (int) xl - 1;
00099     if (minx < 1)
00100         minx = 1;
00101     maxx = (int) xl + 1;
00102 
00103     if (maxx > 64 * 256)
00104         maxx = 64 * 256;
00105 
00106     for (val = minx; val <= maxx; val++)
00107     {
00108 
00109         if (val == 1 || ((oddclkout <= F_LOW) && factors[val]))
00110 
00111         {
00112             serialclk = oddclkout / (val * 2);
00113 
00114             /*
00115              * -debug printf("vco = %3.5f av9110 out = %3.5f, odd divide out
00116              * = %3.5f\n", vco, av_out, oddclkout); printf("serial clk =
00117              * %3.5f (m=%d,  n=%d, v=%d, r=%d, h=%d, l=%d, x=%d)\n" ,
00118              * serialclk, m, n, v, r, h, l, x);
00119              */
00120             if ((targ->hits == 0) ||
00121                 (fabs(targ->actual - targ->target) > fabs(serialclk - targ->target)))
00122             {
00123                 /* update the target structure */
00124                 targ->actual = serialclk;
00125                 targ->pll->m = m;
00126                 targ->pll->n = n;
00127                 targ->pll->v = v;
00128                 targ->pll->r = r;
00129                 targ->pll->h = h;
00130 
00131                 targ->pll->l = (factors[val] >> 16);
00132                 targ->pll->x = (factors[val] & 0xffff);
00133 
00134                 targ->hits++;
00135 
00136                 if (targ->actual == targ->target)
00137                     targ->finished = 1;
00138 
00139 #if 0
00140                 printf("vco = %3.5f av9110 out = %3.5f, odd divide out = %3.5f\n",
00141                        vco, av_out, oddclkout);
00142                 printf("serial clk = %3.5f val = %d (%d,  n=%d, v=%d, r=%d, h=%d, l=%d, x=%d)\n"
00143                 ,serialclk, val, m, n, v, r, h, targ->pll->l, targ->pll->x);
00144 #endif
00145 
00146             }
00147         }
00148 
00149         loops++;
00150 
00151     }
00152 
00153 }
00154 
00155 /*
00156  * check all av9110 output frequencies for legality to enter the xilinx. If
00157  * ok call all possible high speed odd dividers
00158  */
00159 
00160 static void
00161 av_outputs(r, n, v, m, xtal, vco, ref, targ)
00162     int     r, n, v, m;
00163     double  xtal, vco, ref;
00164     struct target *targ;
00165 {
00166     double  av_out = vco / r;
00167 
00168     if ((av_out) <= F_XILINX)
00169     {
00170 
00171         /*
00172          * for all possible divsors of the high speed odd divider in the
00173          * xilinx
00174          */
00175 
00176         div_out(1, r, n, v, m, xtal, vco, ref, av_out, targ);
00177         if (targ->finished)
00178             return;
00179 
00180         div_out(3, r, n, v, m, xtal, vco, ref, av_out, targ);
00181         if (targ->finished)
00182             return;
00183 
00184         div_out(5, r, n, v, m, xtal, vco, ref, av_out, targ);
00185         if (targ->finished)
00186             return;
00187 
00188         div_out(7, r, n, v, m, xtal, vco, ref, av_out, targ);
00189     }
00190 }
00191 
00192 
00193 /*
00194  * do all n to find legal vco frequencies for given ref and v
00195  */
00196 static void
00197 all_n(v, m, xtal, ref, targ)
00198     int     v, m;
00199     double  xtal, ref;
00200     struct target *targ;
00201 {
00202     int     n = 3;
00203     double  vco;
00204     double  vref = v * ref;
00205 
00206 
00207     vco = vref * 3;
00208     while ((n < 128) && ((vco) <= HI_VCO))
00209     {
00210         if ((vco) >= LOW_VCO)
00211         {
00212             /*
00213              * for each legal vco freq check all values of r
00214              */
00215             /*
00216              * -debug printf("vco = %3.5f (m=%d,  n=%d, v=%d)\n", vco, m, n,
00217              * v);
00218              */
00219 
00220 
00221             av_outputs(1, n, v, m, xtal, vco, ref, targ);
00222             if (targ->finished)
00223                 return;
00224             av_outputs(2, n, v, m, xtal, vco, ref, targ);
00225             if (targ->finished)
00226                 return;
00227             av_outputs(4, n, v, m, xtal, vco, ref, targ);
00228             if (targ->finished)
00229                 return;
00230             /* canceled out if v == 8 */
00231             /* same as v == 1, r == 1 */
00232             if (v != 8)
00233                 av_outputs(8, n, v, m, xtal, vco, ref, targ);
00234             if (targ->finished)
00235                 return;
00236         }
00237         n++;
00238         vco += vref;
00239     }
00240 }
00241 
00242 /*
00243  * print all possible vco frequencies for the refernce frequency passed
00244  * (xtal/m).
00245  */
00246 
00247 static void
00248 vcofreq(m, xtal, targ)
00249     int     m;
00250     double  xtal;
00251     struct target *targ;
00252 {
00253     double  ref;
00254 
00255     /*
00256      * call n rates for v is 1 and 8
00257      */
00258     ref = xtal / m;
00259     all_n(1, m, xtal, ref, targ);
00260     if (targ->finished)
00261         return;
00262     all_n(8, m, xtal, ref, targ);
00263 }
00264 
00265 double
00266 edt_find_vco_frequency(EdtDev * edt_p, double target,
00267                        double xtal, edt_pll * pll, int verbose)
00268 
00269 {
00270 
00271     struct target targ;
00272     edt_pll dummypll;
00273 
00274     int     m, minm, maxm;
00275 
00276 
00277     if (!pll)
00278         pll = &dummypll;
00279 
00280     edt_dtime();
00281 
00282     if (!factorsfilled)
00283     {
00284         fill_factors();
00285         factorsfilled = 1;
00286     }
00287 
00288     if (xtal == 0)
00289     {
00290         switch (edt_p->devid)
00291         {
00292         case PCD20_ID:
00293             xtal = XTAL20;
00294             break;
00295         case PDV_ID:            /* probably never do output from dv (and family) */
00296         case PDVK_ID:           /* but sticking in here just in case */
00297         case PDV44_ID:
00298         case PDVFOI_ID:
00299         case PCD40_ID:
00300             xtal = XTAL40;
00301             break;
00302         case PCD60_ID:
00303         case PGP_ECL_ID:
00304         case PCD_16_ID:
00305         case PSS16_ID:
00306             xtal = XTAL60;
00307             break;
00308         default:
00309             xtal = XTAL20;
00310             fprintf(stderr, "WARNING -- vco set got invalid device ID (%d) -- using 20...?\n", edt_p->devid);
00311 
00312             break;
00313 
00314         }
00315     }
00316 
00317     if ((minm = (int) (xtal / HI_REF)) < 3)
00318         minm = 3;
00319     if ((maxm = (int) (xtal / LOW_REF)) > 127)
00320         maxm = 127;
00321 
00322     targ.hits = 0;              /* zero means no updates have been made */
00323     targ.finished = 0;
00324     targ.target = target;
00325 
00326     targ.pll = pll;
00327 
00328     for (m = minm; m <= maxm; m++)
00329     {
00330 
00331         vcofreq(m, xtal, &targ);
00332 
00333         if (targ.finished)
00334             break;
00335     }
00336 
00337     if (verbose)
00338     {
00339         printf("\nClosest frequency to target frequency %3.5f is %3.5f\n",
00340                targ.target, targ.actual);
00341         printf("N=%d, M=%d, V=%d, R=%d, H=%d, L=%d, X=%d, updates=%d loops = %d\n",
00342                pll->n, pll->m, pll->v, pll->r, pll->h, pll->l, pll->x,
00343                targ.hits, loops);
00344         printf("Elapsed: %10.6f seconds\n", edt_dtime());
00345     }
00346 
00347     return targ.actual;
00348 
00349 }
00350 
00351 /*
00352  * set phase lock loop clock
00353  */
00354 void
00355 edt_set_pll_clock(EdtDev * edt_p, int ref_xtal, edt_pll * clkset, int verbose)
00356 {
00357     double  freq = 0;
00358     double  vco = 0;
00359 
00360     /* set output clock */
00361     if (verbose)
00362     {
00363         printf("setting pll clock\n");
00364         printf("clock parameters - \n");
00365         printf("\tAV9110 refernce divide(-M) = %d\n", clkset->m);
00366         printf("\tAV9110 VCO feedback divide(-N) = %d\n", clkset->n);
00367         printf("\tAV9110 VCO feedback prescale divide(-V) = %d\n", clkset->v);
00368         printf("\tAV9110 VCO output  divide(-R) = %d\n", clkset->r);
00369         printf("\tXilinx low speed divide(-L)  = %d\n", clkset->l);
00370         printf("\tXilinx odd divide(-H) = %d\n", clkset->h);
00371         printf("\tXilinx tclk prescaler(-X) = %d\n", clkset->x);
00372     }
00373     vco = (ref_xtal * clkset->v * clkset->n) / (clkset->m);
00374     if (vco < 45e+06 || vco > 250e+06)
00375         printf("edt_set_pll_clock: VCO FREQUENCY OUT OF RANGE at %g Hz\n", vco);
00376     else if (verbose)
00377         printf("VCO Frequency at %g Hz\n", vco);
00378     freq = vco / (2 * clkset->r * clkset->x * clkset->h * clkset->l);
00379     if (verbose)
00380         printf("setting write unit output clock %g Hertz\n", freq);
00381     edt_set_out_clk(edt_p, clkset);
00382     edt_set_funct_bit(edt_p, EDT_FUNCT_PLLCLK);
00383 }
00384 

Generated on Mon May 12 16:38:52 2008 by  doxygen 1.5.1