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