home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / SVGALIB / SVGALIB1.TAR / svgalib / src / ramdac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-21  |  18.0 KB  |  767 lines

  1.  
  2. /*
  3.  * This file contains RAMDAC definitions of type DacMethods for
  4.  * various DACs.
  5.  */
  6.  
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include "libvga.h"
  10.  
  11. #include "timing.h"
  12. #include "vgaregs.h"
  13. #include "ramdac.h"
  14.  
  15.  
  16. /*
  17.  * The following function probes the DACs in daclist, which must be
  18.  * terminated by NULL. It returns the detected DAC if succesful, NULL
  19.  * otherwise. The detected DAC is also initialized.
  20.  */
  21.  
  22. DacMethods *probeDacs( DacMethods **dacs_to_probe) {
  23.     /* Probe for a RAMDAC. */
  24.     for (;;) {
  25.         DacMethods *dac;
  26.         dac = *dacs_to_probe;
  27.         if (dac == NULL)
  28.             /* None found. */
  29.             return NULL;
  30.          if (dac->probe()) {
  31.              dac->initialize();
  32.              return dac;
  33.          }
  34.          dacs_to_probe++;
  35.      }
  36. }
  37.  
  38.  
  39. /*
  40.  * RAMDAC definition for normal VGA DAC.
  41.  * Max dot clock is set at 80 MHz.
  42.  */
  43.  
  44. int normal_dac_probe() {
  45.     return 1;
  46. }
  47.  
  48. void normal_dac_init() {
  49. }
  50.  
  51. int normal_dac_map_clock( int bpp, int pixelclock ) {
  52.     return pixelclock;
  53. }
  54.  
  55. int normal_dac_map_horizontal_crtc( int bpp, int pixelclock, int htiming ) {
  56.     return htiming;
  57. }
  58.  
  59. void normal_dac_savestate( unsigned char *regs ) {
  60. }
  61.  
  62. void normal_dac_restorestate( unsigned char *regs ) {
  63. }
  64.  
  65. void normal_dac_initializestate( unsigned char *regs, int bpp, int colormode,
  66. int pixelclock ) {
  67.     /* Nothing to do. */
  68. }
  69.  
  70. void normal_dac_qualify_cardspecs( CardSpecs *cardspecs ) {
  71.     cardspecs->maxPixelClock4bpp = 80000;
  72.     cardspecs->maxPixelClock8bpp = 80000;
  73.     cardspecs->maxPixelClock16bpp = 0;
  74.     cardspecs->maxPixelClock24bpp = 0;
  75.     cardspecs->maxPixelClock32bpp = 0;
  76.     cardspecs->mapClock = normal_dac_map_clock;
  77.     cardspecs->mapHorizontalCrtc = normal_dac_map_horizontal_crtc;
  78. }
  79.  
  80. DacMethods normal_dac_methods = {
  81.     NORMAL_DAC,
  82.     "Normal VGA DAC",
  83.     0,
  84.     normal_dac_probe,
  85.     normal_dac_init,
  86.     normal_dac_qualify_cardspecs,
  87.     normal_dac_savestate,
  88.     normal_dac_restorestate,
  89.     normal_dac_initializestate,
  90.     0    /* State size. */
  91. };
  92.  
  93.  
  94. /*
  95.  * RAMDAC definition for basic Sierra-type DAC
  96.  * that can do 32K (5-6-5) color mode (16bpp) with doubled VCLK.
  97.  * A value of 0x80 is written to the Hidden DAC register for this mode.
  98.  */
  99.  
  100. int Sierra_32K_probe() {
  101.     /* Should return 1 for any Sierra-type DAC. */
  102.     return 0;
  103. }
  104.  
  105. void Sierra_32K_init() {
  106.     /* Should probe the exact DAC type. */
  107. }
  108.  
  109. int Sierra_32K_map_clock( int bpp, int pixelclock ) {
  110.     if (bpp == 16)
  111.         return pixelclock * 2;
  112.     return pixelclock;
  113. }
  114.  
  115. int Sierra_32K_map_horizontal_crtc( int bpp, int pixelclock, int htiming ) {
  116.     /* Not sure. */
  117.     if (bpp == 16)
  118.         return htiming * 2;
  119.     return htiming;
  120. }
  121.  
  122. void Sierra_32K_savestate( unsigned char *regs ) {
  123.     inb(0x3C8);
  124.         inb(0x3C6); inb(0x3C6); inb(0x3C6); inb(0x3C6);
  125.         regs[0] = inb(0x3C6);
  126. }
  127.  
  128. void Sierra_32K_restorestate( unsigned char *regs ) {
  129.     inb(0x3C8);
  130.         inb(0x3C6); inb(0x3C6); inb(0x3C6); inb(0x3C6);
  131.         outb(0x3C6, regs[0]);
  132. }
  133.  
  134. void Sierra_32K_initializestate( unsigned char *regs, int bpp, int colormode,
  135. int pixelclock ) {
  136.     regs[0] = 0;
  137.     if (colormode == RGB16_555)
  138.         regs[0] = 0x80;
  139. }
  140.  
  141. void Sierra_32K_qualify_cardspecs( CardSpecs *cardspecs ) {
  142.     cardspecs->maxPixelClock4bpp = 80000;
  143.     cardspecs->maxPixelClock8bpp = 80000;
  144.     cardspecs->maxPixelClock16bpp = 40000;
  145.     cardspecs->maxPixelClock24bpp = 0;
  146.     cardspecs->maxPixelClock32bpp = 0;
  147.     cardspecs->mapClock = Sierra_32K_map_clock;
  148.     cardspecs->mapHorizontalCrtc = Sierra_32K_map_horizontal_crtc;
  149.     cardspecs->flags |= NO_RGB16_565;
  150. }
  151.  
  152. DacMethods Sierra_32K_methods = {
  153.     SIERRA_32K,
  154.     "Sierra 32K colors VGA DAC",
  155.     0,
  156.     Sierra_32K_probe,
  157.     Sierra_32K_init,
  158.     Sierra_32K_qualify_cardspecs,
  159.     Sierra_32K_savestate,
  160.     Sierra_32K_restorestate,
  161.     Sierra_32K_initializestate,
  162.     1    /* State size. */
  163. };
  164.  
  165.  
  166. /*
  167.  * RAMDAC definitions for the S3-SDAC (86C716) and S3-GENDAC.
  168.  *
  169.  * 16-bit DAC, 110 MHz raw clock limit. The 135 MHz version supports
  170.  * pixel multiplexing in 8bpp modes with a halved raw clock.
  171.  *
  172.  * The state consists of 6 registers (same for SDAC and GENDAC).
  173.  */
  174.  
  175. #define SDAC_COMMAND        0    /* Register offsets into state. */
  176. #define GENDAC_COMMAND        0
  177. #define SDAC_PLL_WRITEINDEX    1
  178. #define SDAC_PLL_READINDEX    2
  179. #define SDAC_PLL_M        3    /* f2 programmed clock */
  180. #define SDAC_PLL_N1_N2        4
  181. #define SDAC_PLL_CONTROL    5
  182.  
  183. #define SDAC_STATESIZE 6    /* 6 registers. */
  184. #define GENDAC_STATESIZE 6
  185.  
  186.  
  187.  
  188. int GENDAC_SDAC_probe() {
  189. /* Taken from XFree86, accel/s3.c. */
  190. /* Return 1 if GENDAC found, 2 if SDAC, 0 otherwise. */
  191.    /* probe for S3 GENDAC or SDAC */
  192.    /*
  193.     * S3 GENDAC and SDAC have two fixed read only PLL clocks
  194.     *     CLK0 f0: 25.255MHz   M-byte 0x28  N-byte 0x61
  195.     *     CLK0 f1: 28.311MHz   M-byte 0x3d  N-byte 0x62
  196.     * which can be used to detect GENDAC and SDAC since there is no chip-id
  197.     * for the GENDAC.
  198.     *
  199.     * NOTE: for the GENDAC on a MIRO 10SD (805+GENDAC) reading PLL values
  200.     * for CLK0 f0 and f1 always returns 0x7f (but is documented "read only")
  201.     */
  202.    
  203.    unsigned char saveCR55, savelut[6];
  204.    int i;
  205.    long clock01, clock23;
  206.  
  207.    saveCR55 = inCR(0x55);
  208.    outbCR(0x55, saveCR55 & ~1);
  209.  
  210.    outb(0x3c7,0);
  211.    for(i=0; i<2*3; i++)        /* save first two LUT entries */
  212.       savelut[i] = inb(0x3c9);
  213.    outb(0x3c8,0);
  214.    for(i=0; i<2*3; i++)        /* set first two LUT entries to zero */
  215.       outb(0x3c9,0);
  216.  
  217.    outbCR(0x55, saveCR55 | 1);
  218.  
  219.    outb(0x3c7,0);
  220.    for(i=clock01=0; i<4; i++)
  221.       clock01 = (clock01 << 8) | (inb(0x3c9) & 0xff);
  222.    for(i=clock23=0; i<4; i++)
  223.       clock23 = (clock23 << 8) | (inb(0x3c9) & 0xff);
  224.  
  225.    outbCR(0x55, saveCR55 & ~1);
  226.  
  227.    outb(0x3c8,0);
  228.    for(i=0; i<2*3; i++)        /* restore first two LUT entries */
  229.       outb(0x3c9,savelut[i]);
  230.  
  231.    outbCR(0x55, saveCR55);
  232.  
  233.    if ( clock01 == 0x28613d62 ||
  234.        (clock01 == 0x7f7f7f7f && clock23 != 0x7f7f7f7f)) {
  235.  
  236.       inb(0x3c8);    /* dactopel */
  237.  
  238.       inb(0x3c6);
  239.       inb(0x3c6);
  240.       inb(0x3c6);
  241.  
  242.       /* the forth read will show the SDAC chip ID and revision */
  243.       if (((i=inb(0x3c6)) & 0xf0) == 0x70) {
  244.      return 2;    /* SDAC found. */
  245.       }
  246.       else {
  247.      return 1;    /* GENDAC found. */
  248.       }
  249.       inb(0x3c8);    /* dactopel */
  250.    }
  251.    return 0;
  252. }
  253.  
  254. void GENDAC_SDAC_init() {
  255.     unsigned char val;
  256.     int m, n, n1, n2, MCLK;
  257.     val = inCR(0x55);
  258.     outbCR(0x55, val | 0x01);
  259.  
  260.     outb(0x3C7, 10);    /* Read MCLK. */
  261.     m = inb(0x3C9);
  262.     n = inb(0x3C9);
  263.  
  264.     outbCR(0x55, val);    /* Restore CR55. */
  265.  
  266.     m &= 0x7f;
  267.     n1 = n & 0x1f;
  268.     n2 = (n >> 5) & 0x03;
  269.     /* Calculate MCLK in kHz. */
  270.     MCLK = 14318 * (m + 2) / (n1 + 2) / (1 << n2);
  271.     printf("svgalib: S3-GENDAC/SDAC: MCLK = %d.%03d MHz\n",
  272.         MCLK / 1000, MCLK % 1000);
  273. }
  274.  
  275.  
  276. /* From XFree86, common_hw/S3gendac.c and S3gendac.h */
  277. /*
  278.  * Progaming of the S3 gendac programable clocks, from the S3 Gendac
  279.  * programing documentation by S3 Inc. 
  280.  * Jon Tombs <jon@esix2.us.es>
  281.  */
  282.  
  283. #include <math.h>
  284.  
  285. #define GENDAC_INDEX         0x3C8
  286. #define GENDAC_DATA         0x3C9
  287. #define BASE_FREQ         14318.18   /* KHz */
  288.  
  289.  
  290. int
  291. S3gendacFindClock(int freq, int min_n2, int freq_min, int freq_max,
  292. int *best_m_out, int *best_n1_out, int *best_n2_out)
  293. {
  294.    double ffreq, ffreq_min, ffreq_max;
  295.    double div, diff, best_diff;
  296.    unsigned int m;
  297.    unsigned char n, n1, n2;
  298.    unsigned char best_n1=16+2, best_n2=2, best_m=125+2;
  299.  
  300.    ffreq     = freq     / 1000.0 / BASE_FREQ;
  301.    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
  302.    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
  303.  
  304.    if (ffreq < ffreq_min/8) {
  305.       printf("invalid frequency %1.3f MHz  [freq >= %1.3f MHz]\n", 
  306.          ffreq*BASE_FREQ, ffreq_min*BASE_FREQ/8);
  307.       ffreq = ffreq_min/8;
  308.    }
  309.    if (ffreq > ffreq_max / (1<<min_n2)) {
  310.       printf("invalid frequency %1.3f MHz  [freq <= %1.3f MHz]\n", 
  311.          ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1<<min_n2));
  312.       ffreq = ffreq_max / (1<<min_n2);
  313.    }
  314.  
  315.    /* work out suitable timings */
  316.  
  317.    best_diff = ffreq;
  318.    
  319.    for (n2=min_n2; n2<=3; n2++) {
  320.       for (n1 = 1+2; n1 <= 31+2; n1++) {
  321.      m = (int)(ffreq * n1 * (1<<n2) + 0.5) ;
  322.      if (m < 1+2 || m > 127+2) 
  323.         continue;
  324.      div = (double)(m) / (double)(n1);     
  325.      if ((div >= ffreq_min) &&
  326.          (div <= ffreq_max)) {
  327.         diff = ffreq - div / (1<<n2);
  328.         if (diff < 0.0) 
  329.            diff = -diff;
  330.         if (diff < best_diff) {
  331.            best_diff = diff;
  332.            best_m    = m;
  333.            best_n1   = n1;
  334.            best_n2   = n2;
  335.         }
  336.      }
  337.       }
  338.    }
  339.    
  340. #if 0
  341.    ErrorF("clk %d, setting to %1.6f MHz (m %d, n1 %d, n2 %d)\n", clk,
  342.       ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ
  343.       ,best_m-2 ,best_n1-2 ,best_n2
  344.       );
  345. #endif
  346.  
  347.    n = (best_n1 - 2) | (best_n2 << 5);
  348.    m = best_m - 2;
  349.  
  350.    *best_m_out = best_m;
  351.    *best_n1_out = best_n1;
  352.    *best_n2_out = best_n2;
  353. }
  354.  
  355. int SDAC_GENDAC_match_programmable_clock( int desiredclock ) {
  356.     int min_m, min_n1, n2;
  357.     S3gendacFindClock(desiredclock, 0, 100000, 250000,
  358.         &min_m, &min_n1, &n2);
  359. /*
  360.     For ICS5342, min_n2 parameter should be one.
  361.     For Trio, min_n2 = 0, freq_min = 130000 and freq_max = 270000
  362. */
  363.      
  364.     return ((float)(min_m) / (float)(min_n1) / (1 << n2))
  365.         * BASE_FREQ;
  366. }
  367.  
  368. int Trio64_match_programmable_clock( int desiredclock ) {
  369.     int min_m, min_n1, n2;
  370.     S3gendacFindClock(desiredclock, 0, 130000, 270000,
  371.         &min_m, &min_n1, &n2);
  372.      
  373.     return ((float)(min_m) / (float)(min_n1) / (1 << n2))
  374.         * BASE_FREQ;
  375. }
  376.  
  377.  
  378. #if 0    /* Retain for reference. */
  379. static void
  380. setdacpll(reg, data1, data2)
  381. int reg;
  382. unsigned char data1;
  383. unsigned char data2;
  384. {
  385.    unsigned char tmp, tmp1;
  386.    int vgaCRIndex = vgaIOBase + 4;
  387.    int vgaCRReg = vgaIOBase + 5;
  388.         
  389.    /* set RS2 via CR55, yuck */
  390.    tmp = inCR(0x55) & 0xFC;
  391.    outCR(tmp | 0x01);
  392.    tmp1 = inb(GENDAC_INDEX);
  393.  
  394.    outb(GENDAC_INDEX, reg);
  395.    outb(GENDAC_DATA, data1);
  396.    outb(GENDAC_DATA, data2);
  397.  
  398.    /* Now clean up our mess */
  399.    outb(GENDAC_INDEX, tmp1);  
  400.    outbCR(0x55, tmp);
  401. }
  402. #endif
  403.  
  404. void SDAC_GENDAC_initialize_clock_state(unsigned char *regs, int freq ) {
  405.     int min_m, min_n1, n2;
  406.     int n, m;
  407.     S3gendacFindClock(freq, 0, 100000, 250000, &min_m, &min_n1, &n2);
  408.     n = (min_n1 - 2) | (n2 << 5);
  409.     m = min_m - 2;
  410.     regs[SDAC_PLL_M] = m;
  411.     regs[SDAC_PLL_N1_N2] = n;
  412.     printf("Initializing DAC values; 0x%02X, 0x%02X.\n", m, n);
  413. }
  414.  
  415. void GENDAC_SDAC_savestate( unsigned char *regs ) {
  416.     unsigned char tmp;
  417.     tmp = inCR(0x55);
  418.     outbCR(0x55, tmp | 1);
  419.  
  420.     regs[SDAC_COMMAND] = inb(0x3c6);
  421.     regs[SDAC_PLL_WRITEINDEX] = inb(0x3c8);    /* PLL write index */
  422.     regs[SDAC_PLL_READINDEX] = inb(0x3c7);    /* PLL read index */
  423.     outb(0x3c7, 2);                /* index to f2 reg */
  424.     regs[SDAC_PLL_M] = inb(0x3c9);        /* f2 PLL M divider */
  425.     regs[SDAC_PLL_N1_N2] = inb(0x3c9);    /* f2 PLL N1/N2 divider */
  426.     outb(0x3c7, 0x0e);            /* index to PLL control */
  427.     regs[SDAC_PLL_CONTROL] = inb(0x3c9);    /* PLL control */
  428.  
  429.     outbCR(0x55, tmp & ~1);
  430. }
  431.  
  432. void GENDAC_SDAC_restorestate( unsigned char *regs ) {
  433.     unsigned char tmp;
  434.  
  435.     /* set RS2 via CR55, yuck */
  436.     tmp = inCR(0x55) & 0xFC;
  437.     outbCR(0x55, tmp | 0x01);
  438.  
  439.     printf("SDAC.restorestate, setting clock 0x%02X 0x%02X\n",
  440.         regs[SDAC_PLL_M],
  441.         regs[SDAC_PLL_N1_N2]);
  442.  
  443.     outb(0x3c6, regs[SDAC_COMMAND]);
  444.     outb(0x3c8, 2);                /* index to f2 reg */
  445.     outb(0x3c9, regs[SDAC_PLL_M]);        /* f2 PLL M divider */
  446.     outb(0x3c9, regs[SDAC_PLL_N1_N2]);    /* f2 PLL N1/N2 divider */
  447.     outb(0x3c8, 0x0e);            /* index to PLL control */
  448.     outb(0x3c9, regs[SDAC_PLL_CONTROL]);    /* PLL control */
  449.     outb(0x3c8, regs[SDAC_PLL_WRITEINDEX]);    /* PLL write index */
  450.     outb(0x3c7, regs[SDAC_PLL_READINDEX]);    /* PLL read index */
  451.  
  452.     outbCR(0x55, tmp);
  453. }
  454.  
  455.  
  456. /* SDAC */
  457.  
  458. int SDAC_probe() {
  459.     return GENDAC_SDAC_probe() == 2;
  460. }
  461.  
  462. int SDAC_map_clock( int bpp, int pixelclock ) {
  463.     if (bpp == 8 && pixelclock >= 67500)
  464.         /* Use pixel multiplexing. */
  465.         return pixelclock / 2;
  466.     if (bpp == 32)
  467.         return pixelclock * 2;
  468.     return pixelclock;
  469. }
  470.  
  471. int SDAC_map_horizontal_crtc( int bpp, int pixelclock, int htiming ) {
  472.     if (bpp == 16)
  473.         return htiming * 2;
  474.     if (bpp == 32)
  475.         return htiming * 4;
  476.     return htiming;
  477. }
  478.  
  479. void SDAC_initializestate( unsigned char *regs, int bpp, int colormode,
  480. int pixelclock ) {
  481.     int pixmux;        /* SDAC command register. */
  482.     pixmux = 0;
  483.     if (colormode == CLUT8_6 && pixelclock >= 67500)
  484.         pixmux = 0x10;
  485.     else
  486.     if (colormode == RGB16_555)
  487.         pixmux = 0x30;
  488.     else
  489.     if (colormode == RGB16_565)
  490.         pixmux = 0x50;
  491.     else
  492.     if (colormode == RGB32_888_B)
  493.         pixmux = 0x70;
  494.     regs[SDAC_COMMAND] = pixmux;
  495.     SDAC_GENDAC_initialize_clock_state(regs,
  496.         SDAC_map_clock(bpp, pixelclock));
  497. }
  498.  
  499. void SDAC_qualify_cardspecs( CardSpecs *cardspecs ) {
  500.     /* Conservative values for 110 MHz version. */
  501.     cardspecs->maxPixelClock4bpp = 110000;
  502.     cardspecs->maxPixelClock8bpp = 110000;    /* Most can do 135 MHz. */
  503.     cardspecs->maxPixelClock16bpp = 110000;    /* Raw clock limit. */
  504.     cardspecs->maxPixelClock24bpp = 0;    /* How to program? */
  505.     cardspecs->maxPixelClock32bpp = 110000 / 2;
  506.     cardspecs->mapClock = SDAC_map_clock;
  507.     cardspecs->matchProgrammableClock = SDAC_GENDAC_match_programmable_clock;
  508.     cardspecs->flags |= CLOCK_PROGRAMMABLE;
  509.     cardspecs->mapHorizontalCrtc = SDAC_map_horizontal_crtc;
  510. }
  511.  
  512. DacMethods S3_SDAC_methods = {
  513.     S3_SDAC,
  514.     "S3-SDAC (86C716)",
  515.     DAC_HAS_PROGRAMMABLE_CLOCKS,
  516.     SDAC_probe,
  517.     GENDAC_SDAC_init,
  518.     SDAC_qualify_cardspecs,
  519.     GENDAC_SDAC_savestate,
  520.     GENDAC_SDAC_restorestate,
  521.     SDAC_initializestate,
  522.     SDAC_STATESIZE
  523. };
  524.  
  525.  
  526. /* S3-GENDAC, 8-bit DAC. */
  527.  
  528. int GENDAC_probe() {
  529.     return GENDAC_SDAC_probe() == 1;
  530. }
  531.  
  532. int GENDAC_map_clock( int bpp, int pixelclock ) {
  533.     if (bpp == 16)
  534.         return pixelclock * 2;
  535.     if (bpp == 32)
  536.         return pixelclock * 4;
  537.     return pixelclock;
  538. }
  539.  
  540. int GENDAC_map_horizontal_crtc( int bpp, int pixelclock, int htiming ) {
  541.     /* XXXX Not sure. */
  542.     if (bpp == 24)
  543.         return htiming * 3;
  544.     if (bpp == 16)
  545.         return htiming * 2;
  546.     return htiming;
  547. }
  548.  
  549. void GENDAC_initializestate( unsigned char *regs, int bpp, int colormode,
  550. int pixelclock ) {
  551.     int daccomm;        /* DAC command register. */
  552.     daccomm = 0;
  553.     if (colormode == RGB16_555)
  554.         daccomm = 0x20;
  555.     else
  556.     if (colormode == RGB16_565)
  557.         daccomm = 0x60;
  558.     else
  559.     if (colormode == RGB32_888_B)
  560.         daccomm = 0x40;
  561.     regs[GENDAC_COMMAND] = daccomm;
  562.     SDAC_GENDAC_initialize_clock_state(regs,
  563.         GENDAC_map_clock(bpp, pixelclock));
  564. }
  565.  
  566. void GENDAC_qualify_cardspecs( CardSpecs *cardspecs ) {
  567.     /* Conservative values for 110 MHz version. */
  568.     cardspecs->maxPixelClock4bpp = 110000;
  569.     cardspecs->maxPixelClock8bpp = 110000;
  570.     cardspecs->maxPixelClock16bpp = 110000 / 2;
  571.     cardspecs->maxPixelClock24bpp = 0;        /* How to program? */
  572.     cardspecs->maxPixelClock32bpp = 0;
  573.     cardspecs->mapClock = GENDAC_map_clock;
  574.     cardspecs->matchProgrammableClock = SDAC_GENDAC_match_programmable_clock;
  575.     cardspecs->mapHorizontalCrtc = GENDAC_map_horizontal_crtc;
  576. }
  577.  
  578. DacMethods S3_GENDAC_methods = {
  579.     S3_GENDAC,
  580.     "S3-GENDAC (86C708)",
  581.     DAC_HAS_PROGRAMMABLE_CLOCKS,
  582.     GENDAC_probe,
  583.     GENDAC_SDAC_init,
  584.     GENDAC_qualify_cardspecs,
  585.     GENDAC_SDAC_savestate,
  586.     GENDAC_SDAC_restorestate,
  587.     GENDAC_initializestate,
  588.     GENDAC_STATESIZE
  589. };
  590.  
  591.  
  592. /* S3-Trio64, 16-bit integrated DAC. */
  593.  
  594. #define    TRIO64_SR15        0
  595. #define TRIO64_SR18        1
  596. #define TRIO64_PLL_N1_N2    2
  597. #define TRIO64_PLL_M        3
  598. #define TRIO64_CR67        4
  599. #define TRIO64_STATESIZE    5
  600.  
  601. /* Note: s3.c also defines CR67, but doesn't use it for the Trio64. */
  602.  
  603. void Trio64_init() {
  604.     unsigned char sr8;
  605.     int m, n, n1, n2, mclk;
  606.  
  607.     outb(0x3c4, 0x08);
  608.     sr8 = inb(0x3c5);
  609.     outb(0x3c5, 0x06);
  610.      
  611.     outb(0x3c4, 0x11);
  612.     m = inb(0x3c5);
  613.     outb(0x3c4, 0x10);
  614.     n = inb(0x3c5);
  615.      
  616.     outb(0x3c4, 0x08);
  617.     outb(0x3c5, sr8);
  618.  
  619.     m &= 0x7f;
  620.     n1 = n & 0x1f;
  621.     n2 = (n>>5) & 0x03;
  622.     /* Calculate MCLK in kHz. */
  623.     mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
  624.     printf("svgalib: Trio64: MCLK = %d.%03d MHz\n",
  625.         mclk / 1000, mclk % 1000);
  626. }
  627.  
  628.  
  629. int Trio64_map_clock( int bpp, int pixelclock ) {
  630.     if (bpp == 8 && pixelclock >= 80000)
  631.         return pixelclock / 2;
  632.     if (bpp == 32)
  633.         return pixelclock * 2;
  634.     return pixelclock;
  635. }
  636.  
  637. int Trio64_map_horizontal_crtc( int bpp, int pixelclock, int htiming ) {
  638.     if (bpp == 16)
  639.         return htiming * 2;
  640.     /* Normal mapping for 8bpp and 32bpp. */
  641.     return htiming;
  642. }
  643.  
  644. void Trio64_initialize_clock_state(unsigned char *regs, int freq ) {
  645.     int min_m, min_n1, n2;
  646.     int n, m;
  647.     S3gendacFindClock(freq, 0, 130000, 270000, &min_m, &min_n1, &n2);
  648.     n = (min_n1 - 2) | (n2 << 5);
  649.     m = min_m - 2;
  650.     regs[TRIO64_PLL_M] = m;
  651.     regs[TRIO64_PLL_N1_N2] = n;
  652. }
  653.  
  654. void Trio64_initializestate( unsigned char *regs, int bpp, int colormode,
  655. int pixelclock ) {
  656.     int pixmux, invert_vclk;
  657.     regs[TRIO64_SR15] &= ~0x10;
  658.     regs[TRIO64_SR18] &= ~0x80;
  659.     pixmux = 0;
  660.     invert_vclk = 0;
  661.     if (colormode == CLUT8_6 && pixelclock >= 80000) {
  662.         pixmux = 0x10;
  663.         invert_vclk = 2;
  664.         regs[TRIO64_SR15] |= 0x10;
  665.         regs[TRIO64_SR18] |= 0x80;
  666.     }
  667.     else
  668.     if (bpp == 16) {
  669.         /* moderegs[S3_CR33] |= 0x08; */ /* done in s3.c. */
  670.         if (colormode == RGB16_555)
  671.             pixmux = 0x30;
  672.         else
  673.             pixmux = 0x50;
  674.     }
  675.     if (colormode == RGB32_888_B) {
  676.         pixmux = 0xD0;    /* 32-bit color, 2 VCLKs/pixel. */
  677.     }
  678.     regs[TRIO64_CR67] = pixmux | invert_vclk;
  679.  
  680.     Trio64_initialize_clock_state(regs, pixelclock);
  681. }
  682.  
  683. void Trio64_savestate( unsigned char *regs ) {
  684.     unsigned char SR8;
  685.     outb(0x3C4, 0x08);
  686.     SR8 = inb(0x3C5);
  687.  
  688.     regs[TRIO64_SR15] = inSR(0x15);
  689.     regs[TRIO64_SR18] = inSR(0x18);
  690.     regs[TRIO64_PLL_N1_N2] = inSR(0x12);
  691.     regs[TRIO64_PLL_M] = inSR(0x13);
  692.     regs[TRIO64_CR67] = inCR(0x67);
  693.  
  694.     outSR(0x08, SR8);
  695. }
  696.  
  697. void Trio64_restorestate( unsigned char *regs ) {
  698.     unsigned char SR8;
  699.  
  700.     outb(0x3C4, 0x08);
  701.     SR8 = inb(0x3C5);
  702.     outb(0x3C5, 0x06);    /* Unlock. */
  703.  
  704.     outCR(0x67, regs[TRIO64_CR67]);
  705.  
  706.     outSR(0x15, regs[TRIO64_SR15]);
  707.     outSR(0x18, regs[TRIO64_SR18]);
  708.  
  709.     /* Clock. */
  710.     outSR(0x12, regs[TRIO64_PLL_N1_N2]);
  711.     outSR(0x13, regs[TRIO64_PLL_M]);
  712.  
  713. #if 0
  714.     /*
  715.      * XFree86 XF86_S3 (common_hw/gendac.c) has this, but it looks
  716.      * incorrect, it should flip the bit by writing to 0x3c5, not
  717.      * 0x3c4.
  718.      */
  719.       outb(0x3c4, 0x15);
  720.       tmp = inb(0x3c5);
  721.       outb(0x3c4, tmp & ~0x20);
  722.       outb(0x3c4, tmp |  0x20);
  723.       outb(0x3c4, tmp & ~0x20);
  724. #endif
  725.  
  726.     outSR(0x08, SR8);
  727. }
  728.  
  729.  
  730. void Trio64_qualify_cardspecs( CardSpecs *cardspecs ) {
  731.     cardspecs->maxPixelClock4bpp = 80000;
  732.     cardspecs->maxPixelClock8bpp = 135000;
  733.     cardspecs->maxPixelClock16bpp = 80000;
  734.     cardspecs->maxPixelClock24bpp = 0;        /* How to program? */
  735.     cardspecs->maxPixelClock32bpp = 50000;
  736.     cardspecs->mapClock = Trio64_map_clock;
  737.     cardspecs->matchProgrammableClock = Trio64_match_programmable_clock;
  738.     cardspecs->mapHorizontalCrtc = Trio64_map_horizontal_crtc;
  739. }
  740.  
  741. DacMethods Trio64_methods = {
  742.     TRIO64,
  743.     "S3-Trio64 internal DAC",
  744.     DAC_HAS_PROGRAMMABLE_CLOCKS,
  745.     NULL,    /* probe */
  746.     Trio64_init,
  747.     Trio64_qualify_cardspecs,
  748.     Trio64_savestate,
  749.     Trio64_restorestate,
  750.     Trio64_initializestate,
  751.     TRIO64_STATESIZE
  752. };
  753.  
  754.  
  755. /*
  756.  * List of all DACs.
  757.  */
  758.  
  759. DacMethods *all_dacs[] = {
  760.     &normal_dac_methods,
  761.     &S3_SDAC_methods,
  762.     &S3_GENDAC_methods,
  763.     &Trio64_methods,
  764.     &Sierra_32K_methods,
  765.     NULL
  766. };
  767.