edt_ss_vco.c

00001 /* #pragma ident "@(#)edt_ss_vco.c      1.7 05/30/07 EDT" */
00002 
00003 #include "edtinc.h"
00004 #include "edt_ss_vco.h"
00005 
00006 #include <assert.h>
00007 
00008 #include <math.h>
00009 /*********************************************************/
00010 
00011 /* Mapping in edt_pll ftom av9110 to ics307 */
00012 
00013 /* v = VCO Divider Word (VDW) range 4 - 511 */
00014 
00015 /* r = Reference Divider Word (RDW) range  1-127 */
00016 
00017 /* m = Output Divide (OD) values: 2 - 9, 10 */
00018 
00019 #define HIGH_VCO_307 400000000
00020 #define LOW_VCO_ics307 55000000
00021 #define MIN_RDW_FREQ    200000
00022 
00023 static int test_loops = 0;
00024 
00025 typedef struct _target_ics307
00026 {
00027     double  target;
00028     double  actual;
00029 
00030     edt_pll *pll;
00031 
00032 
00033     int     hits;
00034     int     finished;
00035 }       target_ics307;
00036 
00037 
00038 void
00039 print_ics307_parameters(double target, double actual, double reference, edt_pll * pll)
00040 
00041 {
00042 
00043     double  check;
00044 
00045 
00046     printf("ICS 307 computations for reference frequency %f\n", reference);
00047 
00048     printf("\nClosest frequency to target frequency %3.5f is %3.5f\n",
00049            target, actual);
00050     printf("Parameters VDW=%d, RDW=%d, OD=%d, LX=%d\n",
00051            pll->VDW, pll->RDW, pll->OD,pll->x);
00052 
00053     check = reference * (pll->VDW + 8) / ((pll->RDW + 2) * pll->OD * (pll->x+1));
00054 
00055         if (pll->l)
00056         {
00057 
00058         /* no final divide by 2 */
00059         check *= 2;
00060 
00061         printf("\n--- Note this requires a bitfile which supports no final divide by 2!!!  ---\n\n");
00062 
00063     printf("Computations:\nF  = Ref * 2 * (VDW+8) / ((RDW+2) * (OD) * (LX+1))\n");
00064 
00065     printf("%3.5f = %3.5f * 2 * (%d+8) / ((%d+2) * (%d) * (%d))\n",
00066       actual, reference, pll->VDW, pll->RDW, pll->OD, pll->x+1);
00067 
00068         }
00069         else
00070         {
00071 
00072     printf("Computations:\nF  = Ref * 2 * (VDW+8) / ((RDW+2) * (OD) * (LX+1) * 2)\n");
00073 
00074     printf("%3.5f = %3.5f * 2 * (%d+8) / ((%d+2) * (%d) * (%d) * 2)\n",
00075       actual, reference, pll->VDW, pll->RDW, pll->OD, pll->x+1);
00076 
00077 
00078         }
00079 
00080         printf("Check = %3.5f\n", check);
00081 
00082 }
00083 
00084 
00085 /*
00086  * foreach possible setting of the L (1 to 64) and X (1 to 256) dividers
00087  * check if the output frequency is closer to the target than the last
00088  * closest. Notice the last divide by 2 is fixed for clock symetry. note that
00089  * the F_LOW restriction only applies when either X or L is greater than 1.
00090  */
00091 
00092 static void
00093 div_out_ics307(int h, int vdw, int rdw, int od, double xtal, double av_out, 
00094                            target_ics307 * targ, 
00095                            int lastdivide)
00096 
00097 {
00098     int     val;
00099     double  oddclkout;
00100     double  serialclk;
00101     int     minx = 1;
00102     int     maxx = 64 * 256;
00103 
00104         int divider = lastdivide;
00105 
00106 
00107     oddclkout = av_out / h;
00108 
00109     /* target xl value */
00110 
00111         if (lastdivide)
00112         {
00113                 double  xl;
00114 
00115                 xl = oddclkout / (targ->target * lastdivide);
00116 
00117                 minx = (int) xl - 1;
00118                 if (minx < 1)
00119                 minx = 1;
00120                 maxx = (int) xl + 1;
00121 
00122                 if (maxx > 64 * 256)
00123                 maxx = 64 * 256;
00124 
00125         }
00126         else
00127         {
00128                 minx = maxx = 1;
00129                 divider = 1;
00130         }
00131 
00132     for (val = minx; val <= maxx; val++)
00133     {
00134 
00135         if (val == 1 || ((oddclkout <= F_SS_LOW)))
00136 
00137         {
00138             serialclk = oddclkout / (val * divider);
00139 
00140             if ((targ->hits == 0) ||
00141                 (fabs(targ->actual - targ->target) > fabs(serialclk - targ->target)))
00142             {
00143                 /* update the target structure */
00144                 targ->actual = serialclk;
00145                 targ->pll->VDW = vdw;
00146                 targ->pll->RDW = rdw;
00147                 targ->pll->OD = od;
00148                 targ->pll->h = h;
00149 
00150                 /* store x as a single 14 bit value */
00151 
00152                 targ->pll->x = val-1;
00153 
00154                 targ->hits++;
00155 
00156                 if (targ->actual == targ->target)
00157                     targ->finished = 1;
00158 
00159             }
00160         }
00161 
00162         test_loops++;
00163 
00164     }
00165 
00166 }
00167 
00168 /*
00169  * check all av9110 output frequencies for legality to enter the xilinx. If
00170  * ok call all possible high speed odd dividers
00171  */
00172 
00173 static void
00174 av_outputs_ics307(int vdw, int rdw, int od, double xtal, 
00175                                   double av_out, target_ics307 * targ, 
00176                                   int last_divide)
00177 
00178 {
00179     if ((av_out) <= F_XILINX_307)
00180     {
00181 
00182         /*
00183          * for all possible divsors of the high speed odd divider in the
00184          * xilinx
00185          */
00186 
00187         div_out_ics307(1, vdw, rdw, od, xtal, av_out, targ, last_divide);
00188 
00189     }
00190 }
00191 
00192 
00193 
00194 /*
00195  * do all n to find legal vco frequencies for given ref and v
00196  */
00197 static void
00198 all_vdw_ics307(int od, double xtal, double ref, target_ics307 * targ,
00199                int last_divide)
00200 
00201 {
00202     int     vdw = 4;
00203     int     rdw;
00204     double  vco;
00205     double  vref;
00206 
00207     double  workref;
00208 
00209     int     max_rdw = (int) (xtal / MIN_RDW_FREQ) - 2;
00210 
00211     vref = (vdw + 8) * xtal;
00212 
00213     while ((vdw < 511) && (2 * (vref / 128) <= HIGH_VCO_307))
00214     {
00215         vref = (vdw + 8) * xtal;
00216 
00217         /*
00218          * for each legal vco freq check all values of r
00219          */
00220         /*
00221          * -debug printf("vco = %3.5f (m=%d,  n=%d, v=%d)\n", vco, m, n, v);
00222          */
00223 
00224         workref = 2 * vref;
00225 
00226         for (rdw = 1; rdw < max_rdw; rdw++)
00227         {
00228 
00229             vco = workref / (double) (rdw + 2);
00230 
00231             if ((vco) >= LOW_VCO_ics307)
00232             {
00233                 if (vco <= HIGH_VCO_307)
00234                 {
00235                     vco /= od;
00236 
00237                     av_outputs_ics307(vdw, rdw, od, xtal, vco, targ, last_divide);
00238                 }
00239             }
00240             else
00241                 break;
00242 
00243             if (targ->finished)
00244                 return;
00245         }
00246 
00247 
00248         vdw++;
00249 
00250     }
00251 }
00252 
00253 /*
00254  * print all possible vco frequencies for the refernce frequency passed
00255  * (xtal/m).
00256  */
00257 
00258 static void
00259 calc_vco_freq_ics307(double xtal, target_ics307 * targ, int last_divide)
00260 
00261 {
00262     double  ref;
00263     int     od;
00264 
00265     /*
00266      * call n rates for v is 1 and 8
00267      */
00268 
00269         printf("\ncalc vco freq last_divide = %d\n", last_divide);
00270 
00271     for (od = 2; od <= 10; od++)
00272     {
00273         if (od != 9)
00274         {
00275 
00276             ref = xtal * 2 / od;
00277 
00278             all_vdw_ics307(od, xtal, ref, targ, last_divide);
00279 
00280             if (targ->finished)
00281                 return;
00282 
00283         }
00284     }
00285 
00286 }
00287 
00288 double
00289 edt_find_ss_vco_frequency(EdtDev * edt_p, double target,
00290                               double xtal, edt_pll * pll, int verbose, int nodivide)
00291 
00292 {
00293 
00294     target_ics307 targ;
00295 
00296     edt_pll dummypll;
00297 
00298     int     minm, maxm;
00299         int div_value;
00300 
00301 
00302 
00303     if (!pll)
00304         pll = &dummypll;
00305 
00306     edt_dtime();
00307 
00308 
00309     if (xtal == 0)
00310     {
00311         switch (edt_p->devid)
00312         {
00313         case PSS16_ID:
00314         case PSS4_ID:
00315         case PGS16_ID:
00316         case PGS4_ID:
00317                 xtal = XTAL_SS;
00318                 break;
00319 
00320         default:
00321             xtal = XTAL_SS;
00322             fprintf(stderr, "WARNING -- SS vco set requires ICS307 PLL and PCISSgot invalid device ID (%d) -- using %f...?\n", edt_p->devid, XTAL_SS);
00323 
00324             break;
00325 
00326         }
00327     }
00328 
00329 
00330     /*
00331      * if ( (minm = (int) (xtal/HI_REF)) < 3) minm = 3; if ( (maxm = (int)
00332      * (xtal/LOW_REF)) > 127) maxm = 127;
00333      */
00334 
00335     minm = 4;
00336     maxm = 511;
00337 
00338         memset(&targ, 0, sizeof(targ));
00339 
00340         targ.actual = 0;
00341     targ.hits = 0;              /* zero means no updates have been made */
00342     targ.finished = 0;
00343     targ.target = target;
00344         targ.actual = 0;
00345 
00346     targ.pll = pll;
00347 
00348         switch (nodivide)
00349         {
00350         case 0:
00351                 div_value = 2;
00352                 break;
00353         case 1:
00354                 div_value = 1;
00355                 break;
00356         case 2:
00357                 div_value = 0;
00358                 break;
00359         }
00360 
00361 
00362         targ.pll->l = nodivide;
00363 
00364     calc_vco_freq_ics307(xtal, &targ, div_value);
00365 
00366     if (verbose)
00367     {
00368                 print_ics307_parameters(targ.target, targ.actual, xtal, pll);
00369                 printf("Elapsed: %10.6f seconds\n", edt_dtime());
00370     }
00371     else
00372         printf("Closest frequency to target frequency %3.5f is %3.5f\n",
00373            targ.target, targ.actual);
00374 
00375     return targ.actual;
00376 
00377 }
00378 
00379 
00380 double
00381 edt_find_vco_frequency_ics307(EdtDev * edt_p, double target,
00382                                     double xtal, edt_pll * pll, int verbose)
00383 
00384 {
00385         return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,0);
00386 }
00387 
00388 double
00389 edt_find_vco_frequency_ics307_nodivide(EdtDev * edt_p, double target,
00390                                     double xtal, edt_pll * pll, int verbose)
00391 
00392 {
00393         return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,1);
00394 }
00395 
00396 double
00397 edt_find_vco_frequency_ics307_raw(EdtDev * edt_p, double target,
00398                                     double xtal, edt_pll * pll, int verbose)
00399 
00400 {
00401         return edt_find_ss_vco_frequency(edt_p,target,xtal, pll, verbose,2);
00402 }
00403 
00404 /*
00405  * set phase lock loop clock
00406  */
00407 double
00408 edt_set_frequency_ics307(EdtDev * edt_p,
00409                          double ref_xtal,
00410                          double target,
00411                          int clock_channel,
00412                          int finaldivide)
00413 {
00414     double  freq = 0;
00415 
00416 
00417     edt_pll clkset;
00418 
00419     freq = edt_find_ss_vco_frequency(edt_p, target, ref_xtal, &clkset,
00420                                          FALSE, finaldivide);
00421 
00422     if (freq  > 0) 
00423                 edt_set_out_clk_ics307(edt_p, &clkset, clock_channel);
00424 
00425     return freq;
00426 
00427 }
00428 
00429 /*
00430  * set phase lock loop clock
00431  */
00432 double
00433 edt_set_frequency_fcipcd(EdtDev * edt_p,
00434                          double target)
00435 {
00436     double  freq = 0;
00437         int clock_channel = 0;
00438     edt_pll clkset;
00439         double ref_xtal = XTAL_SS;
00440 
00441     freq = edt_find_ss_vco_frequency(edt_p, target, ref_xtal, &clkset,
00442                                          FALSE, 2);
00443 
00444     if (freq  > 0) 
00445                 edt_set_out_clk_ics307(edt_p, &clkset, clock_channel);
00446 
00447     return freq;
00448 
00449 }
00450 
00451 /*
00452  * assume the ICS307 is already selected assume the ICS307 clock is low and
00453  * leave it low output the number of bits specified from the lsb until done
00454  */
00455 static void
00456 shift_ics307(EdtDev * edt_p, u_int data, u_int numbits)
00457 {
00458     /*
00459      * printf("shift %d bits from bit8 of %08x\n", numbits, data);
00460      */
00461     while (numbits)
00462     {
00463 
00464 
00465         if ((data >> (numbits - 1)) & 0x01)
00466         {
00467             edt_reg_or(edt_p, EDT_SS_PLL_CTL, EDT_SS_PLL_DATA);
00468             /*
00469              * printf("one ");
00470              */
00471         }
00472         else
00473         {
00474             edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~EDT_SS_PLL_DATA);
00475             /*
00476              * printf("zero ");
00477              */
00478         }
00479 
00480         /* clock it in */
00481         edt_reg_or(edt_p, EDT_SS_PLL_CTL, EDT_SS_PLL_CLK);
00482         edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~EDT_SS_PLL_CLK);
00483 
00484         numbits--;
00485     }
00486     /*
00487      * printf("\n");
00488      */
00489 }
00490 
00491 
00492 /*
00493  * Array of values used as S2-S0 on ics307 ; index using OD value from
00494  * edt_pll structure
00495  */
00496 
00497 static int SFromCLK1[11] = {-1, -1, 1, 6, 3, 4, 7, 5, 2, -1, 0};
00498 
00499 /*
00500  * first 5 bits clocked in to ics307 c1 = 0 c0 = 0 TTL = 1 F1 = 1 F0 = 0
00501  */
00502 
00503 #define ICS307_CAP_TTL_CLK2 0x06
00504 
00505 
00506 void
00507 edt_set_out_clk_ics307(EdtDev * edt_p, edt_pll * clk_data, int clock_channel)
00508 {
00509     unsigned short opt_e = 0;
00510 
00511     u_int   out_scale;
00512     u_int   ref_scale;
00513 
00514     u_int   clk1_divide;
00515 
00516     u_int   strobe_bit;
00517 
00518         /* note that 0xffff is reserved for no final 
00519            divide by 2 */
00520 
00521         if (clk_data->l != 2)
00522         {
00523 
00524                 if (clk_data->l)
00525                         opt_e = 0xffff;
00526                 else
00527                         opt_e = (clk_data->x) << EDT_X_DIVN_SHFT;
00528 
00529                 switch (clock_channel)
00530                 {
00531                 case 0:
00532                 out_scale = EDT_SS_PLL0_CLK;
00533                 ref_scale = EDT_SS_PLL0_X;
00534                 break;
00535 
00536                 case 1:
00537                 out_scale = EDT_SS_PLL1_CLK;
00538                 ref_scale = EDT_SS_PLL1_X;
00539                 break;
00540                 case 2:
00541                 out_scale = EDT_SS_PLL2_CLK;
00542                 ref_scale = EDT_SS_PLL2_X;
00543                 break;
00544                 case 3:
00545                 out_scale = EDT_SS_PLL3_CLK;
00546                 ref_scale = EDT_SS_PLL3_X;
00547                 break;
00548                 default:
00549                 assert(0);
00550                 }
00551 
00552                 edt_reg_write(edt_p, out_scale, opt_e & 0xff);
00553                 edt_reg_write(edt_p, ref_scale, opt_e >> 8);
00554 
00555         }
00556     /* shift out data */
00557 
00558     /* fisrt 5 bits alwasy the same */
00559 
00560 
00561     shift_ics307(edt_p, ICS307_CAP_TTL_CLK2, 5);
00562 
00563     clk1_divide = SFromCLK1[clk_data->OD];
00564 
00565     shift_ics307(edt_p, clk1_divide, 3);
00566 
00567     shift_ics307(edt_p, clk_data->VDW, 9);
00568     shift_ics307(edt_p, clk_data->RDW, 7); 
00569 
00570         printf("Programming value %x\n",
00571                 (5 << 19) | (clk1_divide<< 16) | (clk_data->VDW << 7) | (clk_data->RDW));
00572 
00573     switch (clock_channel)
00574     {
00575     case 0:
00576         strobe_bit = EDT_SS_PLL_STROBE0;
00577         break;
00578     case 1:
00579         strobe_bit = EDT_SS_PLL_STROBE1;
00580         break;
00581     case 2:
00582         strobe_bit = EDT_SS_PLL_STROBE2;
00583         break;
00584     case 3:
00585         strobe_bit = EDT_SS_PLL_STROBE3;
00586         break;
00587     default:
00588         assert(0);
00589     }
00590     edt_reg_or(edt_p, EDT_SS_PLL_CTL, strobe_bit);
00591     edt_reg_and(edt_p, EDT_SS_PLL_CTL, ~strobe_bit);
00592 
00593 }
00594 

Generated on 19 Jun 2015 by  doxygen 1.4.7