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