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

Generated on 19 Jun 2015 by  doxygen 1.4.7