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