/*-*-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: 1.2 $ ** $Date: 2000/04/20 21:20:22 $ ** ** Utility routines for SST-1 Initialization code ** */ #pragma optimize ("",off) #include #include #include #ifdef BUILD_FOR_SST1 #include #else #include <3dfx.h> #include #include #endif #define FX_DLL_DEFINITION #include #include #include #include "canopus.h" /* ** sst1InitIdle(): ** Return idle condition of SST-1 ** ** Returns: ** FXTRUE if SST-1 is idle (fifos are empty, graphics engines are idle) ** FXFALSE if SST-1 has not been mapped ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitIdle(FxU32 *sstbase) { if(!sstbase) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if(!initIdleEnabled) return(FXTRUE); if(sst1CurrentBoard->fbiLfbLocked) { if(sst1CurrentBoard->sliSlaveVirtAddr == (FxU32 *) NULL) // SLI not enabled... sst1InitPciFifoIdleLoop(sstbase); else { // Check idle for Master... sst1InitPciFifoIdleLoop(sstbase); // Check idle for Slave... sst1InitPciFifoIdleLoop(sst1CurrentBoard->sliSlaveVirtAddr); } } else { if(sst1CurrentBoard->sliSlaveVirtAddr == (FxU32 *) NULL) // SLI not enabled... sst1InitIdleLoop(sstbase, FXTRUE); else { // Check idle for Master... sst1InitIdleLoop(sstbase, FXTRUE); // Check idle for Slave... // Note that the Slave does not need another NOP command, because // it will snoop the NOP command sent to the Master above. // Sending a NOP command to the Slave also confuses the callback // write routines for the command fifo which are not setup to // handle any other base addresses other than the Master's... sst1InitIdleLoop(sst1CurrentBoard->sliSlaveVirtAddr, FXFALSE); } } return(FXTRUE); } static FxBool sst1InitIdleWithTimeoutLoop(FxU32 *sstbase, FxBool issueNOP, FxU32 timeout) { FxU32 cntr, loop; SstRegs *sst = (SstRegs *) sstbase; if(issueNOP) ISET(sst->nopCMD, 0x0); cntr = loop = 0; while(++loop < timeout) { if(!(sst1InitReturnStatus(sstbase) & SST_BUSY)) { if(++cntr >= 3) break; } else cntr = 0; } return (loop < timeout); } FxBool sst1InitIdleFBIWithTimeout(FxU32 *sstbase, FxBool issueNop, FxU32 timeout) { int retVal; if(!sstbase) return(FXFALSE); if(!sst1InitCheckBoard(sstbase)) return(FXFALSE); if(sst1CurrentBoard->sliSlaveVirtAddr == (FxU32 *) NULL) { // SLI not enabled... retVal = sst1InitIdleWithTimeoutLoop(sstbase, issueNop, timeout); } else { // Check idle for Master... if(!sst1InitIdleWithTimeoutLoop(sstbase, issueNop, timeout)) return(FXFALSE); // Check idle for Slave... // Note that the Slave does not need another NOP command, because // it will snoop the NOP command sent to the Master above. // Sending a NOP command to the Slave also confuses the callback // write routines for the command fifo which are not setup to // handle any other base addresses other than the Master's... retVal = sst1InitIdleWithTimeoutLoop(sst1CurrentBoard->sliSlaveVirtAddr, FXFALSE, timeout); } return retVal; } FX_EXPORT FxBool FX_CSTYLE sst1InitIdleNoNOP(FxU32 *sstbase) { if(!sstbase) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if(!initIdleEnabled) return(FXTRUE); if(sst1CurrentBoard->fbiLfbLocked) { if(sst1CurrentBoard->sliSlaveVirtAddr == (FxU32 *) NULL) // SLI not enabled... sst1InitPciFifoIdleLoop(sstbase); else { // Check idle for Master... sst1InitPciFifoIdleLoop(sstbase); // Check idle for Slave... sst1InitPciFifoIdleLoop(sst1CurrentBoard->sliSlaveVirtAddr); } } else { if(sst1CurrentBoard->sliSlaveVirtAddr == (FxU32 *) NULL) // SLI not enabled... sst1InitIdleLoop(sstbase, FXFALSE); else { // Check idle for Master... sst1InitIdleLoop(sstbase, FXFALSE); // Check idle for Slave... sst1InitIdleLoop(sst1CurrentBoard->sliSlaveVirtAddr, FXFALSE); } } return(FXTRUE); } void sst1InitIdleLoop(FxU32 *sstbase, FxBool issueNOP) { FxU32 cntr; SstRegs *sst = (SstRegs *) sstbase; if(issueNOP) ISET(sst->nopCMD, 0x0); cntr = 0; while(1) { if(!(sst1InitReturnStatus(sstbase) & SST_BUSY)) { if(++cntr >= 3) break; } else cntr = 0; } } void sst1InitPciFifoIdleLoop(FxU32 *sstbase) { FxU32 cntr; cntr = 0; while(1) { if(((sst1InitReturnStatus(sstbase) & SST_FIFOLEVEL)) == 0x3f) { // Since sst1InitPciFifoIdleLoop is only called when we're trying // to "fake" idle during lfb locks, wait for 6 passes to give the // hardware time to drain if(++cntr >= 6) break; } else cntr = 0; } } /* ** sst1InitIdleFBI(): ** Return idle condition of FBI (ignoring idle status of TMU) ** ** Returns: ** FXTRUE if FBI is idle (fifos are empty, graphics engines are idle) ** FXFALSE if FBI has not been mapped ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitIdleFBI(FxU32 *sstbase) { FxU32 cntr; SstRegs *sst = (SstRegs *) sstbase; if(!sst) return(FXFALSE); ISET(sst->nopCMD, 0x0); cntr = 0; while(1) { if(!(sst1InitReturnStatus(sstbase) & SST_FBI_BUSY)) { if(++cntr >= 3) break; } else cntr = 0; } return(FXTRUE); } /* ** sst1InitIdleFBINoNOP(): ** Return idle condition of FBI (ignoring idle status of TMU) ** sst1InitIdleFBINoNOP() differs from sst1InitIdleFBI() in that no NOP command ** is issued to flush the graphics pipeline. ** ** Returns: ** FXTRUE if FBI is idle (fifos are empty, graphics engines are idle) ** FXFALSE if FBI has not been mapped ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitIdleFBINoNOP(FxU32 *sstbase) { FxU32 cntr; SstRegs *sst = (SstRegs *) sstbase; if(!sst) return(FXFALSE); // ISET(sst->nopCMD, 0x0); cntr = 0; while(1) { if(!(sst1InitReturnStatus(sstbase) & SST_FBI_BUSY)) { if(++cntr > 5) break; } else cntr = 0; } return(FXTRUE); } // Included so compiler doesn't optimize out loop code waiting on status bits FX_EXPORT FxU32 FX_CSTYLE sst1InitReturnStatus(FxU32 *sstbase) { SstRegs *sst = (SstRegs *) sstbase; return(IGET(sst->status)); } /* ** sst1InitClearSwapPending(): ** Clear any swaps pending in the status register ** NOTE: The video unit of FBI must be initialized before calling this routine ** ** Returns: ** FXTRUE ** */ FX_ENTRY FxBool FX_CALL sst1InitClearSwapPending(FxU32 *sstbase) { SstRegs *sst = (SstRegs *) sstbase; FxU32 displayedBuffer, i; INIT_PRINTF(("sst1InitClearSwapPending() WARNING: Clearing pending swapbufferCMDs...\n")); sst1InitIdle(sstbase); displayedBuffer = (IGET(sst->status) & SST_DISPLAYED_BUFFER) >> SST_DISPLAYED_BUFFER_SHIFT; // Wait until vsync is inactive to guarantee that swaps queue in the // PCI fifo properly while(!(IGET(sst->status) & SST_VRETRACE) || ((IGET(sst->vRetrace) & 0xfff) > 100) || ((IGET(sst->vRetrace) & 0xfff) < 10)) ; // First swap syncs to Vsync...Subsequent ones do not... ISET(sst->swapbufferCMD, 0x1); ISET(sst->nopCMD, 0x0); for(i=0; i<17; i++) { ISET(sst->swapbufferCMD, 0x0); ISET(sst->nopCMD, 0x0); } if(displayedBuffer) { ISET(sst->swapbufferCMD, 0x0); ISET(sst->nopCMD, 0x0); } sst1InitIdle(sstbase); return(FXTRUE); } /* ** sst1InitVgaPassCtrl(): ** Control VGA passthrough setting ** ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitVgaPassCtrl(FxU32 *sstbase, FxU32 enable) { SstRegs *sst = (SstRegs *) sstbase; if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); //if (sst1CurrentBoard->singleBrdSLISlave) { // enable = 1; //} if(enable) { // VGA controls monitor ISET(sst->fbiInit0, (IGET(sst->fbiInit0) & ~SST_EN_VGA_PASSTHRU) | sst1CurrentBoard->vgaPassthruEnable); ISET(sst->fbiInit1, IGET(sst->fbiInit1) | SST_VIDEO_BLANK_EN); } else { // SST-1 controls monitor ISET(sst->fbiInit0, (IGET(sst->fbiInit0) & ~SST_EN_VGA_PASSTHRU) | sst1CurrentBoard->vgaPassthruDisable); ISET(sst->fbiInit1, IGET(sst->fbiInit1) & ~SST_VIDEO_BLANK_EN); } return(FXTRUE); } /* ** sst1InitResetTmus(): ** Reset TMUs ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitResetTmus(FxU32 *sstbase) { volatile int delay; SstRegs *sst = (SstRegs *) sstbase; FxU32 allowTexturing = (GETENV(("SSTV2_TEXMAP_DISABLE"))) ? 0 : 1; if(!sst) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); // Ignore stalls on FT Bus ISET(sst->fbiInit3, IGET(sst->fbiInit3) | SST_TEXMAP_DISABLE); // Delay for(delay=0;delay<10000;) delay++; // while(++cntr < 6) { INIT_PRINTF(("sst1InitResetTmus(): Reset Graphics ")); do { INIT_PRINTF((".")); // Set Default initialization values for all TMUs... ISET(SST_TREX(sst,0)->trexInit0, sst1CurrentBoard->tmuInit0[0]); ISET(SST_TREX(sst,1)->trexInit0, sst1CurrentBoard->tmuInit0[1]); // Delay for(delay=0;delay<10000;) delay++; ISET(SST_TREX(sst,0)->trexInit1, sst1CurrentBoard->tmuInit1[0]); ISET(SST_TREX(sst,1)->trexInit1, sst1CurrentBoard->tmuInit1[1]); // Delay for(delay=0;delay<10000;) delay++; // Reset TMU FIFOs and graphics core for all TMUs... ISET(SST_TREX(sst,0)->trexInit1, sst1CurrentBoard->tmuInit1[0] | SST_TEX_RESET_FIFO | SST_TEX_RESET_GRX); ISET(SST_TREX(sst,1)->trexInit1, sst1CurrentBoard->tmuInit1[1] | SST_TEX_RESET_FIFO | SST_TEX_RESET_GRX); // Delay for(delay=0;delay<10000;) delay++; ISET(SST_TREX(sst,1)->trexInit1, sst1CurrentBoard->tmuInit1[1]); // Allow unreset to propagate backwards... // Delay for(delay=0;delay<10000;) delay++; ISET(SST_TREX(sst,0)->trexInit1, sst1CurrentBoard->tmuInit1[0]); // Delay for(delay=0;delay<10000;) delay++; // Reset in the downstream TMU may cause glitches in FBI's TF FIFO // Waiting for Idle in FBI will not stall on something in the TF FIFO, // as the TF FIFO empty signal is not part of FBI's "busy" bit // sst1InitIdleFBIWithTimeout(sstbase, FXTRUE, 100000); sst1InitResetFbi(sstbase); /* fbiInit0 = IGET(sst->fbiInit0) | SST_GRX_RESET | SST_PCI_FIFO_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; fbiInit0 &= ~SST_PCI_FIFO_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; fbiInit0 &= ~SST_GRX_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; */ if(allowTexturing) { ISET(sst->fbiInit3, IGET(sst->fbiInit3) & ~SST_TEXMAP_DISABLE); for(delay=0;delay<10000;) delay++; } delay = 0; while( sst1InitReturnStatus(sstbase) & (SST_TMU_BUSY | SST_FBI_BUSY) && (delay < 50000) ) delay++; }while( delay == 50000 ); INIT_PRINTF(("\n")); // INIT_PRINTF(("sst1InitResetTmus(): Could not reset graphics (0x%08lx)\n", ret)); // else // break; // } // if(cntr == 6) { // INIT_PRINTF(("sst1InitResetTmus(): Could not reset TMUs...\n")); // return(FXFALSE); // } // Fix problem where first Texture downloads to TMU weren't being // received properly ISET(*(long *) (0xf00000 + (long) sstbase), 0xdeadbeef); sst1InitIdle(sstbase); return(FXTRUE); } /* ** sst1InitResetFbi(): ** Reset FBI graphics engine and frontend PCI Fifo... ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitResetFbi(FxU32 *sstbase) { volatile delay; // int i; FxU32 fbiInit0; SstRegs *sst = (SstRegs *) sstbase; /* for(i=0;i<20000;i++) sst1InitReturnStatus(sstbase); ISET(sst->fbiInit0, IGET(sst->fbiInit0) | SST_GRX_RESET | SST_PCI_FIFO_RESET); for(i=0;i<20000;i++) sst1InitReturnStatus(sstbase); ISET(sst->fbiInit0, IGET(sst->fbiInit0) & ~SST_PCI_FIFO_RESET); for(i=0;i<20000;i++) sst1InitReturnStatus(sstbase); ISET(sst->fbiInit0, IGET(sst->fbiInit0) & ~SST_GRX_RESET); for(i=0;i<20000;i++) sst1InitReturnStatus(sstbase); */ fbiInit0 = IGET(sst->fbiInit0) | SST_GRX_RESET | SST_PCI_FIFO_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; fbiInit0 &= ~SST_PCI_FIFO_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; fbiInit0 &= ~SST_GRX_RESET; ISET(sst->fbiInit0, fbiInit0); // Delay for(delay=0;delay<10000;) delay++; return(FXTRUE); } #if SET_BSWAP #if __POWERPC__ && defined(__MWERKS__) #define GET(s) __lwbrx(s, 0 ) #define SET(d, s) __stwbrx((s), (d), 0); #else /* !__MWERKS__ */ #error "Define byte swapped macros for GET/SET" #endif /* !__MWERKS__ */ #else /* !SET_BSWAP */ #ifdef GET #undef GET #endif #ifdef SET #undef SET #endif #define GET(s) (*s) #define SET(d, s) ((*d) = s) #endif /* !SET_BSWAP */ /* ** sst1InitWrite32(): ** Write 32-bit Word to specified address ** */ FX_EXPORT void FX_CSTYLE sst1InitWrite32(FxU32 *addr, FxU32 data) { /* If the client software is using the command fifo then they are * responsible for passing a callback that can be used to put * register writes from the init code into the command fifo that * they are managing. However, some registers cannot be accessed via * the command fifo, and, inconveniently, these are not contiguously * allocated. */ const FxU32 addrOffset = ((const FxU32)addr - (const FxU32)sst1CurrentBoard->virtAddr[0]); FxBool directWriteP = ((sst1CurrentBoard == NULL) || (sst1CurrentBoard->set32 == NULL) || sst1CurrentBoard->fbiLfbLocked || (addrOffset == 0x004) || /* intrCtrl */ ((addrOffset >= 0x1E0) && (addrOffset <= 0x200)) || /* cmdFifoBase ... fbiInit4 */ ((addrOffset >= 0x208) && (addrOffset <= 0x224)) || /* backPorch ... vSync */ ((addrOffset >= 0x22C) && (addrOffset <= 0x23C)) || /* dacData ... borderColor */ ((addrOffset >= 0x244) && (addrOffset <= 0x24C))); /* fbiInit5 ... fbiInit7 */ if (directWriteP) { P6FENCE; SET(addr, data); P6FENCE; } else { (*sst1CurrentBoard->set32)(addr, data); } } /* ** sst1InitRead32(): ** Read 32-bit Word from specified address ** */ FX_EXPORT FxU32 FX_CSTYLE sst1InitRead32(FxU32 *addr) { P6FENCE; return GET(addr); } /* ** ** sst1InitCmdFifo(): ** Setup Command Fifo. ** ** The 'enable' parameter either enables or disables the Command Fifo. ** ** Upon return, the 'virtAddrStart' parameter is filled with the starting ** virtual address where command fifo packets should be stored. The ** 'memAddrStart' parameter is filled with the address of where the command ** fifo is stored in frame buffer memory. The 'memAddrStart' value is often ** used by the JMP command to jump to the beginning of the command fifo. ** The 'size' parameter is filled with the size of the command fifo. ** The values of 'virtAddrstart', 'memAddrStart' and 'size' ** are dependent on the amount of frame buffer memory detected as well as the ** video resolution setup by sst1InitVideo(). 'virtAddrstart', ** 'memAddrStart' and 'size' are all specified in bytes. ** */ FX_ENTRY FxBool FX_CALL sst1InitCmdFifo(FxU32 *sstbase, FxBool enable, FxU32 *virtAddrStart, FxU32 *memAddrStart, FxU32 *size, FxSet32Proc set32Proc) { SstRegs *sst = (SstRegs *) sstbase; FxU32 fbiInit, fifoStart, fifoSize; FxBool directExec = (GETENV(("SSTV2_CMDFIFO_DIRECT"))) ? FXTRUE : FXFALSE; FxBool disableHoles = (GETENV(("SSTV2_CMDFIFO_NOHOLES"))) ? FXTRUE : FXFALSE; if(!sst) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if(sst1CurrentBoard->fbiCmdFifoEn || (IGET(sst->fbiInit7) & SST_EN_CMDFIFO)) sst1InitIdleNoNOP(sstbase); else sst1InitIdle(sstbase); if(enable == FXFALSE) { // Remove any client set callbacks before continuing since // these must go straight to the hw. sst1CurrentBoard->set32 = NULL; sst1CurrentBoard->fbiCmdFifoEn = 0; // Disable Command Fifo INIT_PRINTF(("sst1InitCmdFifo(): Disabling Command Fifo...\n")); ISET(sst->fbiInit7, IGET(sst->fbiInit7) & ~SST_EN_CMDFIFO); // Reset graphics core to force disable to take effect... ISET(sst->fbiInit0, IGET(sst->fbiInit0) | SST_GRX_RESET | SST_EN_LFB_MEMFIFO | SST_EN_TEX_MEMFIFO); sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); ISET(sst->fbiInit0, IGET(sst->fbiInit0) & ~SST_GRX_RESET); if(sst1CurrentBoard->sliSlaveVirtAddr) { SstRegs *slaveSst = (SstRegs *) sst1CurrentBoard->sliSlaveVirtAddr; ISET(slaveSst->fbiInit7, IGET(slaveSst->fbiInit7) & ~SST_EN_CMDFIFO); // Reset graphics core to force disable to take effect... ISET(slaveSst->fbiInit0, IGET(slaveSst->fbiInit0) | SST_GRX_RESET | SST_EN_LFB_MEMFIFO | SST_EN_TEX_MEMFIFO); sst1InitReturnStatus(sst1CurrentBoard->sliSlaveVirtAddr); sst1InitReturnStatus(sst1CurrentBoard->sliSlaveVirtAddr); sst1InitReturnStatus(sst1CurrentBoard->sliSlaveVirtAddr); ISET(slaveSst->fbiInit0, IGET(slaveSst->fbiInit0) & ~SST_GRX_RESET); if(sst1InitCheckBoard(sst1CurrentBoard->sliSlaveVirtAddr) == FXFALSE) return(FXFALSE); sst1CurrentBoard->set32 = NULL; sst1CurrentBoard->fbiCmdFifoEn = 0; } return(FXTRUE); } sst1InitIdle(sstbase); fbiInit = IGET(sst->fbiInit4); fifoStart = (fbiInit & SST_MEM_FIFO_ROW_BASE) >> SST_MEM_FIFO_ROW_BASE_SHIFT; fifoStart <<= 12; // Convert page-address into byte-address if(sst1CurrentBoard->fbiMemSize == 4) fifoSize = (1024 - (fifoStart >> 12)) << 12; else if(sst1CurrentBoard->fbiMemSize == 2) fifoSize = (512 - (fifoStart >> 12)) << 12; else fifoSize = (256 - (fifoStart >> 12)) << 12; if(fifoSize > (256<<10)) fifoSize = (256<<10); *virtAddrStart = (FxU32) (((FxU32) sstbase) + SST_CMDFIFO_ADDR); *memAddrStart = fifoStart; *size = fifoSize; if(!sst1InitCmdFifoDirect(sstbase, 0, fifoStart, fifoSize, directExec, disableHoles, set32Proc)) { INIT_PRINTF(("sst1InitCmdFifo(): sst1InitCmdFifoDirect() failed...\n")); return(FXFALSE); } if(sst1CurrentBoard->sliSlaveVirtAddr) { if(!sst1InitCmdFifoDirect(sst1CurrentBoard->sliSlaveVirtAddr, 0, fifoStart, fifoSize, directExec, disableHoles, set32Proc)) { INIT_PRINTF(("sst1InitCmdFifo(): sst1InitCmdFifoDirect() failed for SLI Slave...\n")); return(FXFALSE); } } INIT_PRINTF(("sst1InitCmdFifo() exiting with status %d...\n", FXTRUE)); return(FXTRUE); } /* ** ** sst1InitCmdFifoDirect(): ** Explicitly initialize Command FIFO. This routine is typically not ** called directly from apps, but is included so that csim diags can ** call it directly. ** ** The 'start' and 'size' parameters are specified in bytes. ** The 'which' parameter is not used, but is included for H3 compatibility. ** */ FX_ENTRY FxBool FX_CALL sst1InitCmdFifoDirect(FxU32 *sstbase, FxU32 which, FxU32 start, FxU32 size, FxBool directExec, FxBool disableHoles, FxSet32Proc set32Proc) { SstRegs *sst = (SstRegs *) sstbase; FxU32 fbiInit7, initEnable, n; FxU32 pageStart = start >> 12; FxU32 pageEnd = (start+size-1) >> 12; if(!sst) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); // sst1Initidle() routines must be properly executed... initIdleEnabled = 1; INIT_PRINTF(("sst1InitCmdFifoDirect(): Start:0x%x bytes, Size:%d(0x%x) bytes\n", start, size, size)); INIT_PRINTF(("sst1InitCmdFifoDirect(): DirectExec:%d, DisableHoles:%d\n", directExec, disableHoles)); INIT_PRINTF(("sst1InitCmdFifoDirect(): pageStart:%d, pageEnd:%d\n", pageStart, pageEnd)); INIT_PRINTF(("sst1InitCmdFifoDirect(): set32Proc: 0x%X\n", (FxU32)set32Proc)); if(sst1CurrentBoard->fbiCmdFifoEn || (IGET(sst->fbiInit7) & SST_EN_CMDFIFO)) sst1InitIdleNoNOP(sstbase); else sst1InitIdle(sstbase); // Disable memory-backed fifo, and disallow lfb and texture writes // through command fifo... ISET(sst->fbiInit0, (IGET(sst->fbiInit0) & ~(SST_MEM_FIFO_EN | SST_EN_LFB_MEMFIFO | SST_EN_TEX_MEMFIFO))); sst1InitReturnStatus(sstbase); fbiInit7 = IGET(sst->fbiInit7); fbiInit7 &= ~(SST_EN_CMDFIFO | SST_EN_CMDFIFO_OFFSCREEN | SST_CMDFIFO_DISABLE_HOLES | SST_CMDFIFO_REGS_SYNC_WRITES | SST_CMDFIFO_REGS_SYNC_READS | SST_CMDFIFO_RDFETCH_THRESH | SST_CMDFIFO_PCI_TIMEOUT); fbiInit7 |= SST_CMDFIFO_REGS_SYNC_WRITES | SST_CMDFIFO_REGS_SYNC_READS | (0x10<fbiInit7, fbiInit7); // turn off the command fifo sst1InitReturnStatus(sstbase); // Disable all writes to the PCI fifo while we're setting up CMDFIFO PCICFG_RD(SST1_PCI_INIT_ENABLE, initEnable); PCICFG_WR(SST1_PCI_INIT_ENABLE, ((initEnable & ~(SST_INITWR_EN | SST_PCI_FIFOWR_EN)) | SST_INITWR_EN)); // Setup command fifo... ISET(sst->cmdFifoBase, (pageEnd << SST_CMDFIFO_END_SHIFT) | pageStart); sst1InitReturnStatus(sstbase); // prevent PCI bursts... ISET(sst->cmdFifoReadPtr, start); sst1InitReturnStatus(sstbase); ISET(sst->cmdFifoAmin, start-4); sst1InitReturnStatus(sstbase); ISET(sst->cmdFifoAmax, start-4); sst1InitReturnStatus(sstbase); ISET(sst->cmdFifoDepth, 0); sst1InitReturnStatus(sstbase); ISET(sst->cmdFifoHoles, 0); sst1InitReturnStatus(sstbase); sst1InitIdle(sstbase); // Turn on command fifo... ISET(sst->fbiInit7, fbiInit7 | SST_EN_CMDFIFO | (directExec ? 0 : SST_EN_CMDFIFO_OFFSCREEN) | (disableHoles ? SST_CMDFIFO_DISABLE_HOLES : 0)); // Can't perform sst1InitIdle() here because it will generate // writes to the CMDFIFO since the CMDFIFO is now enabled... sst1InitReturnStatus(sstbase); // Enable writes to be pushed onto the CMDFIFO... PCICFG_WR(SST1_PCI_INIT_ENABLE, (initEnable | SST_INITWR_EN | SST_PCI_FIFOWR_EN)); sst1CurrentBoard->fbiCmdFifoEn = 1; if(GETENV(("SSTV2_IGNORE_IDLE"))) initIdleEnabled = 0; /* Set the client callbacks, if necessary. */ sst1CurrentBoard->set32 = set32Proc; return(FXTRUE); } /* ** ** sst1InitLfbLock(): ** Used to workaround a hw bug when performing lfb and texture writes when ** the command fifo is enabled. The routines sst1InitLfbLock() and ** sst1InitLfbUnlock() dynamically disable the command fifo so that lfb ** and texture accesses do not pass through the command fifo. ** WARNING: No register writes of any kind may be performed between a ** sst1InitLfbLock() and sst1InitLfbUnlock() pair -- only lfb reads and ** writes are allowed. */ FX_ENTRY FxBool FX_CALL sst1InitLfbLock(FxU32* sstbase) { if(!sstbase) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); // Idle the hardware... sst1InitIdle(sstbase); if(sst1InitLfbLockDirect(sstbase) == FXFALSE) return(FXFALSE); if(sst1CurrentBoard->sliSlaveVirtAddr) { // SLI Enabled if(sst1InitLfbLockDirect(sst1CurrentBoard->sliSlaveVirtAddr) == FXFALSE) return(FXFALSE); } return(FXTRUE); } FX_ENTRY FxBool FX_CALL sst1InitLfbLockDirect(FxU32* sstbase) { SstRegs *sst = (SstRegs *) sstbase; if(!sst) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if((!(IGET(sst->fbiInit7) & SST_EN_CMDFIFO) && !sst1CurrentBoard->fbiCmdFifoEn) || sst1CurrentBoard->fbiLfbLocked) return(FXTRUE); // Force direct writes... sst1CurrentBoard->fbiLfbLocked = 1; ISET(sst->fbiInit7, IGET(sst->fbiInit7) & ~SST_EN_CMDFIFO_OFFSCREEN); sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); return(FXTRUE); } /* ** ** sst1InitLfbUnlock(): ** Used to workaround a hw bug when performing lfb and texture writes when ** the command fifo is enabled. The routines sst1InitLfbLock() and ** sst1InitLfbUnlock() dynamically disable the command fifo so that lfb ** and texture accesses do not pass through the command fifo. ** WARNING: No register writes of any kind may be performed between a ** sst1InitLfbLock() and sst1InitLfbUnlock() pair -- only lfb reads and ** writes are allowed. */ FX_ENTRY FxBool FX_CALL sst1InitLfbUnlock(FxU32* sstbase) { if(!sstbase) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); // Idle the hardware. Since lfb lock is set, a NOP will not be issued, and // sst1InitPciFifoIdleLoop() will be used instead of sst1InitIdleLoop()... sst1InitIdle(sstbase); if(sst1CurrentBoard->sliSlaveVirtAddr) { // SLI Enabled if(sst1InitLfbUnlockDirect(sst1CurrentBoard->sliSlaveVirtAddr) == FXFALSE) return(FXFALSE); } if(sst1InitLfbUnlockDirect(sstbase) == FXFALSE) return(FXFALSE); // After the command fifo is re-enabled, make sure the chip is really idle... sst1InitIdle(sstbase); return(FXTRUE); } FX_ENTRY FxBool FX_CALL sst1InitLfbUnlockDirect(FxU32* sstbase) { SstRegs *sst = (SstRegs *) sstbase; if(!sst) return(FXFALSE); if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if(!sst1CurrentBoard->fbiCmdFifoEn || !sst1CurrentBoard->fbiLfbLocked) return(FXTRUE); ISET(sst->fbiInit7, IGET(sst->fbiInit7) | SST_EN_CMDFIFO_OFFSCREEN); sst1CurrentBoard->fbiLfbLocked = 0; sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); sst1InitReturnStatus(sstbase); return(FXTRUE); } /* ** ** sst1InitPrintInitRegs(): ** Print Initialization Registers ** */ FX_EXPORT void FX_CSTYLE sst1InitPrintInitRegs(FxU32 *sstbase) { SstRegs *sst = (SstRegs *) sstbase; INIT_PRINTF(("FBI Initialization Registers:\n")); INIT_PRINTF(("-----------------------------\n")); INIT_PRINTF(("fbiInit0:0x%08x fbiInit1:0x%08x\n", IGET(sst->fbiInit0), IGET(sst->fbiInit1))); INIT_PRINTF(("fbiInit2:0x%08x fbiInit3:0x%08x\n", IGET(sst->fbiInit2), IGET(sst->fbiInit3))); INIT_PRINTF(("fbiInit4:0x%08x fbiInit5:0x%08x\n", IGET(sst->fbiInit4), IGET(sst->fbiInit5))); INIT_PRINTF(("fbiInit6:0x%08x fbiInit7:0x%08x\n", IGET(sst->fbiInit6), IGET(sst->fbiInit7))); INIT_PRINTF(("videoDimensions:0x%08x\n\n", IGET(sst->videoDimensions))); INIT_PRINTF(("FBI Command Fifo Registers:\n")); INIT_PRINTF(("---------------------------\n")); INIT_PRINTF(("cmdFifoBase: 0x%08x\tcmdFifoBump:0x%x\n", IGET(sst->cmdFifoBase), IGET(sst->cmdFifoBump))); INIT_PRINTF(("cmdFifoReadPtr: 0x%08x\tcmdFifoAmin:0x%x\n", IGET(sst->cmdFifoReadPtr), IGET(sst->cmdFifoAmin))); INIT_PRINTF(("cmdFifoAmax: 0x%08x\tcmdFifoDepth:0x%x\n", IGET(sst->cmdFifoAmax), IGET(sst->cmdFifoDepth))); INIT_PRINTF(("cmdFifoHoles: 0x%08x\n", IGET(sst->cmdFifoHoles))); } /* ** ** sst1InitMeasureSiProcess(): ** Use silicon process register to measure silicon performance ** */ FX_EXPORT FxU32 FX_CSTYLE sst1InitMeasureSiProcess(FxU32 *sstbase, FxU32 which) { FxU32 n, siProcess, nandOsc, norOsc; FxU32 pciCntrLoad = 0xfff; FxU32 cntr; if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); if(GETENV(("SSTV2_SIPROCESS_CNTR"))) { SSCANF(GETENV(("SSTV2_SIPROCESS_CNTR")), "%i", &pciCntrLoad); INIT_PRINTF(("sst1InitMeasureSiProcess(): Using PCI Counter preload value of 0x%x...\n", pciCntrLoad)); } if(!which) { //////////////////////////////// // Test NAND oscillator tree... //////////////////////////////// PCICFG_WR(SST1_PCI_SIPROCESS, (pciCntrLoad<fbiNandTree = nandOsc; INIT_PRINTF(("sst1InitInfo(): NAND-tree: %d\n", nandOsc)); } else { //////////////////////////////// // Test NOR oscillator tree... //////////////////////////////// PCICFG_WR(SST1_PCI_SIPROCESS, (pciCntrLoad<fbiNorTree = norOsc; INIT_PRINTF(("sst1InitInfo(): NOR-tree : %d\n", norOsc)); } return(siProcess); } /* ** ** sst1InitCalcTClkDelay() ** Calculate optimal TF/TT Clock delay values ** */ FX_EXPORT FxBool FX_CSTYLE sst1InitCalcTClkDelay(FxU32 *sstbase, FxU32 tmuNumber, FxU32 tClkDelay) { SstRegs *sst = (SstRegs *) sstbase; volatile FxU32 *texAddr; if(sst1InitCheckBoard(sstbase) == FXFALSE) return(FXFALSE); ISET(sst->tLOD, 0x0); ISET(sst->tDetail, 0x0); ISET(sst->texBaseAddr, 0x0); ISET(sst->fogMode, 0x0); ISET(sst->alphaMode, 0x0); ISET(sst->fbzMode, SST_ENCHROMAKEY); ISET(sst->fbzColorPath, SST_RGBSEL_TREXOUT | SST_CC_PASS | SST_ENTEXTUREMAP); //texAddr = (numTmu<<(21-2)) + (FxU32 *) SST_TEX_ADDRESS(sst); texAddr = (0<<(21-2)) + (FxU32 *) SST_TEX_ADDRESS(sst); ISET(texAddr[0], 0x0); texAddr = (1<<(21-2)) + (FxU32 *) SST_TEX_ADDRESS(sst); ISET(texAddr[0], 0x0); texAddr = (2<<(21-2)) + (FxU32 *) SST_TEX_ADDRESS(sst); ISET(texAddr[0], 0x0); ISET(SST_TREX(sst,tmuNumber)->trexInit1, (sst1CurrentBoard->tmuInit1[tmuNumber] & ~SST_TEX_TF_CLK_DEL_ADJ) | (tClkDelay<nopCMD, 0x3); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0xff0000); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0x00ffff); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0xf0f0f0); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0x0f0f0f); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0x55aa55); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0xaa55aa); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0x5a5a5a); sst1InitCheckTmuMemConst(sstbase, tmuNumber, 0xa5a5a5); if(!sst1InitIdleFBIWithTimeout(sstbase, FXTRUE, 10000)) return(FXFALSE); if(IGET(sst->stats.fbiChromaFail)) return(FXFALSE); else return(FXTRUE); } #define COLOR32TOCOLOR24_6666(X) \ ((((X >> 2) & 0x3F) << 0) | \ (((X >> 10) & 0x3F) << 6) | \ (((X >> 18) & 0x3F) << 12) | \ (((X >> 26) & 0x3F) << 18)) #define COLOR24_6666TOCOLOR32(X) \ (((((X >> 0) & 0x3F) << 2) | (((X >> 4) & 0x3) << 0)) | \ ((((X >> 6) & 0x3F) << 10) | (((X >> 10) & 0x3) << 8)) | \ ((((X >> 12) & 0x3F) << 18) | (((X >> 16) & 0x3) << 16)) | \ ((((X >> 18) & 0x3F) << 26) | (((X >> 22) & 0x3) << 24))) void sst1InitCheckTmuMemConst(FxU32 *sstbase, FxU32 tmuNumber, FxU32 dataExpect32) { SstRegs *sst = (SstRegs *) sstbase; FxU32 dataExpect6666 = COLOR32TOCOLOR24_6666(dataExpect32); FxU32 dataExpect6666To32 = COLOR24_6666TOCOLOR32(dataExpect6666) & 0xffffff; ISET(sst->chromaKey, dataExpect6666To32); ISET(sst->chromaRange, dataExpect6666To32 | SST_ENCHROMARANGE | SST_CHROMARANGE_BLUE_EX | SST_CHROMARANGE_GREEN_EX | SST_CHROMARANGE_RED_EX | SST_CHROMARANGE_BLOCK_OR); if(!tmuNumber) { ISET(sst->textureMode, SST_P8_ARGB6666 | SST_TC_REPLACE | SST_TCA_ZERO); } else if(tmuNumber == 1) { // Force downstream TMU to passthrough upstream data ISET(SST_TREX(sst,0)->textureMode, SST_P8_ARGB6666 | SST_TC_PASS | SST_TCA_PASS); ISET(SST_TREX(sst,1)->textureMode, SST_P8_ARGB6666 | SST_TC_REPLACE | SST_TCA_ZERO); ISET(SST_TREX(sst,2)->textureMode, SST_P8_ARGB6666 | SST_TC_REPLACE | SST_TCA_ZERO); } else { // Force downstream TMUs to passthrough upstream data ISET(SST_TREX(sst,0)->textureMode, SST_P8_ARGB6666 | SST_TC_PASS | SST_TCA_PASS); ISET(SST_TREX(sst,1)->textureMode, SST_P8_ARGB6666 | SST_TC_PASS | SST_TCA_PASS); ISET(SST_TREX(sst,2)->textureMode, SST_P8_ARGB6666 | SST_TC_REPLACE | SST_TCA_ZERO); } // Specify color in palette entry 0... //sst->nccTable0[4]=BIT(31) | ((index>>1)<<24) | (palette[index] & 0xffffff); ISET(sst->nccTable0[4], BIT(31) | COLOR32TOCOLOR24_6666(dataExpect32)); sst1InitDrawRectUsingTris(sstbase, 0, 0, 128); return; } void sst1InitDrawRectUsingTris(FxU32 *sstbase, FxU32 x, FxU32 y, FxU32 tSize) { SstRegs *sst = (SstRegs *) sstbase; ISET(sst->vA.x, (x<vA.y, (y<vB.x, ((x+tSize)<vB.y, (y<vC.x, ((x+tSize)<vC.y, ((y+tSize)<s, 0); ISET(sst->t, 0); ISET(sst->w, 0); ISET(sst->r, (0xff<g, 0); ISET(sst->b, 0); ISET(sst->dsdx, 0); ISET(sst->dtdx, 0); ISET(sst->dwdx, 0); ISET(sst->dsdy, 0); ISET(sst->dtdy, 0); ISET(sst->dwdy, 0); ISET(sst->triangleCMD, 0); ISET(sst->vB.x, (x<vB.y, ((y+tSize)<triangleCMD, 0xFFFFFFFF); } #pragma optimize ("",on)