102be438aSmrg 202be438aSmrg#ifdef HAVE_CONFIG_H 302be438aSmrg#include "config.h" 402be438aSmrg#endif 502be438aSmrg 6ee74aa5cSmrg#include <sys/time.h> 7ee74aa5cSmrg 802be438aSmrg#include "xf86.h" 902be438aSmrg#include "xf86_OSproc.h" 1002be438aSmrg#include "xf86fbman.h" 1102be438aSmrg#include "compiler.h" 1202be438aSmrg#include "tdfx.h" 1302be438aSmrg 1402be438aSmrg/* 1502be438aSmrg Memory layout of card is as follows: 1602be438aSmrg 1702be438aSmrg 000000-00ffff: VGA memory 1802be438aSmrg 010000-013fff: Cursor 1902be438aSmrg 011000-xxxxxx: Fifo (Min of CMDFIFO pages) 2002be438aSmrg xxxxxx- A-1 : Front Buffer (framebuffer) 2102be438aSmrg A - B-1 : Pixmap Cache (framebuffer) 2202be438aSmrg B - C-1 : Texture Memory 2302be438aSmrg C - D-1 : Back Buffer 2402be438aSmrg D - E-1 : Depth Buffer 2502be438aSmrg 2602be438aSmrg NB: pixmap cache usually butts right up against texture memory. when 2702be438aSmrg 3d is disabled (via Transition2D) then the pixmap cache is increased 2802be438aSmrg to overlap the texture memory. maximum pixmap cache of 4095 lines on 2902be438aSmrg voodoo5 and 2048 on voodoo3/4 applies. 3002be438aSmrg*/ 3102be438aSmrg 3202be438aSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN 3302be438aSmrgvoid TDFXWriteFifo_24(TDFXPtr pTDFX, int val) { 3402be438aSmrg *pTDFX->fifoPtr++ = val; 3502be438aSmrg} 3602be438aSmrg 3702be438aSmrgvoid TDFXWriteFifo_16(TDFXPtr pTDFX, int val) { 3802be438aSmrg *pTDFX->fifoPtr++ = BE_WSWAP32(val); 3902be438aSmrg} 4002be438aSmrg 4102be438aSmrgvoid TDFXWriteFifo_8(TDFXPtr pTDFX, int val) { 4202be438aSmrg *pTDFX->fifoPtr++ = BE_BSWAP32(val); 4302be438aSmrg} 4402be438aSmrg#endif 4502be438aSmrg 4602be438aSmrg 4702be438aSmrgstatic void TDFXSendNOPFifo3D(ScrnInfoPtr pScrn) 4802be438aSmrg{ 4902be438aSmrg TDFXPtr pTDFX; 5002be438aSmrg 5102be438aSmrg pTDFX=TDFXPTR(pScrn); 5202be438aSmrg TDFXAllocateSlots(pTDFX, 2); 5302be438aSmrg SET_3DPK4_HEADER(1, 0x48<<3); 5402be438aSmrg WRITE_FIFO(pTDFX, 0, 0); 5502be438aSmrg} 5602be438aSmrg 5702be438aSmrgvoid TDFXSendNOPFifo2D(ScrnInfoPtr pScrn) 5802be438aSmrg{ 5902be438aSmrg TDFXPtr pTDFX; 6002be438aSmrg 6102be438aSmrg pTDFX=TDFXPTR(pScrn); 6202be438aSmrg if (!pTDFX->syncDone) { 6302be438aSmrg TDFXFirstSync(pScrn); 6402be438aSmrg return; 6502be438aSmrg } 6602be438aSmrg TDFXAllocateSlots(pTDFX, 2); 6702be438aSmrg SET_PKT2_HEADER(SSTCP_COMMAND); 6802be438aSmrg WRITE_FIFO(pTDFX, SST_2D_COMMAND, SST_2D_NOP|SST_2D_GO); 6902be438aSmrg} 7002be438aSmrg 7102be438aSmrgvoid TDFXSendNOPFifo(ScrnInfoPtr pScrn) 7202be438aSmrg{ 7302be438aSmrg TDFXSendNOPFifo2D(pScrn); 7402be438aSmrg TDFXSendNOPFifo3D(pScrn); 7502be438aSmrg} 7602be438aSmrg 7702be438aSmrgstatic void InstallFifo(ScrnInfoPtr pScrn) 7802be438aSmrg{ 7902be438aSmrg TDFXPtr pTDFX; 8002be438aSmrg 8102be438aSmrg pTDFX=TDFXPTR(pScrn); 8202be438aSmrg /* Install the fifo */ 8302be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASEADDR0, pTDFX->fifoOffset>>12); 8402be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_BUMP0, 0); 8502be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_RDPTRL0, pTDFX->fifoOffset); 8602be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_RDPTRH0, 0); 8702be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_AMIN0, pTDFX->fifoOffset-4); 8802be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_AMAX0, pTDFX->fifoOffset-4); 8902be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_DEPTH0, 0); 9002be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_HOLECNT0, 0); 9102be438aSmrg if (pTDFX->ChipType == PCI_CHIP_BANSHEE) 9202be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_FIFOTHRESH, (0x9<<5) | 0x2); 9302be438aSmrg else 9402be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_FIFOTHRESH, (0xf<<5) | 0x8); 9502be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, ((pTDFX->fifoSize>>12)-1) | 9602be438aSmrg SST_EN_CMDFIFO); 9702be438aSmrg /* Set the internal state */ 9802be438aSmrg pTDFX->fifoRead = pTDFX->fifoBase; 9902be438aSmrg pTDFX->fifoPtr = pTDFX->fifoBase; 10002be438aSmrg pTDFX->fifoSlots = (pTDFX->fifoSize>>2) - 1; 10102be438aSmrg pTDFX->fifoEnd = pTDFX->fifoBase+pTDFX->fifoSlots; 10202be438aSmrg TDFXSendNOPFifo(pScrn); 10302be438aSmrg} 10402be438aSmrg 10502be438aSmrgstatic void TDFXResetFifo(ScrnInfoPtr pScrn) 10602be438aSmrg{ 10702be438aSmrg TDFXPtr pTDFX; 10802be438aSmrg int oldValue; 109880ed95aSmrg struct timeval start, stop; 11002be438aSmrg 11102be438aSmrg pTDFX=TDFXPTR(pScrn); 11202be438aSmrg ErrorF("Resetting FIFO\n"); 11302be438aSmrg /* Shut down the fifo */ 11402be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, 0); 11502be438aSmrg /* Toggle the reset bits */ 11602be438aSmrg oldValue=TDFXReadLongMMIO(pTDFX, MISCINIT0); 11702be438aSmrg TDFXWriteLongMMIO(pTDFX, MISCINIT0, oldValue|0x23); 118880ed95aSmrg gettimeofday(&start, NULL); 11902be438aSmrg do { 120880ed95aSmrg gettimeofday(&stop, NULL); 121880ed95aSmrg } while (stop.tv_sec - start.tv_sec < 2); 12202be438aSmrg TDFXWriteLongMMIO(pTDFX, MISCINIT0, oldValue); 12302be438aSmrg oldValue=TDFXReadLongMMIO(pTDFX, MISCINIT1); 12402be438aSmrg TDFXWriteLongMMIO(pTDFX, MISCINIT1, oldValue|BIT(19)); 125880ed95aSmrg gettimeofday(&start, NULL); 12602be438aSmrg do { 127880ed95aSmrg gettimeofday(&stop, NULL); 128880ed95aSmrg } while (stop.tv_sec - start.tv_sec < 2); 12902be438aSmrg TDFXWriteLongMMIO(pTDFX, MISCINIT1, oldValue); 13002be438aSmrg InstallFifo(pScrn); 13102be438aSmrg} 13202be438aSmrg 13302be438aSmrg/* 13402be438aSmrg There are two steps to fully syncing the board: 13502be438aSmrg 13602be438aSmrg 1) Send a NOP, which waits for any commands in progress 13702be438aSmrg 2) Read the status register for 3 consecutive non-busy 13802be438aSmrg 13902be438aSmrg !!! We should use expedential backoff in our reads !!! 14002be438aSmrg*/ 14102be438aSmrgstatic void TDFXSyncFifo(ScrnInfoPtr pScrn) 14202be438aSmrg{ 14302be438aSmrg TDFXPtr pTDFX; 14402be438aSmrg int i, cnt, resets=0; 14502be438aSmrg int stat; 146880ed95aSmrg long tmp, readptr; 147880ed95aSmrg struct timeval start, stop; 14802be438aSmrg 14902be438aSmrg TDFXTRACEACCEL("TDFXSyncFifo start\n"); 15002be438aSmrg pTDFX=TDFXPTR(pScrn); 15102be438aSmrg TDFXSendNOPFifo(pScrn); 15202be438aSmrg i=0; 15302be438aSmrg cnt=0; 154880ed95aSmrg start.tv_sec=0; 155880ed95aSmrg 15602be438aSmrg readptr=TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0); 15702be438aSmrg do { 15802be438aSmrg readptr=TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0); 15902be438aSmrg stat=TDFXReadLongMMIO(pTDFX, 0); 16002be438aSmrg if (stat&SST_BUSY) i=0; else i++; 16102be438aSmrg cnt++; 16202be438aSmrg if (cnt==1000) { 163880ed95aSmrg if (!start.tv_sec) { 164880ed95aSmrg gettimeofday(&start, NULL); 16502be438aSmrg } else { 166880ed95aSmrg gettimeofday(&stop, NULL); 167880ed95aSmrg if (stop.tv_sec - start.tv_sec > 3) { 168880ed95aSmrg tmp = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0); 169880ed95aSmrg if (tmp == readptr) { 17002be438aSmrg TDFXResetFifo(pScrn); 171880ed95aSmrg readptr = tmp; 17202be438aSmrg resets++; 17302be438aSmrg if (resets==3) { 17402be438aSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 17502be438aSmrg "Board is not responding.\n"); 17602be438aSmrg return; 17702be438aSmrg } 17802be438aSmrg } 179880ed95aSmrg start.tv_sec=0; 18002be438aSmrg } 18102be438aSmrg } 18202be438aSmrg cnt=0; 18302be438aSmrg } 18402be438aSmrg } while (i<3); 18502be438aSmrg pTDFX->PciCnt=stat&0x1F; 18602be438aSmrg pTDFX->prevBlitDest.x1=pTDFX->prevBlitDest.y1=0; 18702be438aSmrg pTDFX->prevBlitDest.x2=pTDFX->prevBlitDest.y2=0; 18802be438aSmrg} 18902be438aSmrg 19002be438aSmrgBool TDFXInitFifo(ScreenPtr pScreen) 19102be438aSmrg{ 19202be438aSmrg ScrnInfoPtr pScrn; 19302be438aSmrg TDFXPtr pTDFX; 19402be438aSmrg 1953a56a767Smrg pScrn = xf86ScreenToScrn(pScreen); 19602be438aSmrg pTDFX=TDFXPTR(pScrn); 19702be438aSmrg#ifdef DEBUG_FIFO 19802be438aSmrg pTDFX->fifoMirrorBase=0; 19902be438aSmrg#endif 20002be438aSmrg pTDFX->fifoBase = (uint32*)(pTDFX->FbBase+pTDFX->fifoOffset); 20102be438aSmrg#ifdef DEBUG_FIFO 2023a56a767Smrg pTDFX->fifoMirrorBase = malloc(pTDFX->fifoSize); 20302be438aSmrg pTDFX->fifoMirrorPtr = pTDFX->fifoMirrorBase; 20402be438aSmrg#endif 20502be438aSmrg pTDFX->sync=TDFXSyncFifo; 20602be438aSmrg InstallFifo(pScrn); 20702be438aSmrg return TRUE; 20802be438aSmrg} 20902be438aSmrg 21002be438aSmrgvoid TDFXShutdownFifo(ScreenPtr pScreen) 21102be438aSmrg{ 21202be438aSmrg ScrnInfoPtr pScrn; 21302be438aSmrg TDFXPtr pTDFX; 21402be438aSmrg 2153a56a767Smrg pScrn = xf86ScreenToScrn(pScreen); 21602be438aSmrg pTDFX=TDFXPTR(pScrn); 21702be438aSmrg TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, 0); 21802be438aSmrg pTDFX->sync=TDFXSync; 21902be438aSmrg#ifdef DEBUG_FIFO 2203a56a767Smrg if (pTDFX->fifoMirrorBase) free(pTDFX->fifoMirrorBase); 22102be438aSmrg pTDFX->fifoMirrorBase=0; 22202be438aSmrg#endif 22302be438aSmrg} 22402be438aSmrg 22502be438aSmrgstatic uint32 22602be438aSmrgGetReadPtr(TDFXPtr pTDFX) 22702be438aSmrg{ 22802be438aSmrg uint32 read_ptr, dummy; 22902be438aSmrg 23002be438aSmrg do { 23102be438aSmrg dummy = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0); 23202be438aSmrg read_ptr = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0); 23302be438aSmrg } while (read_ptr != dummy); 23402be438aSmrg return read_ptr; 23502be438aSmrg} 23602be438aSmrg 2373a56a767Smrg#ifdef TDFXDRI 23802be438aSmrgvoid TDFXSwapContextFifo(ScreenPtr pScreen) 23902be438aSmrg{ 24002be438aSmrg ScrnInfoPtr pScrn; 24102be438aSmrg TDFXPtr pTDFX; 24202be438aSmrg int dummy, readPos; 243daa73adaSmrg#if 0 24402be438aSmrg TDFXSAREAPriv *sPriv; 245daa73adaSmrg#endif 24602be438aSmrg 2473a56a767Smrg pScrn = xf86ScreenToScrn(pScreen); 24802be438aSmrg pTDFX=TDFXPTR(pScrn); 249daa73adaSmrg#if 0 25002be438aSmrg sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen); 251daa73adaSmrg#endif 25202be438aSmrg /* if (sPriv) 25302be438aSmrg ErrorF("In FifoPtr=%d FifoRead=%d\n", sPriv->fifoPtr, sPriv->fifoRead); */ 25402be438aSmrg#if 1 25502be438aSmrg do { 25602be438aSmrg dummy=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0); 25702be438aSmrg readPos=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0); 25802be438aSmrg } while (dummy || readPos); 25902be438aSmrg readPos=(GetReadPtr(pTDFX)-pTDFX->fifoOffset)>>2; 26002be438aSmrg pTDFX->fifoPtr = pTDFX->fifoBase+readPos; 26102be438aSmrg pTDFX->fifoRead = pTDFX->fifoPtr; 26202be438aSmrg#else 26302be438aSmrg sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen); 26402be438aSmrg if (!sPriv) return; 26502be438aSmrg if ((sPriv->fifoPtr<pTDFX->fifoOffset) || 26602be438aSmrg (sPriv->fifoPtr>(int)pTDFX->fifoOffset+pTDFX->fifoSize) || 26702be438aSmrg (sPriv->fifoRead<pTDFX->fifoOffset) || 26802be438aSmrg (sPriv->fifoRead>(int)pTDFX->fifoOffset+pTDFX->fifoSize)) { 26902be438aSmrg ErrorF("Invalid offsets passed between client and X server\n"); 27002be438aSmrg ResetFifo(pScrn); 27102be438aSmrg } else { 27202be438aSmrg pTDFX->fifoPtr = (unsigned int *)(pTDFX->FbBase+sPriv->fifoPtr); 27302be438aSmrg pTDFX->fifoRead = (unsigned int *)(pTDFX->FbBase+sPriv->fifoRead); 27402be438aSmrg } 27502be438aSmrg#endif 27602be438aSmrg if (pTDFX->fifoRead>pTDFX->fifoPtr) 27702be438aSmrg pTDFX->fifoSlots = pTDFX->fifoRead-pTDFX->fifoPtr-1-8; 27802be438aSmrg else 27902be438aSmrg pTDFX->fifoSlots = pTDFX->fifoEnd-pTDFX->fifoPtr-8; 28002be438aSmrg} 28102be438aSmrg 28202be438aSmrg#endif 28302be438aSmrg 28402be438aSmrgstatic void 28502be438aSmrgTDFXMakeSpace(TDFXPtr pTDFX, uint32 slots) 28602be438aSmrg{ 28702be438aSmrg uint32 slots_available; 28802be438aSmrg 28902be438aSmrg /* 29002be438aSmrg ** Check to see if we have to wrap to get enough space. 29102be438aSmrg */ 29202be438aSmrg if (slots > pTDFX->fifoEnd-pTDFX->fifoPtr) { 29302be438aSmrg /* 29402be438aSmrg ** Make sure that the read pointer is not ahead of us in the 29502be438aSmrg ** the command fifo before wrapping. 29602be438aSmrg ** This insures two things: 29702be438aSmrg ** 1) There is room at fifo_ptr for the JMP packet. 29802be438aSmrg ** 2) There are slots available at the beginning of the fifo up to the read_ptr. 29902be438aSmrg ** 30002be438aSmrg ** Since we are wrapping, insure that the read pointer is not at the 30102be438aSmrg ** beginning of the fifo to prevent the ambiguous situation described 30202be438aSmrg ** below. 30302be438aSmrg */ 30402be438aSmrg do { 30502be438aSmrg pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX)); 30602be438aSmrg } 30702be438aSmrg while (pTDFX->fifoRead>pTDFX->fifoPtr || 30802be438aSmrg pTDFX->fifoRead == pTDFX->fifoBase); 30902be438aSmrg /* 31002be438aSmrg ** Put a jump command in command fifo to wrap to the beginning. 31102be438aSmrg */ 31202be438aSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN 31302be438aSmrg WRITE_FIFO(pTDFX, 0, (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT | 31402be438aSmrg SSTCP_PKT0_JMP_LOCAL); 31502be438aSmrg#else 31602be438aSmrg *pTDFX->fifoPtr = (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT | 31702be438aSmrg SSTCP_PKT0_JMP_LOCAL; 31802be438aSmrg#endif 31902be438aSmrg FLUSH_WCB(); 32002be438aSmrg 32102be438aSmrg /* 32202be438aSmrg ** Reset the fifo_ptr to the beginning of the command fifo. 32302be438aSmrg */ 32402be438aSmrg pTDFX->fifoPtr = pTDFX->fifoBase; 32502be438aSmrg#ifdef DEBUG_FIFO 32602be438aSmrg pTDFX->fifoMirrorPtr = pTDFX->fifoMirrorBase; 32702be438aSmrg#endif 32802be438aSmrg } 32902be438aSmrg 33002be438aSmrg /* 33102be438aSmrg ** Wait for enough slots to satisfy the request. 33202be438aSmrg */ 33302be438aSmrg do { 33402be438aSmrg pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX)); 33502be438aSmrg 33602be438aSmrg /* 33702be438aSmrg ** If the HW read_ptr is ahead the SW fifo_ptr, we don't allocate the 33802be438aSmrg ** fifo slot immediately behind the HW read_ptr. This is to prevent 33902be438aSmrg ** the following ambiguous situation... 34002be438aSmrg ** 34102be438aSmrg ** If (HW read_ptr == SW fifo_ptr) is it because the HW read_ptr has 34202be438aSmrg ** caught up to the SW fifo_ptr and the fifo is completely empty 34302be438aSmrg ** OR is it because the SW fifo_ptr has caught up to the HW read_ptr 34402be438aSmrg ** and the fifo is completely full? 34502be438aSmrg */ 34602be438aSmrg if ((uint32*)pTDFX->fifoRead > pTDFX->fifoPtr) 34702be438aSmrg slots_available = pTDFX->fifoRead - pTDFX->fifoPtr - 1; 34802be438aSmrg else 34902be438aSmrg slots_available = pTDFX->fifoEnd - pTDFX->fifoPtr; 35002be438aSmrg } while (slots > slots_available); 35102be438aSmrg 35202be438aSmrg pTDFX->fifoSlots = slots_available-slots; 35302be438aSmrg} 35402be438aSmrg 35502be438aSmrgvoid 35602be438aSmrgTDFXAllocateSlots(TDFXPtr pTDFX, int slots) 35702be438aSmrg{ 35802be438aSmrg#ifdef TDFX_DEBUG_FIFO 35902be438aSmrg if (pTDFX->fifoEnd-pTDFX->fifoPtr<pTDFX->fifoSlots) 36002be438aSmrg ErrorF("FIFO overrun\n"); 36102be438aSmrg if (!pTDFX->syncDone) { 36202be438aSmrg ErrorF("Writing to FIFO without sync\n"); 36302be438aSmrg } 36402be438aSmrg#endif 36502be438aSmrg pTDFX->fifoSlots-=slots; 36602be438aSmrg if (pTDFX->fifoSlots<0) TDFXMakeSpace(pTDFX, slots); 36702be438aSmrg} 368