750 lines
29 KiB
C
750 lines
29 KiB
C
/*-*-c++-*-*/
|
|
/*
|
|
** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
|
|
** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
|
|
** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
|
|
** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
|
|
** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
|
|
** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
|
|
** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
|
|
**
|
|
** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
|
|
** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
|
|
** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
|
|
** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
|
|
** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
|
|
** THE UNITED STATES.
|
|
**
|
|
** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
|
|
**
|
|
**
|
|
** $Revision$
|
|
** $Date$
|
|
**
|
|
** Initialization code for initializing scanline interleaving
|
|
**
|
|
*/
|
|
#ifdef __WIN32__
|
|
#pragma optimize ("",off)
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#ifdef BUILD_FOR_SST1
|
|
#include <sst.h>
|
|
#else
|
|
#include <3dfx.h>
|
|
#include <cvgregs.h>
|
|
#include <cvgdefs.h>
|
|
#endif
|
|
#define FX_DLL_DEFINITION
|
|
#include <fxdll.h>
|
|
#include <sst1vid.h>
|
|
#include <sst1init.h>
|
|
|
|
/*
|
|
** sst1InitSli():
|
|
** Setup Multiple SST-1 subsystems for Scanline Interleaving
|
|
** sstbase0 defined to be the SLI Master
|
|
** sstbase1 defined to be the SLI Slave
|
|
**
|
|
*/
|
|
FX_EXPORT FxBool FX_CSTYLE sst1InitSli(FxU32 *sstbase0, FxU32 *sstbase1)
|
|
{
|
|
FxU32 j, n, MasterPhysAddr, cntr;
|
|
SstRegs *sstMaster = (SstRegs *) sstbase0;
|
|
SstRegs *sstSlave = (SstRegs *) sstbase1;
|
|
FxU32 masterVInClkDel, masterVOutClkDel;
|
|
FxU32 slaveVInClkDel, slaveVOutClkDel;
|
|
FxU32 masterPVOutClkDel, slavePVOutClkDel;
|
|
FxU32 pciFifoLwm, memFifoLwm;
|
|
FxU32 memOffsetOrig, tilesInXOrig;
|
|
FxU32 memOffsetNew;
|
|
int memFifoEntriesNew;
|
|
FxU32 memSizeInPages;
|
|
FxU32 memFifoRowBaseNew;
|
|
FxU32 swapAlgorithm = SST_SWAP_SLISYNC;
|
|
FxU32 videoWindowActive = 0x1;
|
|
FxU32 videoWindowActiveDrag = 0xf;
|
|
sst1DeviceInfoStruct *sst1M, *sst1S;
|
|
int i;
|
|
|
|
if(sst1InitCheckBoard(sstbase1) == FXFALSE)
|
|
return(FXFALSE);
|
|
if(!sst1CurrentBoard->sliDetected)
|
|
return(FXFALSE);
|
|
sst1S = sst1CurrentBoard;
|
|
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
if(!sst1CurrentBoard->sliDetected)
|
|
return(FXFALSE);
|
|
sst1M = sst1CurrentBoard;
|
|
|
|
// Verify that the board configurations are identical
|
|
//
|
|
// NB: Some of the tests are no longer necessary because
|
|
// the init code clients are doing the magic to make the
|
|
// board appear as the minimum value for things like memory.
|
|
if(/* (sst1M->fbiMemSize != sst1S->fbiMemSize) || */
|
|
/*(sst1M->tmuMemSize[0] != sst1S->tmuMemSize[0]) || */
|
|
(sst1M->numberTmus != sst1S->numberTmus) ||
|
|
/* [koolsmoky] mismatched SLI support */
|
|
(!GETENV(("SSTV2_MISMATCHED_SLI")) && (sst1M->fbiBoardID != sst1S->fbiBoardID)) ||
|
|
/* (sst1M->fbiRevision != sst1S->fbiRevision) || */
|
|
/* (sst1M->tmuRevision != sst1S->tmuRevision) || */
|
|
(sst1M->fbiVideoStruct != sst1S->fbiVideoStruct)) {
|
|
INIT_PRINTF(("sst1InitSli() ERROR: Boards types must be identical...\n"));
|
|
return(FXFALSE);
|
|
}
|
|
|
|
// Verify that no video scanline doubling is being used...
|
|
if(sst1M->fbiVideoStruct->miscCtrl & BIT(1)) {
|
|
INIT_PRINTF(("sst1InitSli() ERROR: Scanline doubling not supported with SLI...\n"));
|
|
return(FXFALSE);
|
|
}
|
|
|
|
INIT_PRINTF(("sst1InitSli(): Enabling Scanline Interleaving...\n"));
|
|
|
|
// sst1Initidle() routines must be properly executed...
|
|
initIdleEnabled = 1;
|
|
|
|
// User override of swap algorithm...
|
|
if(GETENV(("SSTV2_SLISWAP"))) {
|
|
FxU32 swapAlg = ATOI(GETENV(("SSTV2_SLISWAP")));
|
|
|
|
if(swapAlg == 1) {
|
|
INIT_PRINTF(("sst1InitSli(): Using dac_data[0] for swapping(%d, %d)...\n", videoWindowActive, videoWindowActiveDrag));
|
|
swapAlgorithm = SST_SWAP_DACDATA0;
|
|
}
|
|
}
|
|
|
|
// Get values setup by sst1InitVideo()...
|
|
memOffsetOrig = (IGET(sstMaster->fbiInit2) & SST_VIDEO_BUFFER_OFFSET) >>
|
|
SST_VIDEO_BUFFER_OFFSET_SHIFT;
|
|
tilesInXOrig = (IGET(sstMaster->fbiInit1) & SST_VIDEO_TILES_IN_X) >>
|
|
SST_VIDEO_TILES_IN_X_SHIFT;
|
|
if(IGET(sstMaster->fbiInit1) & SST_VIDEO_TILES_IN_X_MSB)
|
|
tilesInXOrig += 16;
|
|
|
|
if(tilesInXOrig & 0x1) {
|
|
// (e.g. 800x600 resolution)
|
|
/*
|
|
Integer formula for:
|
|
memOffset =
|
|
(TRUNC((xDimension/64)+.99) *
|
|
TRUNC((((yDimension/2)+1)/32)+.99))
|
|
*/
|
|
memOffsetNew = (tilesInXOrig *
|
|
((((sst1CurrentBoard->fbiVideoHeight>>1)+1) + 31) >> 5));
|
|
} else {
|
|
// (e.g. 640x480 resolution)
|
|
// Calculate number of tiles in the vertical dimension
|
|
// Must add entire row of tiles at the bottom for fixes for
|
|
// Y-Origin at lower left
|
|
memOffsetNew = tilesInXOrig *
|
|
(((sst1CurrentBoard->fbiVideoHeight >> 1) + 32) >> 5);
|
|
}
|
|
|
|
if(sst1CurrentBoard->fbiMemSize == 1)
|
|
memSizeInPages = 256;
|
|
else if(sst1CurrentBoard->fbiMemSize == 2)
|
|
memSizeInPages = 512;
|
|
else
|
|
memSizeInPages = 1024;
|
|
|
|
memFifoRowBaseNew = (sst1CurrentBoard->fbiVideoColBuffs +
|
|
sst1CurrentBoard->fbiVideoAuxBuffs) * memOffsetNew;
|
|
|
|
memFifoEntriesNew = (65536 - (int)
|
|
(((int) (memSizeInPages - 1) -
|
|
(int) memFifoRowBaseNew) * 512)) >> 5;
|
|
if(memFifoEntriesNew <= 256)
|
|
memFifoEntriesNew = 0x100; // max. memory fifo size...
|
|
else if(memFifoEntriesNew >= 2048) {
|
|
INIT_PRINTF(("sst1InitSli(): Invalid memFifoEntriesNew 0x%x\n",
|
|
memFifoEntriesNew));
|
|
return(FXFALSE);
|
|
}
|
|
|
|
INIT_PRINTF(("sst1InitSli(): Allocating %d Color Buffers and %d Aux Buffer(s)...\n", sst1CurrentBoard->fbiVideoColBuffs, sst1CurrentBoard->fbiVideoAuxBuffs));
|
|
INIT_PRINTF(("sst1InitSli(): Allocating Memory/Command Fifo starting at page %d...\n", memFifoRowBaseNew));
|
|
INIT_PRINTF(("sst1InitSli(): Memory FIFO Entries: %d...\n",
|
|
65536 - (memFifoEntriesNew << 5)));
|
|
#if 0
|
|
INIT_PRINTF(("sst1InitSli(): memOffsetOrig:%d, tilesInXOrig:%d\n",
|
|
memOffsetOrig, tilesInXOrig));
|
|
INIT_PRINTF(("sst1InitSli(): memOffsetNew:%d, memFifoEntriesNew:0x%x\n",
|
|
memOffsetNew, memFifoEntriesNew));
|
|
#endif
|
|
|
|
// Setup SLI Slave...
|
|
cntr = 0;
|
|
while(1) {
|
|
if(sst1InitCheckBoard(sstbase1) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE,
|
|
((j & ~SST_SCANLINE_SLV_OWNPCI) | SST_SCANLINE_SLI_SLV));
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) |
|
|
(SST_VIDEO_RESET | SST_EN_SCANLINE_INTERLEAVE));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(SST_TREX(sstSlave,0)->trexInit1, sst1CurrentBoard->tmuInit1[0] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE | SST_TEX_SCANLINE_INTERLEAVE_SLAVE);
|
|
sst1InitIdle(sstbase1);
|
|
ISET(SST_TREX(sstSlave,1)->trexInit1, sst1CurrentBoard->tmuInit1[1] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE | SST_TEX_SCANLINE_INTERLEAVE_SLAVE);
|
|
sst1InitIdle(sstbase1);
|
|
ISET(SST_TREX(sstSlave,2)->trexInit1, sst1CurrentBoard->tmuInit1[2] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE | SST_TEX_SCANLINE_INTERLEAVE_SLAVE);
|
|
sst1InitIdle(sstbase1);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit2, (IGET(sstSlave->fbiInit2) &
|
|
~SST_SWAP_ALGORITHM) | swapAlgorithm);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
// Initialize Y-Origin
|
|
ISET(sstSlave->fbiInit3, (IGET(sstSlave->fbiInit3) & ~SST_YORIGIN_TOP) |
|
|
(sst1CurrentBoard->fbiVideoHeight << SST_YORIGIN_TOP_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit2, (IGET(sstSlave->fbiInit2) &
|
|
~SST_VIDEO_BUFFER_OFFSET) |
|
|
(memOffsetNew << SST_VIDEO_BUFFER_OFFSET_SHIFT));
|
|
sst1CurrentBoard->fbiVideoMemOffset = memOffsetNew;
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
// Initialize memory fifo
|
|
ISET(sstSlave->fbiInit0, (IGET(sstSlave->fbiInit0) &
|
|
~SST_MEM_FIFO_HWM) | (memFifoEntriesNew << SST_MEM_FIFO_HWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit4, (IGET(sstSlave->fbiInit4) &
|
|
~SST_MEM_FIFO_ROW_BASE) |
|
|
(memFifoRowBaseNew << SST_MEM_FIFO_ROW_BASE_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
// Fix video dimensions
|
|
ISET(sstSlave->videoDimensions,
|
|
(((sst1CurrentBoard->fbiVideoHeight+2) << SST_VIDEO_YDIM_SHIFT) |
|
|
((sst1CurrentBoard->fbiVideoWidth-1) << SST_VIDEO_XDIM_SHIFT)));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
// Setup video clocks
|
|
ISET(sstSlave->fbiInit5, (IGET(sstSlave->fbiInit5) &
|
|
~(SST_VIDEO_CLK_SLAVE_OE_EN | SST_VID_CLK_2X_OUT_OE_EN)) |
|
|
SST_VID_CLK_DAC_DATA16_SEL);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) &
|
|
~SST_VIDEO_VID_CLK_SLAVE);
|
|
sst1CurrentBoard->fbiInit6 &= ~SST_SLI_SYNC_MASTER;
|
|
sst1CurrentBoard->fbiInit6 = ((sst1CurrentBoard->fbiInit6 &
|
|
~(SST_SLI_SWAP_VACTIVE | SST_SLI_SWAP_VACTIVE_DRAG)) |
|
|
(videoWindowActive<<SST_SLI_SWAP_VACTIVE_SHIFT) |
|
|
(videoWindowActiveDrag<<SST_SLI_SWAP_VACTIVE_DRAG_SHIFT));
|
|
ISET(sstSlave->fbiInit6, sst1CurrentBoard->fbiInit6);
|
|
|
|
slaveVInClkDel = 0;
|
|
slaveVOutClkDel = 0;
|
|
slavePVOutClkDel = 0;
|
|
|
|
if(GETENV(("SSTV2_SLIS_VOUT_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIS_VOUT_CLKDEL")), "%i", &i) == 1))
|
|
slaveVOutClkDel = i;
|
|
if(GETENV(("SSTV2_SLIS_PVOUT_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIS_PVOUT_CLKDEL")), "%i", &i) == 1))
|
|
slavePVOutClkDel = i;
|
|
if(GETENV(("SSTV2_SLIS_VIN_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIS_VIN_CLKDEL")), "%i", &i) == 1))
|
|
slaveVInClkDel = i;
|
|
INIT_PRINTF(("sst1InitSli(): slaveVinClkdel=0x%x, slaveVOutClkDel=0x%x, slavePVOutClkDel=0x%x\n",
|
|
slaveVInClkDel, slaveVOutClkDel, slavePVOutClkDel));
|
|
if(sst1CurrentBoard->fbiVideo16BPP)
|
|
// 16-bit Video Output
|
|
ISET(sstSlave->fbiInit1, (IGET(sstSlave->fbiInit1) &
|
|
~(SST_VIDEO_VCLK_2X_OUTPUT_DEL | SST_VIDEO_VCLK_DEL |
|
|
SST_VIDEO_VCLK_SEL | SST_VIDEO_VCLK_2X_INPUT_DEL)) |
|
|
SST_EN_SCANLINE_INTERLEAVE |
|
|
// SST_VIDEO_VID_CLK_SLAVE |
|
|
// SST_VIDEO_VID_CLK_2X |
|
|
// SST_VIDEO_INVERT_VID_CLK_2X |
|
|
SST_VIDEO_VCLK_SEL |
|
|
SST_PCI_WRWS_1 |
|
|
(slaveVInClkDel << SST_VIDEO_VCLK_DEL_SHIFT) |
|
|
(slaveVOutClkDel << SST_VIDEO_VCLK_2X_OUTPUT_DEL_SHIFT) |
|
|
(slavePVOutClkDel << SST_VIDEO_VCLK_2X_INPUT_DEL_SHIFT));
|
|
else
|
|
// 24-bit Video Output
|
|
ISET(sstSlave->fbiInit1, (IGET(sstSlave->fbiInit1) &
|
|
~(SST_VIDEO_VCLK_2X_OUTPUT_DEL | SST_VIDEO_VCLK_DEL |
|
|
SST_VIDEO_VCLK_SEL | SST_VIDEO_VCLK_2X_INPUT_DEL)) |
|
|
SST_EN_SCANLINE_INTERLEAVE |
|
|
// SST_VIDEO_VID_CLK_SLAVE |
|
|
// SST_VIDEO_VID_CLK_2X |
|
|
// SST_VIDEO_INVERT_VID_CLK_2X |
|
|
(0x0 << SST_VIDEO_VCLK_SEL_SHIFT) |
|
|
SST_PCI_WRWS_1 |
|
|
(slaveVInClkDel << SST_VIDEO_VCLK_DEL_SHIFT) |
|
|
(slaveVOutClkDel << SST_VIDEO_VCLK_2X_OUTPUT_DEL_SHIFT) |
|
|
(slavePVOutClkDel << SST_VIDEO_VCLK_2X_INPUT_DEL_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) &
|
|
~(SST_VIDEO_DATA_OE_EN |
|
|
SST_VIDEO_BLANK_OE_EN |
|
|
SST_VIDEO_BLANK_EN |
|
|
SST_VIDEO_DCLK_OE_EN |
|
|
SST_VIDEO_HVSYNC_OE_EN));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
// Initialize pci and memory fifos...
|
|
pciFifoLwm = 16;
|
|
memFifoLwm = 26;
|
|
if(!GETENV(("SSTV2_PCIFIFO_LWM")))
|
|
ISET(sstSlave->fbiInit0, (IGET(sstSlave->fbiInit0) &
|
|
~SST_PCI_FIFO_LWM) | (pciFifoLwm << SST_PCI_FIFO_LWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
if(!GETENV(("SSTV2_MEMFIFO_LWM")))
|
|
ISET(sstSlave->fbiInit4, (IGET(sstSlave->fbiInit4) &
|
|
~SST_MEM_FIFO_LWM) | (memFifoLwm << SST_MEM_FIFO_LWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
INIT_PRINTF(("sst1InitSli(): Slave pciFifoLwm:%d, memFifoLwm:%d\n",
|
|
((IGET(sstSlave->fbiInit0) & SST_PCI_FIFO_LWM) >>
|
|
SST_PCI_FIFO_LWM_SHIFT),
|
|
((IGET(sstSlave->fbiInit4) & SST_MEM_FIFO_LWM) >>
|
|
SST_MEM_FIFO_LWM_SHIFT)));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) |
|
|
(SST_EN_SCANLINE_INTERLEAVE | SST_VIDEO_RESET));
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) & ~SST_VIDEO_RESET);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
sst1InitIdleFBINoNOP(sstbase1);
|
|
if(IGET(sstSlave->fbiInit1) & SST_VIDEO_RESET) {
|
|
INIT_PRINTF(("sst1InitSli(): Could not unReset Slave Video...\n"));
|
|
if(++cntr < 10)
|
|
continue;
|
|
else
|
|
return(FXFALSE);
|
|
}
|
|
if(!(IGET(sstSlave->fbiInit1) & SST_EN_SCANLINE_INTERLEAVE)) {
|
|
INIT_PRINTF(("sst1InitSli(): Could not setup SLI Slave...\n"));
|
|
if(++cntr < 10)
|
|
continue;
|
|
else
|
|
return(FXFALSE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Setup SLI Master...
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) | SST_VIDEO_RESET);
|
|
ISET(SST_TREX(sstMaster,0)->trexInit1, sst1CurrentBoard->tmuInit1[0] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE);
|
|
sst1InitIdle(sstbase0);
|
|
ISET(SST_TREX(sstMaster,1)->trexInit1, sst1CurrentBoard->tmuInit1[1] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE);
|
|
sst1InitIdle(sstbase0);
|
|
ISET(SST_TREX(sstMaster,2)->trexInit1, sst1CurrentBoard->tmuInit1[2] |
|
|
SST_EN_TEX_SCANLINE_INTERLEAVE);
|
|
sst1InitIdle(sstbase0);
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
ISET(sstMaster->fbiInit2, (IGET(sstMaster->fbiInit2) &
|
|
~SST_SWAP_ALGORITHM) | swapAlgorithm);
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
// Initialize Y-Origin
|
|
ISET(sstMaster->fbiInit3, (IGET(sstMaster->fbiInit3) & ~SST_YORIGIN_TOP) |
|
|
((sst1CurrentBoard->fbiVideoHeight) << SST_YORIGIN_TOP_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
if(sst1CurrentBoard->fbiVideoWidth == 960)
|
|
ISET(sstMaster->fbiInit0, IGET(sstMaster->fbiInit0) & ~SST_MEM_FIFO_EN);
|
|
ISET(sstMaster->fbiInit2, (IGET(sstMaster->fbiInit2) &
|
|
~SST_VIDEO_BUFFER_OFFSET) |
|
|
(memOffsetNew << SST_VIDEO_BUFFER_OFFSET_SHIFT));
|
|
sst1CurrentBoard->fbiVideoMemOffset = memOffsetNew;
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
// // Initialize memory fifo
|
|
ISET(sstMaster->fbiInit0, (IGET(sstMaster->fbiInit0) & ~SST_MEM_FIFO_HWM) |
|
|
(memFifoEntriesNew << SST_MEM_FIFO_HWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
ISET(sstMaster->fbiInit4, (IGET(sstMaster->fbiInit4) &
|
|
~SST_MEM_FIFO_ROW_BASE) |
|
|
(memFifoRowBaseNew << SST_MEM_FIFO_ROW_BASE_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
// Fix video dimensions
|
|
ISET(sstMaster->videoDimensions,
|
|
(((sst1CurrentBoard->fbiVideoHeight+2) << SST_VIDEO_YDIM_SHIFT) |
|
|
((sst1CurrentBoard->fbiVideoWidth-1) << SST_VIDEO_XDIM_SHIFT)));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
// Setup video clocks
|
|
ISET(sstMaster->fbiInit5, IGET(sstMaster->fbiInit5) |
|
|
SST_VIDEO_CLK_SLAVE_OE_EN | SST_VID_CLK_2X_OUT_OE_EN |
|
|
SST_VID_CLK_DAC_DATA16_SEL);
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) &
|
|
~SST_VIDEO_VID_CLK_SLAVE);
|
|
sst1CurrentBoard->fbiInit6 |= SST_SLI_SYNC_MASTER;
|
|
sst1CurrentBoard->fbiInit6 = ((sst1CurrentBoard->fbiInit6 &
|
|
~(SST_SLI_SWAP_VACTIVE | SST_SLI_SWAP_VACTIVE_DRAG)) |
|
|
(videoWindowActive<<SST_SLI_SWAP_VACTIVE_SHIFT) |
|
|
(videoWindowActiveDrag<<SST_SLI_SWAP_VACTIVE_DRAG_SHIFT));
|
|
ISET(sstMaster->fbiInit6, sst1CurrentBoard->fbiInit6);
|
|
|
|
// Following work well up to around 100 MHz...
|
|
// masterVInClkDel = 2;
|
|
// masterVOutClkDel = 0;
|
|
// masterPVOutClkDel = 0;
|
|
// Following seem to work up to 800x600@85 Hz (112 MHz)
|
|
masterVInClkDel = 3;
|
|
masterVOutClkDel = 2;
|
|
masterPVOutClkDel = 0;
|
|
if(GETENV(("SSTV2_SLIM_VOUT_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIM_VOUT_CLKDEL")), "%i", &i) == 1))
|
|
masterVOutClkDel = i;
|
|
if(GETENV(("SSTV2_SLIM_PVOUT_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIM_PVOUT_CLKDEL")), "%i", &i) == 1))
|
|
masterPVOutClkDel = i;
|
|
if(GETENV(("SSTV2_SLIM_VIN_CLKDEL")) &&
|
|
(SSCANF(GETENV(("SSTV2_SLIM_VIN_CLKDEL")), "%i", &i) == 1))
|
|
masterVInClkDel = i;
|
|
INIT_PRINTF(("sst1InitSli(): masterVinClkdel=0x%x, masterVOutClkDel=0x%x, masterPVOutClkDel=0x%x\n",
|
|
masterVInClkDel, masterVOutClkDel, masterPVOutClkDel));
|
|
if(sst1CurrentBoard->fbiVideo16BPP)
|
|
// 16-bit Video Output
|
|
ISET(sstMaster->fbiInit1, (IGET(sstMaster->fbiInit1) &
|
|
~(SST_VIDEO_VCLK_2X_OUTPUT_DEL | SST_VIDEO_VCLK_DEL |
|
|
SST_VIDEO_VCLK_SEL | SST_VIDEO_VCLK_2X_INPUT_DEL |
|
|
SST_VIDEO_BLANK_EN)) |
|
|
SST_EN_SCANLINE_INTERLEAVE |
|
|
// SST_VIDEO_VID_CLK_2X |
|
|
// SST_VIDEO_INVERT_VID_CLK_2X |
|
|
SST_VIDEO_VCLK_SEL |
|
|
SST_PCI_WRWS_1 |
|
|
SST_VIDEO_DATA_OE_EN |
|
|
SST_VIDEO_DCLK_OE_EN |
|
|
SST_VIDEO_HVSYNC_OE_EN |
|
|
(masterVInClkDel << SST_VIDEO_VCLK_DEL_SHIFT) |
|
|
(masterVOutClkDel << SST_VIDEO_VCLK_2X_OUTPUT_DEL_SHIFT) |
|
|
(masterPVOutClkDel << SST_VIDEO_VCLK_2X_INPUT_DEL_SHIFT));
|
|
else {
|
|
// 24-bit Video Output
|
|
ISET(sstMaster->fbiInit1, (IGET(sstMaster->fbiInit1) &
|
|
~(SST_VIDEO_VCLK_2X_OUTPUT_DEL | SST_VIDEO_VCLK_DEL |
|
|
SST_VIDEO_VCLK_SEL | SST_VIDEO_VCLK_2X_INPUT_DEL |
|
|
SST_VIDEO_BLANK_EN)) |
|
|
SST_EN_SCANLINE_INTERLEAVE |
|
|
// SST_VIDEO_VID_CLK_2X |
|
|
// SST_VIDEO_INVERT_VID_CLK_2X |
|
|
(0x0 << SST_VIDEO_VCLK_SEL_SHIFT) |
|
|
SST_PCI_WRWS_1 |
|
|
SST_VIDEO_DATA_OE_EN |
|
|
SST_VIDEO_DCLK_OE_EN |
|
|
SST_VIDEO_HVSYNC_OE_EN |
|
|
(masterVInClkDel << SST_VIDEO_VCLK_DEL_SHIFT) |
|
|
(masterVOutClkDel << SST_VIDEO_VCLK_2X_OUTPUT_DEL_SHIFT) |
|
|
(masterPVOutClkDel << SST_VIDEO_VCLK_2X_INPUT_DEL_SHIFT));
|
|
sst1InitReturnStatus(sstbase0);
|
|
ISET(sstMaster->fbiInit5, IGET(sstMaster->fbiInit5) |
|
|
SST_VIDEO_CLK_SLAVE_OE_EN | SST_VID_CLK_2X_OUT_OE_EN);
|
|
}
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
// Initialize pci and memory fifos...
|
|
pciFifoLwm = 16;
|
|
memFifoLwm = 26;
|
|
if(!GETENV(("SSTV2_PCIFIFO_LWM")))
|
|
ISET(sstMaster->fbiInit0, (IGET(sstMaster->fbiInit0) &
|
|
~SST_PCI_FIFO_LWM) | (pciFifoLwm << SST_PCI_FIFO_LWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
if(!GETENV(("SSTV2_MEMFIFO_LWM")))
|
|
ISET(sstMaster->fbiInit4, (IGET(sstMaster->fbiInit4) &
|
|
~SST_MEM_FIFO_LWM) | (memFifoLwm << SST_MEM_FIFO_LWM_SHIFT));
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
INIT_PRINTF(("sst1InitSli(): Master pciFifoLwm:%d, memFifoLwm:%d\n",
|
|
((IGET(sstMaster->fbiInit0) & SST_PCI_FIFO_LWM) >>
|
|
SST_PCI_FIFO_LWM_SHIFT),
|
|
((IGET(sstMaster->fbiInit4) & SST_MEM_FIFO_LWM) >>
|
|
SST_MEM_FIFO_LWM_SHIFT)));
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) & ~SST_VIDEO_RESET);
|
|
sst1InitIdleFBINoNOP(sstbase0);
|
|
|
|
// Master
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE,
|
|
(j & ~(SST_SCANLINE_SLV_OWNPCI | SST_SCANLINE_SLI_SLV)));
|
|
MasterPhysAddr = sst1CurrentBoard->physAddr[0];
|
|
sst1InitReturnStatus(sstbase0); // flush pci packer with reads
|
|
sst1InitReturnStatus(sstbase0);
|
|
sst1InitReturnStatus(sstbase0);
|
|
|
|
// Slave
|
|
if(sst1InitCheckBoard(sstbase1) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE,
|
|
((j & ~(SST_SCANLINE_SLV_OWNPCI)) | SST_SCANLINE_SLI_SLV));
|
|
|
|
/* dpc - 19 may 1998 - FixMe
|
|
* Min the clock values for the two boards so that they are
|
|
* happy running together.
|
|
*/
|
|
#define MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
|
|
{
|
|
sst1DeviceInfoStruct* infoMaster;
|
|
sst1DeviceInfoStruct* infoSlave;
|
|
|
|
if (!sst1InitCheckBoard(sstbase0)) return FXFALSE;
|
|
infoMaster = sst1CurrentBoard;
|
|
|
|
if (!sst1InitCheckBoard(sstbase1)) return FXFALSE;
|
|
infoSlave = sst1CurrentBoard;
|
|
|
|
/* fbi and tmu clock freqs should be equal since they are
|
|
* both set from sst1InitCalcGrxClk.
|
|
*/
|
|
if (infoMaster->fbiGrxClkFreq != infoSlave->fbiGrxClkFreq) {
|
|
/* Recompute the actual clock rates before any clocking down
|
|
* due to sli for some board revisions.
|
|
*/
|
|
if (!sst1InitCalcGrxClk(sstbase0)) return FXFALSE;
|
|
if (!sst1InitCalcGrxClk(sstbase1)) return FXFALSE;
|
|
|
|
/* Save the min clock of the two boards */
|
|
infoMaster->fbiGrxClkFreq =
|
|
infoMaster->tmuGrxClkFreq =
|
|
infoSlave->fbiGrxClkFreq =
|
|
infoSlave->tmuGrxClkFreq = MIN(infoMaster->fbiGrxClkFreq, infoSlave->fbiGrxClkFreq);
|
|
|
|
/* Clear the clock setting bits */
|
|
infoMaster->initGrxClkDone =
|
|
infoSlave->initGrxClkDone = FXFALSE;
|
|
|
|
/* Reset the clocks for each board */
|
|
if (!sst1InitGrxClk(sstbase0)) return FXFALSE;
|
|
if (!sst1InitGrxClk(sstbase1)) return FXFALSE;
|
|
|
|
/* Now check for the memory configurations of the devices.
|
|
* They no longer need to match, but any future calls to
|
|
* sst1InitGetDeviceInfo should now reflect the current
|
|
* minimized state of the world.
|
|
*/
|
|
{
|
|
FxU32 memSize, i;
|
|
|
|
if (infoMaster->fbiMemSize != infoSlave->fbiMemSize) {
|
|
memSize = MIN(infoMaster->fbiMemSize, infoSlave->fbiMemSize);
|
|
infoMaster->fbiMemSize =
|
|
infoSlave->fbiMemSize = memSize;
|
|
}
|
|
|
|
for(i = 0; i < infoMaster->numberTmus; i++) {
|
|
if (infoMaster->tmuMemSize[i] != infoSlave->tmuMemSize[i]) {
|
|
memSize = MIN(infoMaster->tmuMemSize[i], infoSlave->tmuMemSize[i]);
|
|
infoMaster->tmuMemSize[i] =
|
|
infoSlave->tmuMemSize[i] = memSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#undef MIN
|
|
|
|
// Enable SLI Bus Snooping for the Slave
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, (j & ~SST_SLI_SNOOP_MEMBASE) |
|
|
((MasterPhysAddr>>24 & 0xff) << SST_SLI_SNOOP_MEMBASE_SHIFT));
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j | SST_SLI_SNOOP_EN);
|
|
sst1InitReturnStatus(sstbase1); // flush pci packer with reads
|
|
sst1InitReturnStatus(sstbase1);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// Reset video unit in both Master and Slave
|
|
// Then, reset graphics unit in both Master and Slave
|
|
// Finally, deassert both resets to guarantee that Master and Slave
|
|
// see the same vsyncs (and maintain the same swap buffer counter)
|
|
|
|
// Probit writes to PCI fifo while resetting graphics core
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j & ~SST_PCI_FIFOWR_EN);
|
|
if(sst1InitCheckBoard(sstbase1) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j & ~SST_PCI_FIFOWR_EN);
|
|
|
|
// Reset Video core...
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) | SST_VIDEO_RESET);
|
|
sst1InitReturnStatus(sstbase0);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) | SST_VIDEO_RESET);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// Reset Graphics core...
|
|
ISET(sstMaster->fbiInit0, IGET(sstMaster->fbiInit0) | SST_GRX_RESET);
|
|
sst1InitReturnStatus(sstbase0);
|
|
ISET(sstSlave->fbiInit0, IGET(sstSlave->fbiInit0) | SST_GRX_RESET);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// Allow resets to propogate...
|
|
sst1InitReturnStatus(sstbase0);
|
|
sst1InitReturnStatus(sstbase1);
|
|
sst1InitReturnStatus(sstbase0);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// De-assert reset to Graphics core...
|
|
ISET(sstMaster->fbiInit0, IGET(sstMaster->fbiInit0) & ~SST_GRX_RESET);
|
|
sst1InitReturnStatus(sstbase0);
|
|
ISET(sstSlave->fbiInit0, IGET(sstSlave->fbiInit0) & ~SST_GRX_RESET);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// De-assert reset to Video core...
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) & ~SST_VIDEO_RESET);
|
|
sst1InitReturnStatus(sstbase0);
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) & ~SST_VIDEO_RESET);
|
|
sst1InitReturnStatus(sstbase1);
|
|
|
|
// Allow writes to PCI fifo...
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j | SST_PCI_FIFOWR_EN);
|
|
// Update info structure for initEnable
|
|
sst1CurrentBoard->fbiInitEnable = j | SST_PCI_FIFOWR_EN;
|
|
|
|
if(sst1InitCheckBoard(sstbase1) == FXFALSE)
|
|
return(FXFALSE);
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j | SST_PCI_FIFOWR_EN);
|
|
// Update info structure for initEnable
|
|
sst1CurrentBoard->fbiInitEnable = j | SST_PCI_FIFOWR_EN;
|
|
|
|
if(sst1InitCheckBoard(sstbase0) == FXFALSE)
|
|
return(FXFALSE);
|
|
|
|
// Clear fbistat registers after clearing screen
|
|
ISET(sstMaster->nopCMD, 0x1);
|
|
|
|
sst1CurrentBoard->sliSlaveVirtAddr = sstbase1;
|
|
|
|
sst1InitIdle(sstbase0);
|
|
|
|
// Synchronize Boards
|
|
for(j=0; j<3; j++) {
|
|
while(!(sst1InitReturnStatus(sstbase0) & SST_VRETRACE))
|
|
;
|
|
IGET(sstMaster->status);
|
|
ISET(sstMaster->swapbufferCMD, 0x0); // Do not wait for vRetrace...
|
|
IGET(sstMaster->status);
|
|
sst1InitIdle(sstbase0);
|
|
}
|
|
while(!(sst1InitReturnStatus(sstbase0) & SST_VRETRACE))
|
|
;
|
|
IGET(sstMaster->status);
|
|
ISET(sstMaster->swapbufferCMD, 0x1); // Sync to vRetrace...
|
|
IGET(sstMaster->status);
|
|
sst1InitIdle(sstbase0);
|
|
|
|
if(GETENV(("SSTV2_IGNORE_IDLE")))
|
|
initIdleEnabled = 0;
|
|
|
|
INIT_PRINTF(("sst1InitSli() exiting with status %d...\n", FXTRUE));
|
|
return(FXTRUE);
|
|
}
|
|
|
|
/*
|
|
** sst1InitShutdownSli():
|
|
** Shutdown SLI configuration
|
|
**
|
|
*/
|
|
FX_EXPORT FxBool FX_CSTYLE sst1InitShutdownSli(FxU32 *sstbase)
|
|
{
|
|
SstRegs *sstMaster = (SstRegs *) sstbase;
|
|
SstRegs *sstSlave;
|
|
FxU32 n, j, cntr;
|
|
|
|
if(sst1InitCheckBoard(sstbase) == FXFALSE)
|
|
return(FXFALSE);
|
|
|
|
sstSlave = (SstRegs *) sst1CurrentBoard->sliSlaveVirtAddr;
|
|
|
|
if(sst1CurrentBoard->sliSlaveVirtAddr != (FxU32 *) NULL) {
|
|
INIT_PRINTF(("sst1InitShutdownSli(): Disabling Scanline Interleaving...\n"));
|
|
sst1CurrentBoard->sliSlaveVirtAddr = (FxU32 *) NULL;
|
|
|
|
cntr = 0;
|
|
while(1) {
|
|
if(sst1InitCheckBoard((FxU32 *) sstSlave) == FXFALSE)
|
|
return(FXFALSE);
|
|
// Turn off scanline interleaving and snooping in slave...
|
|
PCICFG_RD(SST1_PCI_INIT_ENABLE, j);
|
|
PCICFG_WR(SST1_PCI_INIT_ENABLE, j & ~(SST_SCANLINE_SLV_OWNPCI |
|
|
SST_SCANLINE_SLI_SLV | SST_SLI_SNOOP_EN |
|
|
SST_SLI_SNOOP_MEMBASE));
|
|
ISET(sstSlave->fbiInit1, IGET(sstSlave->fbiInit1) &
|
|
~SST_EN_SCANLINE_INTERLEAVE);
|
|
sst1InitIdle((FxU32 *) sstSlave);
|
|
|
|
if(IGET(sstSlave->fbiInit1) & SST_EN_SCANLINE_INTERLEAVE) {
|
|
if(++cntr < 10)
|
|
continue;
|
|
else {
|
|
INIT_PRINTF(("sst1InitShutdown(): Could not disable Slave SLI...\n"));
|
|
return(FXFALSE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if(sst1InitCheckBoard((FxU32 *) sstMaster) == FXFALSE)
|
|
return(FXFALSE);
|
|
ISET(sstMaster->fbiInit1, IGET(sstMaster->fbiInit1) &
|
|
~SST_EN_SCANLINE_INTERLEAVE);
|
|
sst1InitIdle((FxU32 *) sstMaster);
|
|
}
|
|
return(FXTRUE);
|
|
}
|
|
|
|
/*
|
|
** sst1InitSliDetect():
|
|
** Determine if scanline interleave has been detected (either through
|
|
** power-up settings or through SST_SLIDETECT)
|
|
**
|
|
*/
|
|
FX_ENTRY FxU32 FX_CALL sst1InitSliDetect(FxU32 *sstbase)
|
|
{
|
|
FxU32 sliDetected;
|
|
|
|
if(GETENV(("SSTV2_SLIDETECT")))
|
|
sliDetected = ATOI(GETENV(("SSTV2_SLIDETECT")));
|
|
else
|
|
sliDetected = sst1InitSliPaired(sstbase);
|
|
|
|
return sliDetected;
|
|
}
|
|
|
|
/*
|
|
** sst1InitSliPaired():
|
|
** Determine if scanline interleave has been detected through
|
|
** power-up settings.
|
|
**
|
|
*/
|
|
FX_ENTRY FxU32 FX_CALL
|
|
sst1InitSliPaired(FxU32 *sstbase)
|
|
{
|
|
static int firstTime = 1;
|
|
static FxU32 sliPaired = 0;
|
|
|
|
if(firstTime) {
|
|
SstRegs* sst = (SstRegs *) sstbase;
|
|
|
|
sliPaired = (((IGET(sst->fbiInit5) & SST_SLI_DETECT) == SST_SLI_DETECT) &&
|
|
(boardsInSystem > 1));
|
|
firstTime = 0;
|
|
}
|
|
|
|
return sliPaired;
|
|
}
|
|
|
|
#ifdef __WIN32__
|
|
#pragma optimize ("",on)
|
|
#endif
|