home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / XFREE / common_hw / S3gendac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-29  |  6.2 KB  |  303 lines

  1. /* $XFree86: xc/programs/Xserver/hw/xfree86/common_hw/S3gendac.c,v 3.7 1995/07/01 10:49:02 dawes Exp $ */
  2. /*
  3.  * Progaming of the S3 gendac programable clocks, from the S3 Gendac
  4.  * programing documentation by S3 Inc. 
  5.  * Jon Tombs <jon@esix2.us.es>
  6.  */
  7.  
  8. #include "S3gendac.h" 
  9. #include "compiler.h"
  10. #define NO_OSLIB_PROTOTYPES
  11. #include "xf86_OSlib.h"
  12. #include <math.h>
  13.  
  14.  
  15. #define PLL_S3GENDAC      1
  16. #define PLL_S3TRIO        2
  17. #define PLL_ET4000GENDAC  8
  18.  
  19.  
  20. extern int vgaIOBase;
  21.  
  22. static void setS3gendacpll(
  23. #if NeedFunctionPrototypes
  24. int reg, unsigned char data1, unsigned char data2
  25. #endif
  26. );
  27.  
  28. static void settriopll(
  29. #if NeedFunctionPrototypes
  30. int reg, unsigned char data1, unsigned char data2
  31. #endif
  32. );
  33.  
  34. static void setET4000gendacpll(
  35. #if NeedFunctionPrototypes
  36. int reg, unsigned char data1, unsigned char data2
  37. #endif
  38. );
  39.  
  40.  
  41. static int commonSetClock( 
  42. #if NeedFunctionPrototypes
  43.    long freq, int clock,
  44.    int min_n2, int pll_type,
  45.    long freq_min, long freq_max
  46. #endif
  47. );     
  48.  
  49. int
  50. S3gendacSetClock(freq, clk)
  51. long freq;
  52. int clk;
  53. {
  54.    return commonSetClock(freq, clk, 0, PLL_S3GENDAC, 100000, 250000);
  55. }
  56.  
  57. int
  58. ET4000gendacSetClock(freq, clk)
  59. long freq;
  60. int clk;
  61. {
  62.    return commonSetClock(freq, clk, 0, PLL_ET4000GENDAC, 100000, 270000);
  63. }
  64.  
  65. int
  66. ET4000gendacSetpixmuxClock(freq, clk)
  67. long freq;
  68. int clk;
  69. {
  70.    return commonSetClock(freq, clk, 2, PLL_ET4000GENDAC, 100000, 270000);
  71. }
  72.  
  73. int
  74. ICS5342SetClock(freq, clk)
  75. long freq;
  76. int clk;
  77. {
  78.    return commonSetClock(freq, clk, 1, PLL_S3GENDAC, 100000, 250000);
  79. }
  80.  
  81. int
  82. S3TrioSetClock(freq, clk)
  83. long freq;
  84. int clk;
  85. {
  86.    return commonSetClock(freq, clk, 0, PLL_S3TRIO, 135000, 270000);
  87. }
  88.  
  89. void
  90. commonCalcClock(freq, min_n2, freq_min, freq_max, mdiv, ndiv)
  91. long freq;
  92. int min_n2;
  93. long freq_min, freq_max;
  94. unsigned char *mdiv, *ndiv;
  95. {
  96.    double ffreq, ffreq_min, ffreq_max;
  97.    double div, diff, best_diff;
  98.    unsigned int m;
  99.    unsigned char n1, n2;
  100.    unsigned char best_n1=16+2, best_n2=2, best_m=125+2;
  101.  
  102.    ffreq     = freq     / 1000.0 / BASE_FREQ;
  103.    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
  104.    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
  105.  
  106.    if (ffreq < ffreq_min/8) {
  107.       ErrorF("invalid frequency %1.3f MHz  [freq >= %1.3f MHz]\n", 
  108.          ffreq*BASE_FREQ, ffreq_min*BASE_FREQ/8);
  109.       ffreq = ffreq_min/8;
  110.    }
  111.    if (ffreq > ffreq_max / (1<<min_n2)) {
  112.       ErrorF("invalid frequency %1.3f MHz  [freq <= %1.3f MHz]\n", 
  113.          ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1<<min_n2));
  114.       ffreq = ffreq_max / (1<<min_n2);
  115.    }
  116.  
  117.    /* work out suitable timings */
  118.  
  119.    best_diff = ffreq;
  120.    
  121.    for (n2=min_n2; n2<=3; n2++) {
  122.       for (n1 = 1+2; n1 <= 31+2; n1++) {
  123.      m = (int)(ffreq * n1 * (1<<n2) + 0.5) ;
  124.      if (m < 1+2 || m > 127+2) 
  125.         continue;
  126.      div = (double)(m) / (double)(n1);     
  127.      if ((div >= ffreq_min) &&
  128.          (div <= ffreq_max)) {
  129.         diff = ffreq - div / (1<<n2);
  130.         if (diff < 0.0) 
  131.            diff = -diff;
  132.         if (diff < best_diff) {
  133.            best_diff = diff;
  134.            best_m    = m;
  135.            best_n1   = n1;
  136.            best_n2   = n2;
  137.         }
  138.      }
  139.       }
  140.    }
  141.    
  142. #if 0
  143.    ErrorF("clk %d, setting to %1.6f MHz (m %d, n1 %d, n2 %d)\n", clk,
  144.       ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ
  145.       ,best_m-2 ,best_n1-2 ,best_n2
  146.       );
  147. #endif
  148.  
  149.    *ndiv = (best_n1 - 2) | (best_n2 << 5);
  150.    *mdiv = best_m - 2;
  151. }       
  152.  
  153.  
  154. static int
  155. commonSetClock(freq, clk, min_n2, pll_type, freq_min, freq_max)
  156. long freq;
  157. int clk;
  158. int min_n2, pll_type;
  159. long freq_min, freq_max;
  160. {
  161.    unsigned char m, n;
  162.  
  163.    commonCalcClock(freq, min_n2, freq_min, freq_max, &m, &n);
  164.  
  165.    switch(pll_type)
  166.    {
  167.      case PLL_S3GENDAC:
  168.          setS3gendacpll(clk, m, n);
  169.          break;
  170.      case PLL_S3TRIO:
  171.          settriopll(clk, m, n);
  172.          break;
  173.      case PLL_ET4000GENDAC:
  174.          setET4000gendacpll(clk, m, n);
  175.          break;
  176.      default: 
  177.          ErrorF("Internal error: unknown pll_type in S3gendac.c");
  178.          return -1;
  179.     }
  180.      return 0;
  181. }       
  182.   
  183.  
  184.  
  185. static void
  186. #if NeedFunctionPrototypes
  187. setS3gendacpll(int reg, unsigned char data1, unsigned char data2)
  188. #else
  189. setS3gendacpll(reg, data1, data2)
  190. int reg;
  191. unsigned char data1;
  192. unsigned char data2;
  193. #endif
  194. {
  195.    unsigned char tmp, tmp1;
  196.    int vgaCRIndex = vgaIOBase + 4;
  197.    int vgaCRReg = vgaIOBase + 5;
  198.         
  199.    /* set RS2 via CR55, yuck */
  200.    outb(vgaCRIndex, 0x55);
  201.    tmp = inb(vgaCRReg) & 0xFC;
  202.    outb(vgaCRReg, tmp | 0x01);  
  203.    tmp1 = inb(GENDAC_INDEX);
  204.  
  205.    outb(GENDAC_INDEX, reg);
  206.    outb(GENDAC_DATA, data1);
  207.    outb(GENDAC_DATA, data2);
  208.  
  209.    /* Now clean up our mess */
  210.    outb(GENDAC_INDEX, tmp1);  
  211.    outb(vgaCRReg, tmp);
  212. }
  213.  
  214.  
  215. static void
  216. #if NeedFunctionPrototypes
  217. setET4000gendacpll(int reg, unsigned char data1, unsigned char data2)
  218. #else
  219. setET4000gendacpll(reg, data1, data2)
  220. int reg;
  221. unsigned char data1;
  222. unsigned char data2;
  223. #endif
  224. {
  225.    unsigned char tmp, tmp1;
  226.    int vgaCRIndex = vgaIOBase + 4;
  227.    int vgaCRReg = vgaIOBase + 5;
  228.         
  229.    /* set RS2 via CR31 */
  230.    outb(vgaCRIndex, 0x31);
  231.    tmp = inb(vgaCRReg) & 0xBF;
  232.    outb(vgaCRReg, tmp | 0x40);  
  233.    tmp1 = inb(GENDAC_INDEX);
  234.  
  235.    outb(GENDAC_INDEX, reg);
  236.    outb(GENDAC_DATA, data1);
  237.    outb(GENDAC_DATA, data2);
  238.  
  239.    /* Now clean up our mess */
  240.    outb(GENDAC_INDEX, tmp1);  
  241.    outb(vgaCRReg, tmp);
  242. }
  243.  
  244.  
  245. static void
  246. #if NeedFunctionPrototypes
  247. settriopll(int clk, unsigned char m, unsigned char n)
  248. #else
  249. settriopll(clk, m, n)
  250.      int clk;
  251.      unsigned char m;
  252.      unsigned char n;
  253. #endif
  254. {
  255.    unsigned char tmp;
  256.    int index;
  257.  
  258.    /*
  259.     * simlulate S3 GENDAC clock numbers:
  260.     * 0,1 for fixed 25 and 28 MHz clocks
  261.     * 2-8 free programmable
  262.     * 10  MCLK
  263.     */
  264.  
  265.    if (clk < 2) {
  266.       tmp = inb(0x3cc);
  267.       outb(0x3c2, (tmp & 0xf3) | (clk << 2));
  268.    }
  269.    else {
  270.       tmp = inb(0x3cc);
  271.       outb(0x3c2, tmp | 0x0c);
  272.  
  273.       outb(0x3c4, 0x08);
  274.       outb(0x3c5, 0x06);  /* unlock extended CR9-CR18 */
  275.  
  276.       if (clk != 10) {  /* DCLK */
  277.      outb(0x3c4, 0x12);
  278.      outb(0x3c5, n);
  279.      outb(0x3c4, 0x13);
  280.      outb(0x3c5, m);
  281.       }
  282.       else {        /* MCLK */
  283.      index = 0x10;
  284.      outb(0x3c4, 0x10);
  285.      outb(0x3c5, n);
  286.      outb(0x3c4, 0x11);
  287.      outb(0x3c5, m);
  288.      outb(0x3c4, 0x1a);
  289.      outb(0x3c5, n);
  290.       }
  291.  
  292.       outb(0x3c4, 0x15);
  293.       tmp = inb(0x3c5);
  294.       outb(0x3c4, tmp & ~0x20);
  295.       outb(0x3c4, tmp |  0x20);
  296.       outb(0x3c4, tmp & ~0x20);
  297.  
  298.       outb(0x3c4, 0x08);
  299.       outb(0x3c5, 0x00);  /* lock extended CR9-CR18 */
  300.       
  301.    }
  302. }
  303.