home *** CD-ROM | disk | FTP | other *** search
- /* matrox.cpp 06/15/97 0.93ß
- *
- * Includes class definitions for Matrox Graphics, Inc.
- *
- * _Mystique - Matrox Mystique 1064SG
- * 3 settings
- *
- * _MCLK - The Mystique's clocking arrangement is unique. A single
- * "system PLL" drives two separate portions of the Mystique chipset.
- * The SGRAM memory-controller operates at one frequency ( PLL / 2 )
- * while the graphics-clock (datapath) operates at another ( PLL / 3 )
- * Thus, the system-PLL's frequency is twice the actual MCLK freq,
- * and three times the actual accelerator-engine frequency.
- *
- * None of this code has been tested yet...I hope it all works!
- *
- *
- *
- *
- *
-
- * v0.93ß first release
- */
-
- #include "matrox.h"
-
- #include<dos.h>
- #include<string.h>
- #include<stdio.h>
- #include<stdlib.h>
- #include<iostreams.h>
-
- #define _SYSPLLN 0x2D
- #define _SYSPLLM 0x2C
- #define _SYSPLLP 0x2E
-
- _Mystique::_Mystique( vga_info info ) : vga( info )
- {
- // not used
- }
-
-
- _Mystique::~_Mystique()
- {
- // not used
- }
-
-
- message
- _Mystique::_info( void )
- {
- INITMSG( msg.text );
-
- // msgout << "IO config address = 0x" ; // 32-bit absolute byte address
- // hexout( msgout, baseio.b.b3 ); // print reg.h.bl in "XX" format
- // hexout( msgout, baseio.b.b2 );
- // msgout << " ";
- msgout << ends ;
- return msg;
- }
-
-
- uchar
- _Mystique::read_cbyte( const uchar index )
- {
- uchar value, status = TRUE;
-
- status = pci_bios->read_cbyte( pci_vga, index, &value );
- return value;
- }
-
-
- uchar
- _Mystique::write_cbyte( const uchar index, const uchar value )
- {
- uchar status= TRUE;
-
- if ( pci_bios->write_cbyte( pci_vga, index, value ) != 0 )
- status = FALSE;
-
- return status;
- }
-
-
- uchar
- _Mystique::read_indirect( const uint index )
- {
- // The following data-structure, mga_index, represents the Mystique's
- // mga_index register, which is located at PCI_CFG $44.
- // union {
- // struct
- // {
- // uchar b0;
- // uchar b1;
- // } b; // data byte values
- //
- // struct
- // {
- // unsigned reserved1:2;
- // unsigned index:12;
- // unsigned reserved2:2;
- // } name; // Named bitfields
- // } mga_index; // 16-bit register
-
- // The following three lines effectively perform a read/modify/write
- // operation on the Mystique's MGA_INDEX register (PCI_CFG $44)
- mga_index_load(); // Load MGA registers into object mga_index()
-
- // Now write desired index-value into mga_index
- mga_index.name.index = ( index % 4 );
- // "index % 4" returns the remainder of (m_index DIV 4)
-
- mga_index_store(); // Write object contents back to MGA register
-
- // Ready to read the desired MGA indirect register
- // the DATA register at PCI-CFG $48 is a 32-bit (DWORD) register.
- // Since this routine parses a BYTE (and not DWORD) address, the
- // position of returned byte will depend on the desired address
-
- switch ( index % 4 )
- {
- case 0 : return read_cbyte( 0x48 ); // bits 0-7
- break;
- case 1 : return read_cbyte( 0x48 + 1); // bits 8-15
- break;
- case 2 : return read_cbyte( 0x48 + 2); // bits 16-23
- break;
- case 3 : return read_cbyte( 0x48 + 3); // bits 24-31
- break;
- default:
- ;
- };
- }
-
-
- uchar
- _Mystique::write_indirect( const uint index, const uchar value )
- {
- // The following data-structure, mga_index, represents the Mystique's
- // mga_index register, which is located at PCI_CFG $44.
- // union {
- // struct
- // {
- // uchar b0;
- // uchar b1;
- // } b; // data byte values
- //
- // struct
- // {
- // unsigned reserved1:2;
- // unsigned index:12;
- // unsigned reserved2:2;
- // } name; // Named bitfields
- // } mga_index; // 16-bit register
-
- mga_index_load(); // Load MGA registers into object mga_index()
-
- // Now write desired index-value into mga_index
- mga_index.name.index = ( index % 4 );
- // "index % 4" returns the remainder of (m_index DIV 4)
-
- mga_index_store(); // Write object contents back to MGA register
-
- // Ready to read the desired MGA indirect register
- // the DATA register at PCI-CFG $48 is a 32-bit (DWORD) register.
- // Since this routine parses a BYTE (and not DWORD) address, the
- // position of returned byte will depend on the desired address
-
- switch ( index % 4 )
- {
- case 0 : return write_cbyte( 0x48, value ); // bits 0-7
- break;
- case 1 : return write_cbyte( 0x48 + 1, value ); // bits 8-15
- break;
- case 2 : return write_cbyte( 0x48 + 2, value ); // bits 16-23
- break;
- case 3 : return write_cbyte( 0x48 + 3, value); // bits 24-31
- break;
- default:
- ;
- };
- }
-
-
- uchar
- _Mystique::read_x( const uchar index )
- {
- write_indirect( 0x3C00, index );
- // Load PALWTADD with desired-address
- return read_indirect( 0x3C0A );
- // Read X-reg from port (MGABASE1 + $3C0A)
- }
-
-
- uchar
- _Mystique::write_x( const uchar index, const uchar value )
- {
- write_indirect( 0x3C00, index );
- // Load PALWTADD with desired-address
- return write_indirect( 0x3C0A, value );
- // Write value -> (MGABASE1 + $3C0A)
- }
-
- // set_sysclkdis() will either ENABLE or DISABLE system-clock output,
- // depending on BIT. If BIT=0, clock-output is enabled. If BIT=1,
- // clock-output is disabled.
- // The bitfield sysclkdis is part of the OPTION byte, PCI_CFG $40 (bit2).
- void
- _Mystique::set_sysclkdis( uchar bit )
- {
- union {
- uchar byte;
- struct
- {
- unsigned other1:2;
- unsigned sysclkdis:1;
- unsigned other2:5;
- } name; // total of 8-bits
- } option; // OPTION byte
-
- option.byte = read_cbyte( 0x40 );
- option.name.sysclkdis = bit ;
- write_cbyte( 0x40 , option.byte );
- }
-
- // set_sysclksl() sets the Mystique's clock-source according to the
- // following table: input = bits
- // 00 select PCI clock
- // 01 select output of system clock PLL (on-board clock synthesizer)
- // 10 selects an external source from the MCLK pin
- // 11 reserved
- void
- _Mystique::set_sysclksl( uchar bits )
- {
- union {
- uchar byte;
- struct
- {
- unsigned sysclksl:2;
- unsigned other1:6;
- } name; // total of 8-bits
- } option; // OPTION byte
-
- option.byte = read_cbyte( 0x40 );
- option.name.sysclksl = bits;
- write_cbyte( 0x40, option.byte );
- }
-
-
- /*
- Formula for Mystique System PLL driver
-
- (sysplln + 1)
- FVCO = ------------- * 14.31818 MHz
- (syspllm + 1)
-
- where, final system-pll frequency is given by
-
- FVCO
- frequency( pll ) = -------------
- (syspllp + 1)
-
- sysplln, syspllm constitute control parameters in the feedback loop.
- syspllp is a post-divider circuit.
-
- Range of acceptable values:
- 100 <= sysplln <= 127 (feedback divider)
- 1 <= syspllm <= 31 (input divider)
- syspllp = { 0, 1, 3, 7 }
- */
-
-
- void
- _Mystique::_mclk( int cmd )
- {
- double fv; // Temporary fvco variable
- int i; // dummy loop variable
- union {
- uchar byte; // SYSPLLM register byte
- struct {
- unsigned m : 5; // PLL M prescalar value, 5-bits
- unsigned other : 3;
- } x;
- } syspllm;
-
- union {
- uchar byte; // SYSPLLN register byte
- struct {
- unsigned n : 7; // PLL N feedback-divider value, 7-bits
- unsigned other : 1;
- } x;
- } sysplln;
-
-
- union {
- uchar byte; // SYSPLLP register byte
- struct {
- unsigned p : 3; // PLL P post-divider value, 3-bits
- unsigned s : 2; // PLL S loop-filter value
- unsigned other : 3;
- } x;
- } syspllp;
-
- INITMSG( msg.text );
-
- if ( cmd == _QUERY ) {
- msgout << "0 Mystique MCLK programming\n" << ends;
- return;
- }
-
- // Load the syspll* variables with respective MGA registers
- sysplln.x.n = read_cbyte( _SYSPLLN );
- syspllm.x.m = read_cbyte( _SYSPLLM );
- syspllp.x.p = read_cbyte( _SYSPLLP );
-
- msgout.precision( 2 );
- msgout << "Old PLL clock = " << ( fvco( sysplln.x.n, syspllm.x.m ) /
- ( syspllp.x.p + 1.0 ) ) << " MHz ( N=" << sysplln.x.n <<
- ", M=" << syspllm.x.m << ", P=" << syspllp.x.p << " )";
-
- if ( num_param < 3 && cmd == _SET ) {
- msgout << "\n...not enough parameters, need total of 3.";
- cmd = _HELP; // Not enough parameters.
- } else {
- sysplln.x.n = (uchar)atoi( param[ 0 ] ); // 7-bit value
- syspllm.x.m = (uchar)atoi( param[ 1 ] ); // 5-bit value
- syspllp.x.p = (uchar)atoi( param[ 2 ] ); // 2-bit value
-
- // The following code selects the proper value for the
- // loop-filter "S" parameter
- fv = fvco( sysplln.x.n, syspllm.x.m );
- if ( fv < 50 )
- {
- msgout << "\n FVCO less than 50MHz! Must be > 50MHz.";
- cmd = _HELP; // invalid FVCO value
- } else if ( fv < 100 )
- syspllp.x.s = 0; // 50MHz < fvco < 100MHz ... S=0
- else if ( fv < 140 )
- syspllp.x.s = 1; // 100MHz < fvco < 140MHz ... S=1
- else if ( fv < 180 )
- syspllp.x.s = 2; // 140MHz < fvco < 180MHz ... S=2
- else if ( fv < 220 )
- syspllp.x.s = 3; // 180MHz < fvco < 220MHz ... S=3
- }
-
- switch ( cmd ) {
- case _SET :
- // The following code is copied straight from the section of
- // the 1064SG databook which covers System PLL programming
- // The elaborate procedure prevents glitching while the
- // system PLL locks onto the new frequency
-
- set_sysclkdis( 1 ) ; // DISABLE system-clock
- set_sysclksl( 0 ); // Select PCI-CLOCK -> system-clock
- set_sysclkdis( 0 ) ; // RE-ENABLE system-clock
- write_cbyte( _SYSPLLM, syspllm.byte ); // write PLL register
- write_cbyte( _SYSPLLN, sysplln.byte ); // write PLL register
- write_cbyte( _SYSPLLP, syspllp.byte ); // write PLL register
- while ( i < 32000 && ( ( read_cbyte( 0x2F ) & 0x40 ) == 0 ) )
- i++; // wait until syslock = 1 ( lock achieved )
- set_sysclkdis( 1 ) ; // DISABLE system-clock
- set_sysclksl( 1 ); // Re-select SYSPLL -> system-clock
- set_sysclkdis( 0 ) ; // RE-ENABLE system-clock
-
- if ( i >= 31999 )
- msgout << "\nError, could not synchronize to desired"
- << " frequency!";
- else
- {
- // Load the syspll* variables with respective MGA registers
- syspllm.x.m = read_cbyte( _SYSPLLM );
- sysplln.x.n = read_cbyte( _SYSPLLN );
- syspllp.x.p = read_cbyte( _SYSPLLP );
- msgout << "\nNew PLL clock = " << ( fvco( sysplln.x.n,
- syspllm.x.m ) / ( syspllp.x.p + 1.0 ) ) <<
- " MHz ( N=" << sysplln.x.n << ", M=" <<
- syspllm.x.m << ", P=" << syspllp.x.p << " )";
- }
- break;
- case _GET : case _HELP: msgout
- << "\nNote: Mystique maximum system PLL clock (SCLK) = "
- << "220MHz,\n\tThree inputs : N, M, P ( default : 132MHz )"
- << "\n\tplease see mystique.txt for details!";
- break;
- default:
- msgout << "_Mystique::_mclk(cmd) UNRECOGNIZED cmd.";
- status = EXIT_FAILURE;
- }
- msgout << ends;
- }
-
-
- void
- _Mystique::_fxn1( int cmd ) // Memory wait-state control (MGABASE1 + $1C08)
- {
- INITMSG( msg.text ); // initialize msgout function
-
- union {
- struct {
- uchar b0;
- uchar b1;
- uchar b2;
- uchar b3;
- } b;
- struct {
- unsigned cas : 1; // bit 0
- unsigned reserved1 : 7;// bits 1-7
- unsigned rcd : 1; // bit 8
- unsigned reserved2 : 7;// bits 9-15
- unsigned ras : 2; // bits 16-17
- unsigned reserved3 : 14;// bits 18-31
- } x;
- } mctl; // MCTLWTST Configuration register structure
-
- if ( cmd == _QUERY ) {
- msgout<<"1 Mystique memory wait-state control (3 parameters)\n"
- << ends;
- return;
- }
-
- mctl.b.b0 = read_indirect( 0x1C08 ); // MGABASE1 + $1C08
- mctl.b.b1 = read_indirect( 0x1C09 ); // MGABASE1 + $1C08 + 1
- mctl.b.b2 = read_indirect( 0x1C0A ); // MGABASE1 + $1C08 + 2
- mctl.b.b3 = read_indirect( 0x1C0B ); // MGABASE1 + $1C08 + 3
-
- msgout << "Old RAS/CAS configuration : CAS=" << (int)( mctl.x.cas ) <<
- " RCD=" << (int)( mctl.x.rcd ) << " RAS=" << (int)( mctl.x.ras );
-
- if ( num_param < 3 && cmd == _SET ) {
- msgout << "\nError! Need THREE parameters for input!" ;
- cmd = _HELP;
- } else if ( num_param >= 3 ) {
- mctl.x.cas = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
- mctl.x.rcd = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
- mctl.x.ras = ( (uchar)atoi( param[ 2 ] ) ) & 0x03;
- }
-
-
- switch ( cmd ) {
- case _SET: // Write new variables back to MGA register
- write_indirect( 0x1C08, mctl.b.b0 );
- write_indirect( 0x1C09, mctl.b.b1 );
- write_indirect( 0x1C0A, mctl.b.b2 );
- write_indirect( 0x1C0B, mctl.b.b3 );
-
- // Reread MCTLWTST register values
- mctl.b.b0 = read_indirect( 0x1C08 );
- mctl.b.b1 = read_indirect( 0x1C09 );
- mctl.b.b2 = read_indirect( 0x1C0A );
- mctl.b.b3 = read_indirect( 0x1C0B );
- msgout << "\nNew RAS/CAS configuration : CAS=" <<
- (int)( mctl.x.cas ) << " RCD=" << (int)( mctl.x.rcd )
- << " RAS=" << (int)( mctl.x.ras );
- break;
- case _GET: case _HELP:
- msgout << "\n\nMystique RAS/CAS configuration register\n\t" <<
- "CAS = CAS Latency ( '0' = 2T delay, '1' = 3T delay)\n\t" <<
- "RCD = RAS to CAS delay ( '0' = 2T delay, '1' = 3T delay)\n\t"
- << "RAS = RAS minimum active time.\n\t\t'0' = 4 cycles" <<
- "\n\t\t'1' = 5 cycles\n\t\t'2' = 6 cycles\n\t\t'3' = 7 cycles";
- break;
- default: msgout << "_Mystique::_fxn1(cmd) UNRECOGNIZED cmd.";
- status = EXIT_FAILURE;
- }
- msgout << ends; // Terminate msgout iostream with NULL
- }
-
-
- void
- _Mystique::_fxn2( int cmd ) // GCLK/MCLK Divide control (PCI CFG $40)
- {
- INITMSG( msg.text ); // initialize msgout function
-
- union {
- uchar byte;
- struct {
- unsigned other1 : 3;// bits 0-2
- unsigned gclk : 1; // bit 3
- unsigned mclk : 1; // bit 4
- unsigned other2:3 ;// bits 5-7
- } x;
- } option; // OPTION register (PCI_CFG $40)
-
- if ( cmd == _QUERY ) {
- msgout<<"2 Mystique MCLK/GCLK divider control (2 parameters)\n"
- << ends;
- return;
- }
-
- option.byte = read_cbyte( 0x40 ); // Read MGA PCI_CFG$40 register
-
- msgout << "Old GCLK divider : DIV/" << ( (option.x.gclk) ? "1" : "3" )
- << "\tOld MCLK divider : DIV/" << ( (option.x.mclk) ? "1" : "2" );
-
- if ( num_param < 2 && cmd == _SET ) {
- msgout << "\nError! Need TWO parameters for input!" ;
- cmd = _HELP;
- } else if ( num_param >= 2 ) {
- option.x.gclk =( (uchar)atoi( param[ 0 ] ) ) & 0x01;
-
- option.x.mclk =( (uchar)atoi( param[ 1 ] ) ) & 0x01;
-
- }
-
-
- switch ( cmd ) {
- case _SET: // Write new variables back to MGA register
- set_sysclkdis( 1 ); // Disable system-clock
- write_cbyte( 0x40, option.byte ); // Write register
- set_sysclkdis( 0 ); // Re-enable system-clock
- option.byte = read_cbyte( 0x40 ); // Re-read register
- msgout << "\nNew GCLK divider : DIV/" << ( (option.x.gclk) ?
- "1" : "3" ) << "\tNew MCLK divider : DIV/" <<
- ( (option.x.mclk) ? "1" : "2" );
- break;
- case _GET: case _HELP:
- msgout << "\n\nMystique Graphics clock & memory clock divider"
- << " control\n\t\tGCLK\t\tMCLK\n\t\t'0' = DIV/3\t" <<
- "'0' = DIV/2\n\t\t'1' = DIV/1\t'1' = DIV/1\n\n\t" <<
- "*** USE CAUTION WITH THESE CONTROLS!!! ***";
- break;
- default: msgout << "_Mystique::_fxn2(cmd) UNRECOGNIZED cmd.";
- status = EXIT_FAILURE;
- }
- msgout << ends; // Terminate msgout iostream with NULL
- }
-