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