tdfx_priv.c revision 880ed95a
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include "xf86.h"
7#include "xf86_OSproc.h"
8#include "xf86fbman.h"
9#include "compiler.h"
10#include "tdfx.h"
11
12/*
13  Memory layout of card is as follows:
14
15  000000-00ffff: VGA memory
16  010000-013fff: Cursor
17  011000-xxxxxx: Fifo (Min of CMDFIFO pages)
18  xxxxxx- A-1  : Front Buffer (framebuffer)
19   A    - B-1  : Pixmap Cache (framebuffer)
20   B    - C-1  : Texture Memory
21   C    - D-1  : Back Buffer
22   D    - E-1  : Depth Buffer
23
24  NB: pixmap cache usually butts right up against texture memory. when
25  3d is disabled (via Transition2D) then the pixmap cache is increased
26  to overlap the texture memory. maximum pixmap cache of 4095 lines on
27  voodoo5 and 2048 on voodoo3/4 applies.
28*/
29
30#if X_BYTE_ORDER == X_BIG_ENDIAN
31void TDFXWriteFifo_24(TDFXPtr pTDFX, int val) {
32  *pTDFX->fifoPtr++ = val;
33}
34
35void TDFXWriteFifo_16(TDFXPtr pTDFX, int val) {
36  *pTDFX->fifoPtr++ = BE_WSWAP32(val);
37}
38
39void TDFXWriteFifo_8(TDFXPtr pTDFX, int val) {
40  *pTDFX->fifoPtr++ = BE_BSWAP32(val);
41}
42#endif
43
44
45static void TDFXSendNOPFifo3D(ScrnInfoPtr pScrn)
46{
47  TDFXPtr pTDFX;
48
49  pTDFX=TDFXPTR(pScrn);
50  TDFXAllocateSlots(pTDFX, 2);
51  SET_3DPK4_HEADER(1, 0x48<<3);
52  WRITE_FIFO(pTDFX, 0, 0);
53}
54
55void TDFXSendNOPFifo2D(ScrnInfoPtr pScrn)
56{
57  TDFXPtr pTDFX;
58
59  pTDFX=TDFXPTR(pScrn);
60  if (!pTDFX->syncDone) {
61    TDFXFirstSync(pScrn);
62    return;
63  }
64  TDFXAllocateSlots(pTDFX, 2);
65  SET_PKT2_HEADER(SSTCP_COMMAND);
66  WRITE_FIFO(pTDFX, SST_2D_COMMAND, SST_2D_NOP|SST_2D_GO);
67}
68
69void TDFXSendNOPFifo(ScrnInfoPtr pScrn)
70{
71  TDFXSendNOPFifo2D(pScrn);
72  TDFXSendNOPFifo3D(pScrn);
73}
74
75static void InstallFifo(ScrnInfoPtr pScrn)
76{
77  TDFXPtr pTDFX;
78
79  pTDFX=TDFXPTR(pScrn);
80  /* Install the fifo */
81  TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASEADDR0, pTDFX->fifoOffset>>12);
82  TDFXWriteLongMMIO(pTDFX, SST_FIFO_BUMP0, 0);
83  TDFXWriteLongMMIO(pTDFX, SST_FIFO_RDPTRL0, pTDFX->fifoOffset);
84  TDFXWriteLongMMIO(pTDFX, SST_FIFO_RDPTRH0, 0);
85  TDFXWriteLongMMIO(pTDFX, SST_FIFO_AMIN0, pTDFX->fifoOffset-4);
86  TDFXWriteLongMMIO(pTDFX, SST_FIFO_AMAX0, pTDFX->fifoOffset-4);
87  TDFXWriteLongMMIO(pTDFX, SST_FIFO_DEPTH0, 0);
88  TDFXWriteLongMMIO(pTDFX, SST_FIFO_HOLECNT0, 0);
89  if (pTDFX->ChipType == PCI_CHIP_BANSHEE)
90    TDFXWriteLongMMIO(pTDFX, SST_FIFO_FIFOTHRESH, (0x9<<5) | 0x2);
91  else
92    TDFXWriteLongMMIO(pTDFX, SST_FIFO_FIFOTHRESH, (0xf<<5) | 0x8);
93  TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, ((pTDFX->fifoSize>>12)-1) |
94		    SST_EN_CMDFIFO);
95  /* Set the internal state */
96  pTDFX->fifoRead = pTDFX->fifoBase;
97  pTDFX->fifoPtr = pTDFX->fifoBase;
98  pTDFX->fifoSlots = (pTDFX->fifoSize>>2) - 1;
99  pTDFX->fifoEnd = pTDFX->fifoBase+pTDFX->fifoSlots;
100  TDFXSendNOPFifo(pScrn);
101}
102
103static void TDFXResetFifo(ScrnInfoPtr pScrn)
104{
105  TDFXPtr pTDFX;
106  int oldValue;
107  struct timeval start, stop;
108
109  pTDFX=TDFXPTR(pScrn);
110  ErrorF("Resetting FIFO\n");
111  /* Shut down the fifo */
112  TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, 0);
113  /* Toggle the reset bits */
114  oldValue=TDFXReadLongMMIO(pTDFX, MISCINIT0);
115  TDFXWriteLongMMIO(pTDFX, MISCINIT0, oldValue|0x23);
116  gettimeofday(&start, NULL);
117  do {
118    gettimeofday(&stop, NULL);
119  } while (stop.tv_sec - start.tv_sec < 2);
120  TDFXWriteLongMMIO(pTDFX, MISCINIT0, oldValue);
121  oldValue=TDFXReadLongMMIO(pTDFX, MISCINIT1);
122  TDFXWriteLongMMIO(pTDFX, MISCINIT1, oldValue|BIT(19));
123  gettimeofday(&start, NULL);
124  do {
125    gettimeofday(&stop, NULL);
126  } while (stop.tv_sec - start.tv_sec < 2);
127  TDFXWriteLongMMIO(pTDFX, MISCINIT1, oldValue);
128  InstallFifo(pScrn);
129}
130
131/*
132  There are two steps to fully syncing the board:
133
134  1) Send a NOP, which waits for any commands in progress
135  2) Read the status register for 3 consecutive non-busy
136
137  !!! We should use expedential backoff in our reads !!!
138*/
139static void TDFXSyncFifo(ScrnInfoPtr pScrn)
140{
141  TDFXPtr pTDFX;
142  int i, cnt, resets=0;
143  int stat;
144  long tmp, readptr;
145  struct timeval start, stop;
146
147  TDFXTRACEACCEL("TDFXSyncFifo start\n");
148  pTDFX=TDFXPTR(pScrn);
149  TDFXSendNOPFifo(pScrn);
150  i=0;
151  cnt=0;
152  start.tv_sec=0;
153
154  readptr=TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0);
155  do {
156    readptr=TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0);
157    stat=TDFXReadLongMMIO(pTDFX, 0);
158    if (stat&SST_BUSY) i=0; else i++;
159    cnt++;
160    if (cnt==1000) {
161      if (!start.tv_sec) {
162        gettimeofday(&start, NULL);
163      } else {
164        gettimeofday(&stop, NULL);
165	if (stop.tv_sec - start.tv_sec > 3) {
166	  tmp = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0);
167	  if (tmp == readptr) {
168	    TDFXResetFifo(pScrn);
169	    readptr = tmp;
170	    resets++;
171	    if (resets==3) {
172	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
173			 "Board is not responding.\n");
174	      return;
175	    }
176	  }
177	  start.tv_sec=0;
178        }
179      }
180      cnt=0;
181    }
182  } while (i<3);
183  pTDFX->PciCnt=stat&0x1F;
184  pTDFX->prevBlitDest.x1=pTDFX->prevBlitDest.y1=0;
185  pTDFX->prevBlitDest.x2=pTDFX->prevBlitDest.y2=0;
186}
187
188Bool TDFXInitFifo(ScreenPtr pScreen)
189{
190  ScrnInfoPtr pScrn;
191  TDFXPtr pTDFX;
192
193  pScrn = xf86Screens[pScreen->myNum];
194  pTDFX=TDFXPTR(pScrn);
195#ifdef DEBUG_FIFO
196  pTDFX->fifoMirrorBase=0;
197#endif
198  pTDFX->fifoBase = (uint32*)(pTDFX->FbBase+pTDFX->fifoOffset);
199#ifdef DEBUG_FIFO
200  pTDFX->fifoMirrorBase = xalloc(pTDFX->fifoSize);
201  pTDFX->fifoMirrorPtr = pTDFX->fifoMirrorBase;
202#endif
203  pTDFX->sync=TDFXSyncFifo;
204  InstallFifo(pScrn);
205  return TRUE;
206}
207
208void TDFXShutdownFifo(ScreenPtr pScreen)
209{
210  ScrnInfoPtr pScrn;
211  TDFXPtr pTDFX;
212
213  pScrn = xf86Screens[pScreen->myNum];
214  pTDFX=TDFXPTR(pScrn);
215  TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, 0);
216  pTDFX->sync=TDFXSync;
217#ifdef DEBUG_FIFO
218  if (pTDFX->fifoMirrorBase) xfree(pTDFX->fifoMirrorBase);
219  pTDFX->fifoMirrorBase=0;
220#endif
221}
222
223static uint32
224GetReadPtr(TDFXPtr pTDFX)
225{
226  uint32 read_ptr, dummy;
227
228  do {
229    dummy = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0);
230    read_ptr = TDFXReadLongMMIO(pTDFX, SST_FIFO_RDPTRL0);
231  } while (read_ptr != dummy);
232  return read_ptr;
233}
234
235#ifdef XF86DRI
236void TDFXSwapContextFifo(ScreenPtr pScreen)
237{
238  ScrnInfoPtr pScrn;
239  TDFXPtr pTDFX;
240  int dummy, readPos;
241  TDFXSAREAPriv *sPriv;
242
243  pScrn = xf86Screens[pScreen->myNum];
244  pTDFX=TDFXPTR(pScrn);
245  sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen);
246  /* if (sPriv)
247     ErrorF("In FifoPtr=%d FifoRead=%d\n", sPriv->fifoPtr, sPriv->fifoRead); */
248#if 1
249  do {
250    dummy=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0);
251    readPos=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0);
252  } while (dummy || readPos);
253  readPos=(GetReadPtr(pTDFX)-pTDFX->fifoOffset)>>2;
254  pTDFX->fifoPtr = pTDFX->fifoBase+readPos;
255  pTDFX->fifoRead = pTDFX->fifoPtr;
256#else
257  sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen);
258  if (!sPriv) return;
259  if ((sPriv->fifoPtr<pTDFX->fifoOffset) ||
260      (sPriv->fifoPtr>(int)pTDFX->fifoOffset+pTDFX->fifoSize) ||
261      (sPriv->fifoRead<pTDFX->fifoOffset) ||
262      (sPriv->fifoRead>(int)pTDFX->fifoOffset+pTDFX->fifoSize)) {
263    ErrorF("Invalid offsets passed between client and X server\n");
264    ResetFifo(pScrn);
265  } else {
266    pTDFX->fifoPtr = (unsigned int *)(pTDFX->FbBase+sPriv->fifoPtr);
267    pTDFX->fifoRead = (unsigned int *)(pTDFX->FbBase+sPriv->fifoRead);
268  }
269#endif
270  if (pTDFX->fifoRead>pTDFX->fifoPtr)
271    pTDFX->fifoSlots = pTDFX->fifoRead-pTDFX->fifoPtr-1-8;
272  else
273    pTDFX->fifoSlots = pTDFX->fifoEnd-pTDFX->fifoPtr-8;
274}
275
276#endif
277
278static void
279TDFXMakeSpace(TDFXPtr pTDFX, uint32 slots)
280{
281  uint32 slots_available;
282
283  /*
284  ** Check to see if we have to wrap to get enough space.
285  */
286  if (slots > pTDFX->fifoEnd-pTDFX->fifoPtr) {
287    /*
288    ** Make sure that the read pointer is not ahead of us in the
289    ** the command fifo before wrapping.
290    ** This insures two things:
291    **   1) There is room at fifo_ptr for the JMP packet.
292    **   2) There are slots available at the beginning of the fifo up to the read_ptr.
293    **
294    ** Since we are wrapping, insure that the read pointer is not at the
295    ** beginning of the fifo to prevent the ambiguous situation described
296    ** below.
297    */
298    do {
299      pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX));
300    }
301    while (pTDFX->fifoRead>pTDFX->fifoPtr ||
302	   pTDFX->fifoRead == pTDFX->fifoBase);
303    /*
304    ** Put a jump command in command fifo to wrap to the beginning.
305    */
306#if X_BYTE_ORDER == X_BIG_ENDIAN
307    WRITE_FIFO(pTDFX, 0, (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT |
308      SSTCP_PKT0_JMP_LOCAL);
309#else
310    *pTDFX->fifoPtr = (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT |
311      SSTCP_PKT0_JMP_LOCAL;
312#endif
313    FLUSH_WCB();
314
315    /*
316    ** Reset the fifo_ptr to the beginning of the command fifo.
317    */
318    pTDFX->fifoPtr = pTDFX->fifoBase;
319#ifdef DEBUG_FIFO
320    pTDFX->fifoMirrorPtr = pTDFX->fifoMirrorBase;
321#endif
322  }
323
324  /*
325  ** Wait for enough slots to satisfy the request.
326  */
327  do {
328    pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX));
329
330    /*
331    ** If the HW read_ptr is ahead the SW fifo_ptr, we don't allocate the
332    ** fifo slot immediately behind the HW read_ptr.  This is to prevent
333    ** the following ambiguous situation...
334    **
335    ** If (HW read_ptr == SW fifo_ptr) is it because the HW read_ptr has
336    ** caught up to the SW fifo_ptr and the fifo is completely empty
337    ** OR is it because the SW fifo_ptr has caught up to the HW read_ptr
338    ** and the fifo is completely full?
339    */
340    if ((uint32*)pTDFX->fifoRead > pTDFX->fifoPtr)
341      slots_available = pTDFX->fifoRead - pTDFX->fifoPtr - 1;
342    else
343      slots_available = pTDFX->fifoEnd - pTDFX->fifoPtr;
344  } while (slots > slots_available);
345
346  pTDFX->fifoSlots = slots_available-slots;
347}
348
349void
350TDFXAllocateSlots(TDFXPtr pTDFX, int slots)
351{
352#ifdef TDFX_DEBUG_FIFO
353  if (pTDFX->fifoEnd-pTDFX->fifoPtr<pTDFX->fifoSlots)
354    ErrorF("FIFO overrun\n");
355  if (!pTDFX->syncDone) {
356    ErrorF("Writing to FIFO without sync\n");
357  }
358#endif
359  pTDFX->fifoSlots-=slots;
360  if (pTDFX->fifoSlots<0) TDFXMakeSpace(pTDFX, slots);
361}
362