home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 January / pcwk_01_1999.iso / Tajnepp / MCLK093 / MATROX.CPP < prev    next >
C/C++ Source or Header  |  1997-06-15  |  16KB  |  527 lines

  1. /*    matrox.cpp        06/15/97    0.93ß
  2.  *
  3.  *    Includes class definitions for Matrox Graphics, Inc.
  4.  *
  5.  *    _Mystique - Matrox Mystique 1064SG
  6.  *            3 settings
  7.  *
  8.  *    _MCLK - The Mystique's clocking arrangement is unique.  A single
  9.  *     "system PLL" drives two separate portions of the Mystique chipset.
  10.  *     The SGRAM memory-controller operates at one frequency ( PLL / 2 )
  11.  *    while the graphics-clock (datapath) operates at another ( PLL / 3 )
  12.  *    Thus, the system-PLL's frequency is twice the actual MCLK freq,
  13.  *     and three times the actual accelerator-engine frequency.
  14.  *
  15.  *    None of this code has been tested yet...I hope it all works!
  16.  *
  17.  *
  18.  *
  19.  *
  20.  *
  21.  
  22.  *    v0.93ß first release
  23.  */
  24.  
  25. #include "matrox.h"
  26.  
  27. #include<dos.h>
  28. #include<string.h>
  29. #include<stdio.h>
  30. #include<stdlib.h>
  31. #include<iostreams.h>
  32.  
  33. #define _SYSPLLN 0x2D
  34. #define _SYSPLLM 0x2C
  35. #define _SYSPLLP 0x2E
  36.  
  37. _Mystique::_Mystique( vga_info info ) : vga( info )
  38. {
  39.     //    not used
  40. }
  41.  
  42.  
  43. _Mystique::~_Mystique()
  44. {
  45.     // not used
  46. }
  47.  
  48.  
  49. message
  50. _Mystique::_info( void )
  51. {
  52.     INITMSG( msg.text );
  53.  
  54. //    msgout <<    "IO config address = 0x" ;    // 32-bit absolute byte address
  55. //    hexout( msgout, baseio.b.b3 );    // print reg.h.bl in "XX" format
  56. //    hexout( msgout, baseio.b.b2 );
  57. //    msgout << " ";
  58.     msgout << ends ;
  59.     return msg;
  60. }
  61.  
  62.  
  63. uchar
  64. _Mystique::read_cbyte( const uchar index )
  65. {
  66.     uchar value, status = TRUE;
  67.  
  68.         status = pci_bios->read_cbyte( pci_vga, index, &value );
  69.      return value;
  70. }
  71.  
  72.  
  73. uchar
  74. _Mystique::write_cbyte( const uchar index, const uchar value )
  75. {
  76.      uchar status= TRUE;
  77.  
  78.     if ( pci_bios->write_cbyte( pci_vga, index, value ) != 0 )
  79.          status = FALSE;
  80.  
  81.     return status;
  82. }
  83.  
  84.  
  85. uchar
  86. _Mystique::read_indirect( const uint index )
  87. {
  88.      // The following data-structure, mga_index, represents the Mystique's
  89.      // mga_index register, which is located at PCI_CFG $44.
  90. //     union {
  91. //         struct
  92. //          {
  93. //              uchar b0;
  94. //               uchar b1;
  95. //          } b;    // data byte values
  96. //
  97. //          struct
  98. //          {
  99. //            unsigned reserved1:2;
  100. //               unsigned index:12;
  101. //               unsigned reserved2:2;
  102. //          } name;    // Named bitfields
  103. //     } mga_index;    // 16-bit register
  104.  
  105.      // The following three lines effectively perform a read/modify/write
  106.      // operation on the Mystique's MGA_INDEX register (PCI_CFG $44)
  107.      mga_index_load();    // Load MGA registers into object mga_index()
  108.  
  109.          // Now write desired index-value into mga_index
  110.      mga_index.name.index = ( index % 4 );
  111.          // "index % 4" returns the remainder of (m_index DIV 4)
  112.  
  113.      mga_index_store();    // Write object contents back to MGA register
  114.  
  115.      // Ready to read the desired MGA indirect register
  116.      // the DATA register at PCI-CFG $48 is a 32-bit (DWORD) register.
  117.      // Since this routine parses a BYTE (and not DWORD) address, the
  118.      // position of returned byte will depend on the desired address
  119.  
  120.      switch ( index % 4 )
  121.      {
  122.          case 0 :    return read_cbyte( 0x48 );    // bits 0-7
  123.                break;
  124.          case 1 :    return read_cbyte( 0x48 + 1);    // bits 8-15
  125.                break;
  126.          case 2 :    return read_cbyte( 0x48 + 2);    // bits 16-23
  127.                break;
  128.          case 3 :    return read_cbyte( 0x48 + 3);    // bits 24-31
  129.                break;
  130.           default:
  131.               ;
  132.      };
  133. }
  134.  
  135.  
  136. uchar
  137. _Mystique::write_indirect( const uint index, const uchar value )
  138. {
  139.      // The following data-structure, mga_index, represents the Mystique's
  140.      // mga_index register, which is located at PCI_CFG $44.
  141. //     union {
  142. //         struct
  143. //          {
  144. //              uchar b0;
  145. //               uchar b1;
  146. //          } b;    // data byte values
  147. //
  148. //          struct
  149. //          {
  150. //            unsigned reserved1:2;
  151. //               unsigned index:12;
  152. //               unsigned reserved2:2;
  153. //          } name;    // Named bitfields
  154. //     } mga_index;    // 16-bit register
  155.  
  156.      mga_index_load();    // Load MGA registers into object mga_index()
  157.  
  158.          // Now write desired index-value into mga_index
  159.      mga_index.name.index = ( index % 4 );
  160.          // "index % 4" returns the remainder of (m_index DIV 4)
  161.  
  162.      mga_index_store();    // Write object contents back to MGA register
  163.  
  164.      // Ready to read the desired MGA indirect register
  165.      // the DATA register at PCI-CFG $48 is a 32-bit (DWORD) register.
  166.      // Since this routine parses a BYTE (and not DWORD) address, the
  167.      // position of returned byte will depend on the desired address
  168.  
  169.      switch ( index % 4 )
  170.      {
  171.          case 0 :    return write_cbyte( 0x48, value );    // bits 0-7
  172.                break;
  173.          case 1 :    return write_cbyte( 0x48 + 1, value );    // bits 8-15
  174.                break;
  175.          case 2 :    return write_cbyte( 0x48 + 2, value );    // bits 16-23
  176.                break;
  177.          case 3 :    return write_cbyte( 0x48 + 3, value);    // bits 24-31
  178.                break;
  179.           default:
  180.               ;
  181.      };
  182. }
  183.  
  184.  
  185. uchar
  186. _Mystique::read_x( const uchar index )
  187. {
  188.      write_indirect( 0x3C00, index );
  189.          // Load PALWTADD with desired-address
  190.      return read_indirect( 0x3C0A );
  191.          // Read X-reg from port (MGABASE1 + $3C0A)
  192. }
  193.  
  194.  
  195. uchar
  196. _Mystique::write_x( const uchar index, const uchar value )
  197. {
  198.      write_indirect( 0x3C00, index );
  199.          // Load PALWTADD with desired-address
  200.      return write_indirect( 0x3C0A, value );
  201.          // Write value -> (MGABASE1 + $3C0A)
  202. }
  203.  
  204. // set_sysclkdis() will either ENABLE or DISABLE system-clock output,
  205. // depending on BIT.  If BIT=0, clock-output is enabled.  If BIT=1,
  206. // clock-output is disabled.
  207. // The bitfield sysclkdis is part of the OPTION byte, PCI_CFG $40 (bit2).
  208. void
  209. _Mystique::set_sysclkdis( uchar bit )
  210. {
  211.     union {
  212.         uchar byte;
  213.         struct
  214.         {
  215.             unsigned other1:2;
  216.             unsigned sysclkdis:1;
  217.             unsigned other2:5;
  218.           } name;    // total of 8-bits
  219.     } option;    // OPTION byte
  220.  
  221.      option.byte = read_cbyte( 0x40 );
  222.     option.name.sysclkdis = bit ;
  223.     write_cbyte( 0x40 , option.byte );
  224. }
  225.  
  226. // set_sysclksl() sets the Mystique's clock-source according to the
  227. // following table: input = bits
  228. // 00 select PCI clock
  229. // 01 select output of system clock PLL (on-board clock synthesizer)
  230. // 10 selects an external source from the MCLK pin
  231. // 11 reserved
  232. void
  233. _Mystique::set_sysclksl( uchar bits )
  234. {
  235.     union {
  236.         uchar byte;
  237.         struct
  238.         {
  239.             unsigned sysclksl:2;
  240.             unsigned other1:6;
  241.           } name;    // total of 8-bits
  242.     } option;    // OPTION byte
  243.  
  244.     option.byte = read_cbyte( 0x40 );
  245.     option.name.sysclksl = bits;
  246.     write_cbyte( 0x40, option.byte );
  247. }
  248.  
  249.  
  250. /*
  251.     Formula for Mystique System PLL driver
  252.  
  253.             (sysplln + 1)
  254.      FVCO = ------------- * 14.31818 MHz
  255.             (syspllm + 1)
  256.  
  257.     where, final system-pll frequency is given by
  258.  
  259.                             FVCO
  260.      frequency( pll ) = -------------
  261.                         (syspllp + 1)
  262.  
  263.      sysplln, syspllm constitute control parameters in the feedback loop.
  264.     syspllp is a post-divider circuit.
  265.  
  266.      Range of acceptable values:
  267.          100 <= sysplln <= 127 (feedback divider)
  268.           1 <= syspllm <= 31 (input divider)
  269.           syspllp = { 0, 1, 3, 7 }
  270. */
  271.  
  272.  
  273. void
  274. _Mystique::_mclk( int cmd )
  275. {
  276.      double fv;    // Temporary fvco variable
  277.      int i;    // dummy loop variable
  278.     union    {
  279.          uchar byte;    // SYSPLLM register byte
  280.           struct {
  281.               unsigned m : 5;    // PLL M prescalar value, 5-bits
  282.                unsigned other : 3;
  283.           } x;
  284.      } syspllm;
  285.  
  286.      union    {
  287.          uchar byte;    // SYSPLLN register byte
  288.           struct {
  289.               unsigned n : 7;    // PLL N feedback-divider value, 7-bits
  290.                unsigned other : 1;
  291.           } x;
  292.      } sysplln;
  293.  
  294.  
  295.      union    {
  296.          uchar byte;    // SYSPLLP register byte
  297.           struct {
  298.               unsigned p : 3;    // PLL P post-divider value, 3-bits
  299.                unsigned s : 2;    // PLL S loop-filter value
  300.                unsigned other : 3;
  301.           } x;
  302.      } syspllp;
  303.  
  304.     INITMSG( msg.text );
  305.  
  306.     if ( cmd == _QUERY )    {
  307.         msgout << "0  Mystique MCLK programming\n" << ends;
  308.         return;
  309.     }
  310.  
  311.      // Load the syspll* variables with respective MGA registers
  312.      sysplln.x.n = read_cbyte( _SYSPLLN );
  313.      syspllm.x.m = read_cbyte( _SYSPLLM );
  314.      syspllp.x.p = read_cbyte( _SYSPLLP );
  315.  
  316.     msgout.precision( 2 );
  317.     msgout << "Old PLL clock = " << ( fvco( sysplln.x.n, syspllm.x.m ) /
  318.         ( syspllp.x.p + 1.0 ) ) << " MHz ( N=" << sysplln.x.n <<
  319.           ", M=" << syspllm.x.m << ", P=" << syspllp.x.p << " )";
  320.  
  321.      if ( num_param < 3 && cmd == _SET )    {
  322.         msgout << "\n...not enough parameters, need total of 3.";
  323.         cmd = _HELP;    //    Not enough parameters.
  324.     } else {
  325.         sysplln.x.n = (uchar)atoi( param[ 0 ] ); // 7-bit value
  326.         syspllm.x.m = (uchar)atoi( param[ 1 ] ); // 5-bit value
  327.         syspllp.x.p = (uchar)atoi( param[ 2 ] ); // 2-bit value
  328.  
  329.           // The following code selects the proper value for the
  330.         // loop-filter "S" parameter
  331.           fv = fvco( sysplln.x.n, syspllm.x.m );
  332.           if ( fv < 50 )
  333.           {
  334.               msgout << "\n FVCO less than 50MHz!  Must be > 50MHz.";
  335.                cmd = _HELP;    // invalid FVCO value
  336.           } else if ( fv < 100 )
  337.               syspllp.x.s = 0;    // 50MHz < fvco < 100MHz ... S=0
  338.           else if ( fv < 140 )
  339.               syspllp.x.s = 1;    // 100MHz < fvco < 140MHz ... S=1
  340.           else if ( fv < 180 )
  341.               syspllp.x.s = 2;    // 140MHz < fvco < 180MHz ... S=2
  342.           else if ( fv < 220 )
  343.               syspllp.x.s = 3;    // 180MHz < fvco < 220MHz ... S=3
  344.     }
  345.  
  346.     switch ( cmd )    {
  347.         case _SET    :
  348.               // The following code is copied straight from the section of
  349.             // the 1064SG databook which covers System PLL programming
  350.                // The elaborate procedure prevents glitching while the
  351.                // system PLL locks onto the new frequency
  352.  
  353.             set_sysclkdis( 1 ) ;    // DISABLE system-clock
  354.               set_sysclksl( 0 );    // Select PCI-CLOCK -> system-clock
  355.                set_sysclkdis( 0 ) ;    // RE-ENABLE system-clock
  356.             write_cbyte( _SYSPLLM, syspllm.byte );    // write PLL register
  357.             write_cbyte( _SYSPLLN, sysplln.byte );    // write PLL register
  358.                write_cbyte( _SYSPLLP, syspllp.byte );    // write PLL register
  359.                while ( i < 32000 && ( ( read_cbyte( 0x2F ) & 0x40 ) == 0 ) )
  360.                 i++;    // wait until syslock = 1 ( lock achieved )
  361.             set_sysclkdis( 1 ) ;    // DISABLE system-clock
  362.               set_sysclksl( 1 );    // Re-select SYSPLL -> system-clock
  363.                set_sysclkdis( 0 ) ;    // RE-ENABLE system-clock
  364.  
  365.                if ( i >= 31999 )
  366.                    msgout << "\nError, could not synchronize to desired"
  367.                         << " frequency!";
  368.                else
  369.                {
  370.                     // Load the syspll* variables with respective MGA registers
  371.                  syspllm.x.m = read_cbyte( _SYSPLLM );
  372.                  sysplln.x.n = read_cbyte( _SYSPLLN );
  373.                  syspllp.x.p = read_cbyte( _SYSPLLP );
  374.                 msgout << "\nNew PLL clock = " << ( fvco( sysplln.x.n,
  375.                     syspllm.x.m ) / ( syspllp.x.p + 1.0 ) ) <<
  376.                     " MHz ( N=" << sysplln.x.n << ", M=" <<
  377.                     syspllm.x.m << ", P=" << syspllp.x.p << " )";
  378.                }
  379.             break;
  380.         case _GET :    case _HELP:    msgout
  381.              << "\nNote:  Mystique maximum system PLL clock (SCLK) = "
  382.              << "220MHz,\n\tThree inputs : N, M, P ( default : 132MHz )"
  383.              << "\n\tplease see mystique.txt for details!";
  384.             break;
  385.         default:
  386.             msgout << "_Mystique::_mclk(cmd)  UNRECOGNIZED cmd.";
  387.             status = EXIT_FAILURE;
  388.     }
  389.     msgout << ends;
  390. }
  391.  
  392.  
  393. void
  394. _Mystique::_fxn1( int cmd )    // Memory wait-state control (MGABASE1 + $1C08)
  395. {
  396.     INITMSG( msg.text );    // initialize msgout function
  397.  
  398.      union {
  399.           struct {
  400.               uchar b0;
  401.                uchar b1;
  402.                uchar b2;
  403.                uchar b3;
  404.           } b;
  405.           struct {
  406.                unsigned cas : 1;    // bit 0
  407.               unsigned reserved1 : 7;// bits 1-7
  408.                unsigned rcd : 1;    // bit 8
  409.               unsigned reserved2 : 7;// bits 9-15
  410.                unsigned ras : 2;    // bits 16-17
  411.               unsigned reserved3 : 14;// bits 18-31
  412.           } x;
  413.      } mctl;    // MCTLWTST Configuration register structure
  414.  
  415.     if ( cmd == _QUERY )    {
  416.         msgout<<"1  Mystique memory wait-state control (3 parameters)\n"
  417.             << ends;
  418.         return;
  419.     }
  420.  
  421.      mctl.b.b0 = read_indirect( 0x1C08 );    // MGABASE1 + $1C08
  422.      mctl.b.b1 = read_indirect( 0x1C09 );    // MGABASE1 + $1C08 + 1
  423.      mctl.b.b2 = read_indirect( 0x1C0A );    // MGABASE1 + $1C08 + 2
  424.      mctl.b.b3 = read_indirect( 0x1C0B );    // MGABASE1 + $1C08 + 3
  425.  
  426.     msgout << "Old RAS/CAS configuration :  CAS=" << (int)( mctl.x.cas ) <<
  427.          " RCD=" << (int)( mctl.x.rcd ) << " RAS=" << (int)( mctl.x.ras );
  428.  
  429.     if ( num_param < 3 && cmd == _SET )     {
  430.         msgout << "\nError!  Need THREE parameters for input!" ;
  431.         cmd = _HELP;
  432.     } else if ( num_param >= 3 ) {
  433.         mctl.x.cas = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  434.         mctl.x.rcd = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  435.         mctl.x.ras = ( (uchar)atoi( param[ 2 ] ) ) & 0x03;
  436.     }
  437.  
  438.  
  439.     switch ( cmd )    {
  440.         case _SET:    // Write new variables back to MGA register
  441.             write_indirect( 0x1C08, mctl.b.b0 );
  442.             write_indirect( 0x1C09, mctl.b.b1 );
  443.             write_indirect( 0x1C0A, mctl.b.b2 );
  444.             write_indirect( 0x1C0B, mctl.b.b3 );
  445.  
  446.                // Reread MCTLWTST register values
  447.              mctl.b.b0 = read_indirect( 0x1C08 );
  448.              mctl.b.b1 = read_indirect( 0x1C09 );
  449.              mctl.b.b2 = read_indirect( 0x1C0A );
  450.              mctl.b.b3 = read_indirect( 0x1C0B );
  451.             msgout << "\nNew RAS/CAS configuration :  CAS=" <<
  452.                 (int)( mctl.x.cas ) << " RCD=" << (int)( mctl.x.rcd )
  453.                 << " RAS=" << (int)( mctl.x.ras );
  454.             break;
  455.         case _GET:    case _HELP:
  456.             msgout << "\n\nMystique RAS/CAS configuration register\n\t" <<
  457.             "CAS = CAS Latency ( '0' = 2T delay, '1' = 3T delay)\n\t" <<
  458.             "RCD = RAS to CAS delay ( '0' = 2T delay, '1' = 3T delay)\n\t"
  459.             << "RAS = RAS minimum active time.\n\t\t'0' = 4 cycles" <<
  460.             "\n\t\t'1' = 5 cycles\n\t\t'2' = 6 cycles\n\t\t'3' = 7 cycles";
  461.             break;
  462.         default:    msgout << "_Mystique::_fxn1(cmd)  UNRECOGNIZED cmd.";
  463.             status = EXIT_FAILURE;
  464.     }
  465.     msgout << ends;    // Terminate msgout iostream with NULL
  466. }
  467.  
  468.  
  469. void
  470. _Mystique::_fxn2( int cmd )    // GCLK/MCLK Divide control (PCI CFG $40)
  471. {
  472.     INITMSG( msg.text );    // initialize msgout function
  473.  
  474.      union {
  475.           uchar byte;
  476.           struct {
  477.               unsigned other1 : 3;// bits 0-2
  478.                unsigned gclk : 1;    // bit 3
  479.                unsigned mclk : 1;    // bit 4
  480.               unsigned other2:3 ;// bits 5-7
  481.           } x;
  482.      } option;    // OPTION register (PCI_CFG $40)
  483.  
  484.     if ( cmd == _QUERY )    {
  485.         msgout<<"2  Mystique MCLK/GCLK divider control (2 parameters)\n"
  486.             << ends;
  487.         return;
  488.     }
  489.  
  490.      option.byte = read_cbyte( 0x40 );    // Read MGA PCI_CFG$40 register
  491.  
  492.     msgout << "Old GCLK divider : DIV/" << ( (option.x.gclk) ? "1" : "3" )
  493.          << "\tOld MCLK divider : DIV/" << ( (option.x.mclk) ? "1" : "2" );
  494.  
  495.     if ( num_param < 2 && cmd == _SET )     {
  496.         msgout << "\nError!  Need TWO parameters for input!" ;
  497.         cmd = _HELP;
  498.     } else if ( num_param >= 2 ) {
  499.         option.x.gclk =( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  500.  
  501.         option.x.mclk =( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  502.  
  503.     }
  504.  
  505.  
  506.     switch ( cmd )    {
  507.         case _SET:    // Write new variables back to MGA register
  508.               set_sysclkdis( 1 );    // Disable system-clock
  509.                write_cbyte( 0x40, option.byte );    // Write register
  510.                set_sysclkdis( 0 );    // Re-enable system-clock
  511.                option.byte = read_cbyte( 0x40 );    // Re-read register
  512.             msgout << "\nNew GCLK divider : DIV/" << ( (option.x.gclk) ?
  513.                 "1" : "3" ) << "\tNew MCLK divider : DIV/" <<
  514.                 ( (option.x.mclk) ? "1" : "2" );
  515.             break;
  516.         case _GET:    case _HELP:
  517.             msgout << "\n\nMystique Graphics clock & memory clock divider"
  518.                 << " control\n\t\tGCLK\t\tMCLK\n\t\t'0' = DIV/3\t" <<
  519.                     "'0' = DIV/2\n\t\t'1' = DIV/1\t'1' = DIV/1\n\n\t" <<
  520.                     "*** USE CAUTION WITH THESE CONTROLS!!! ***";
  521.             break;
  522.         default:    msgout << "_Mystique::_fxn2(cmd)  UNRECOGNIZED cmd.";
  523.             status = EXIT_FAILURE;
  524.     }
  525.     msgout << ends;    // Terminate msgout iostream with NULL
  526. }
  527.