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