tdfx_priv.c revision daa73ada
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 = xf86ScreenToScrn(pScreen); 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 = malloc(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 = xf86ScreenToScrn(pScreen); 216 pTDFX=TDFXPTR(pScrn); 217 TDFXWriteLongMMIO(pTDFX, SST_FIFO_BASESIZE0, 0); 218 pTDFX->sync=TDFXSync; 219#ifdef DEBUG_FIFO 220 if (pTDFX->fifoMirrorBase) free(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 TDFXDRI 238void TDFXSwapContextFifo(ScreenPtr pScreen) 239{ 240 ScrnInfoPtr pScrn; 241 TDFXPtr pTDFX; 242 int dummy, readPos; 243#if 0 244 TDFXSAREAPriv *sPriv; 245#endif 246 247 pScrn = xf86ScreenToScrn(pScreen); 248 pTDFX=TDFXPTR(pScrn); 249#if 0 250 sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen); 251#endif 252 /* if (sPriv) 253 ErrorF("In FifoPtr=%d FifoRead=%d\n", sPriv->fifoPtr, sPriv->fifoRead); */ 254#if 1 255 do { 256 dummy=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0); 257 readPos=TDFXReadLongMMIO(pTDFX, SST_FIFO_DEPTH0); 258 } while (dummy || readPos); 259 readPos=(GetReadPtr(pTDFX)-pTDFX->fifoOffset)>>2; 260 pTDFX->fifoPtr = pTDFX->fifoBase+readPos; 261 pTDFX->fifoRead = pTDFX->fifoPtr; 262#else 263 sPriv=(TDFXSAREAPriv*)DRIGetSAREAPrivate(pScreen); 264 if (!sPriv) return; 265 if ((sPriv->fifoPtr<pTDFX->fifoOffset) || 266 (sPriv->fifoPtr>(int)pTDFX->fifoOffset+pTDFX->fifoSize) || 267 (sPriv->fifoRead<pTDFX->fifoOffset) || 268 (sPriv->fifoRead>(int)pTDFX->fifoOffset+pTDFX->fifoSize)) { 269 ErrorF("Invalid offsets passed between client and X server\n"); 270 ResetFifo(pScrn); 271 } else { 272 pTDFX->fifoPtr = (unsigned int *)(pTDFX->FbBase+sPriv->fifoPtr); 273 pTDFX->fifoRead = (unsigned int *)(pTDFX->FbBase+sPriv->fifoRead); 274 } 275#endif 276 if (pTDFX->fifoRead>pTDFX->fifoPtr) 277 pTDFX->fifoSlots = pTDFX->fifoRead-pTDFX->fifoPtr-1-8; 278 else 279 pTDFX->fifoSlots = pTDFX->fifoEnd-pTDFX->fifoPtr-8; 280} 281 282#endif 283 284static void 285TDFXMakeSpace(TDFXPtr pTDFX, uint32 slots) 286{ 287 uint32 slots_available; 288 289 /* 290 ** Check to see if we have to wrap to get enough space. 291 */ 292 if (slots > pTDFX->fifoEnd-pTDFX->fifoPtr) { 293 /* 294 ** Make sure that the read pointer is not ahead of us in the 295 ** the command fifo before wrapping. 296 ** This insures two things: 297 ** 1) There is room at fifo_ptr for the JMP packet. 298 ** 2) There are slots available at the beginning of the fifo up to the read_ptr. 299 ** 300 ** Since we are wrapping, insure that the read pointer is not at the 301 ** beginning of the fifo to prevent the ambiguous situation described 302 ** below. 303 */ 304 do { 305 pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX)); 306 } 307 while (pTDFX->fifoRead>pTDFX->fifoPtr || 308 pTDFX->fifoRead == pTDFX->fifoBase); 309 /* 310 ** Put a jump command in command fifo to wrap to the beginning. 311 */ 312#if X_BYTE_ORDER == X_BIG_ENDIAN 313 WRITE_FIFO(pTDFX, 0, (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT | 314 SSTCP_PKT0_JMP_LOCAL); 315#else 316 *pTDFX->fifoPtr = (pTDFX->fifoOffset >> 2) << SSTCP_PKT0_ADDR_SHIFT | 317 SSTCP_PKT0_JMP_LOCAL; 318#endif 319 FLUSH_WCB(); 320 321 /* 322 ** Reset the fifo_ptr to the beginning of the command fifo. 323 */ 324 pTDFX->fifoPtr = pTDFX->fifoBase; 325#ifdef DEBUG_FIFO 326 pTDFX->fifoMirrorPtr = pTDFX->fifoMirrorBase; 327#endif 328 } 329 330 /* 331 ** Wait for enough slots to satisfy the request. 332 */ 333 do { 334 pTDFX->fifoRead = (uint32*)(pTDFX->FbBase + GetReadPtr(pTDFX)); 335 336 /* 337 ** If the HW read_ptr is ahead the SW fifo_ptr, we don't allocate the 338 ** fifo slot immediately behind the HW read_ptr. This is to prevent 339 ** the following ambiguous situation... 340 ** 341 ** If (HW read_ptr == SW fifo_ptr) is it because the HW read_ptr has 342 ** caught up to the SW fifo_ptr and the fifo is completely empty 343 ** OR is it because the SW fifo_ptr has caught up to the HW read_ptr 344 ** and the fifo is completely full? 345 */ 346 if ((uint32*)pTDFX->fifoRead > pTDFX->fifoPtr) 347 slots_available = pTDFX->fifoRead - pTDFX->fifoPtr - 1; 348 else 349 slots_available = pTDFX->fifoEnd - pTDFX->fifoPtr; 350 } while (slots > slots_available); 351 352 pTDFX->fifoSlots = slots_available-slots; 353} 354 355void 356TDFXAllocateSlots(TDFXPtr pTDFX, int slots) 357{ 358#ifdef TDFX_DEBUG_FIFO 359 if (pTDFX->fifoEnd-pTDFX->fifoPtr<pTDFX->fifoSlots) 360 ErrorF("FIFO overrun\n"); 361 if (!pTDFX->syncDone) { 362 ErrorF("Writing to FIFO without sync\n"); 363 } 364#endif 365 pTDFX->fifoSlots-=slots; 366 if (pTDFX->fifoSlots<0) TDFXMakeSpace(pTDFX, slots); 367} 368