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