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