Home | History | Annotate | Line # | Download | only in src
      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
     33 void TDFXWriteFifo_24(TDFXPtr pTDFX, int val) {
     34   *pTDFX->fifoPtr++ = val;
     35 }
     36 
     37 void TDFXWriteFifo_16(TDFXPtr pTDFX, int val) {
     38   *pTDFX->fifoPtr++ = BE_WSWAP32(val);
     39 }
     40 
     41 void TDFXWriteFifo_8(TDFXPtr pTDFX, int val) {
     42   *pTDFX->fifoPtr++ = BE_BSWAP32(val);
     43 }
     44 #endif
     45 
     46 
     47 static 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 
     57 void 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 
     71 void TDFXSendNOPFifo(ScrnInfoPtr pScrn)
     72 {
     73   TDFXSendNOPFifo2D(pScrn);
     74   TDFXSendNOPFifo3D(pScrn);
     75 }
     76 
     77 static 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 
    105 static 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 */
    141 static 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 
    190 Bool 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 
    210 void 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 
    225 static uint32
    226 GetReadPtr(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
    238 void 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 
    284 static void
    285 TDFXMakeSpace(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 
    355 void
    356 TDFXAllocateSlots(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