1428d7b3dSmrg 2428d7b3dSmrg/************************************************************************** 3428d7b3dSmrg 4428d7b3dSmrgCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 5428d7b3dSmrgAll Rights Reserved. 6428d7b3dSmrg 7428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a 8428d7b3dSmrgcopy of this software and associated documentation files (the 9428d7b3dSmrg"Software"), to deal in the Software without restriction, including 10428d7b3dSmrgwithout limitation the rights to use, copy, modify, merge, publish, 11428d7b3dSmrgdistribute, sub license, and/or sell copies of the Software, and to 12428d7b3dSmrgpermit persons to whom the Software is furnished to do so, subject to 13428d7b3dSmrgthe following conditions: 14428d7b3dSmrg 15428d7b3dSmrgThe above copyright notice and this permission notice (including the 16428d7b3dSmrgnext paragraph) shall be included in all copies or substantial portions 17428d7b3dSmrgof the Software. 18428d7b3dSmrg 19428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20428d7b3dSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21428d7b3dSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22428d7b3dSmrgIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 23428d7b3dSmrgANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24428d7b3dSmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25428d7b3dSmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26428d7b3dSmrg 27428d7b3dSmrg**************************************************************************/ 28428d7b3dSmrg 29428d7b3dSmrg#ifdef HAVE_CONFIG_H 30428d7b3dSmrg#include "config.h" 31428d7b3dSmrg#endif 32428d7b3dSmrg 33428d7b3dSmrg/* 34428d7b3dSmrg * Authors: 35428d7b3dSmrg * Keith Whitwell <keith@tungstengraphics.com> 36428d7b3dSmrg * 37428d7b3dSmrg */ 38428d7b3dSmrg 39428d7b3dSmrg#include "xorg-server.h" 40428d7b3dSmrg#include "xf86.h" 41428d7b3dSmrg#include "xaarop.h" 42428d7b3dSmrg#include "i810.h" 43428d7b3dSmrg 44428d7b3dSmrgconst int I810CopyROP[16] = { 45428d7b3dSmrg ROP_0, /* GXclear */ 46428d7b3dSmrg ROP_DSa, /* GXand */ 47428d7b3dSmrg ROP_SDna, /* GXandReverse */ 48428d7b3dSmrg ROP_S, /* GXcopy */ 49428d7b3dSmrg ROP_DSna, /* GXandInverted */ 50428d7b3dSmrg ROP_D, /* GXnoop */ 51428d7b3dSmrg ROP_DSx, /* GXxor */ 52428d7b3dSmrg ROP_DSo, /* GXor */ 53428d7b3dSmrg ROP_DSon, /* GXnor */ 54428d7b3dSmrg ROP_DSxn, /* GXequiv */ 55428d7b3dSmrg ROP_Dn, /* GXinvert */ 56428d7b3dSmrg ROP_SDno, /* GXorReverse */ 57428d7b3dSmrg ROP_Sn, /* GXcopyInverted */ 58428d7b3dSmrg ROP_DSno, /* GXorInverted */ 59428d7b3dSmrg ROP_DSan, /* GXnand */ 60428d7b3dSmrg ROP_1 /* GXset */ 61428d7b3dSmrg}; 62428d7b3dSmrg 63428d7b3dSmrgconst int I810PatternROP[16] = { 64428d7b3dSmrg ROP_0, 65428d7b3dSmrg ROP_DPa, 66428d7b3dSmrg ROP_PDna, 67428d7b3dSmrg ROP_P, 68428d7b3dSmrg ROP_DPna, 69428d7b3dSmrg ROP_D, 70428d7b3dSmrg ROP_DPx, 71428d7b3dSmrg ROP_DPo, 72428d7b3dSmrg ROP_DPon, 73428d7b3dSmrg ROP_PDxn, 74428d7b3dSmrg ROP_Dn, 75428d7b3dSmrg ROP_PDno, 76428d7b3dSmrg ROP_Pn, 77428d7b3dSmrg ROP_DPno, 78428d7b3dSmrg ROP_DPan, 79428d7b3dSmrg ROP_1 80428d7b3dSmrg}; 81428d7b3dSmrg 82428d7b3dSmrgint 83428d7b3dSmrgI810WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) 84428d7b3dSmrg{ 85428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 86428d7b3dSmrg I810RingBuffer *ring = pI810->LpRing; 87428d7b3dSmrg int iters = 0; 88428d7b3dSmrg int start = 0; 89428d7b3dSmrg int now = 0; 90428d7b3dSmrg int last_head = 0; 91428d7b3dSmrg int first = 0; 92428d7b3dSmrg 93428d7b3dSmrg /* If your system hasn't moved the head pointer in 2 seconds, I'm going to 94428d7b3dSmrg * call it crashed. 95428d7b3dSmrg */ 96428d7b3dSmrg if (timeout_millis == 0) 97428d7b3dSmrg timeout_millis = 2000; 98428d7b3dSmrg 99428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 100428d7b3dSmrg ErrorF("I810WaitLpRing %d\n", n); 101428d7b3dSmrg first = GetTimeInMillis(); 102428d7b3dSmrg } 103428d7b3dSmrg 104428d7b3dSmrg while (ring->space < n) { 105428d7b3dSmrg ring->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 106428d7b3dSmrg ring->space = ring->head - (ring->tail + 8); 107428d7b3dSmrg 108428d7b3dSmrg if (ring->space < 0) 109428d7b3dSmrg ring->space += ring->mem.Size; 110428d7b3dSmrg 111428d7b3dSmrg iters++; 112428d7b3dSmrg now = GetTimeInMillis(); 113428d7b3dSmrg if (start == 0 || now < start || ring->head != last_head) { 114428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 115428d7b3dSmrg if (now > start) 116428d7b3dSmrg ErrorF("space: %d wanted %d\n", ring->space, n); 117428d7b3dSmrg start = now; 118428d7b3dSmrg last_head = ring->head; 119428d7b3dSmrg } else if (now - start > timeout_millis) { 120428d7b3dSmrg ErrorF("Error in I810WaitLpRing(), now is %d, start is %d\n", now, 121428d7b3dSmrg start); 122428d7b3dSmrg I810PrintErrorState(pScrn); 123428d7b3dSmrg ErrorF("space: %d wanted %d\n", ring->space, n); 124428d7b3dSmrg#ifdef HAVE_DRI1 125428d7b3dSmrg if (pI810->directRenderingEnabled) { 126428d7b3dSmrg DRIUnlock(xf86ScrnToScreen(pScrn)); 127428d7b3dSmrg DRICloseScreen(xf86ScrnToScreen(pScrn)); 128428d7b3dSmrg } 129428d7b3dSmrg#endif 130428d7b3dSmrg#if HAVE_XAA_H 131428d7b3dSmrg pI810->AccelInfoRec = NULL; /* Stops recursive behavior */ 132428d7b3dSmrg#endif 133428d7b3dSmrg FatalError("lockup\n"); 134428d7b3dSmrg } 135428d7b3dSmrg 136428d7b3dSmrg DELAY(10000); 137428d7b3dSmrg } 138428d7b3dSmrg 139428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { 140428d7b3dSmrg now = GetTimeInMillis(); 141428d7b3dSmrg if (now - first) { 142428d7b3dSmrg ErrorF("Elapsed %d ms\n", now - first); 143428d7b3dSmrg ErrorF("space: %d wanted %d\n", ring->space, n); 144428d7b3dSmrg } 145428d7b3dSmrg } 146428d7b3dSmrg 147428d7b3dSmrg return iters; 148428d7b3dSmrg} 149428d7b3dSmrg 150428d7b3dSmrgvoid 151428d7b3dSmrgI810Sync(ScrnInfoPtr pScrn) 152428d7b3dSmrg{ 153428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 154428d7b3dSmrg 155428d7b3dSmrg if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) 156428d7b3dSmrg ErrorF("I810Sync\n"); 157428d7b3dSmrg 158428d7b3dSmrg#ifdef HAVE_DRI1 159428d7b3dSmrg /* VT switching tries to do this. 160428d7b3dSmrg */ 161428d7b3dSmrg if (!pI810->LockHeld && pI810->directRenderingEnabled) { 162428d7b3dSmrg return; 163428d7b3dSmrg } 164428d7b3dSmrg#endif 165428d7b3dSmrg 166428d7b3dSmrg /* Send a flush instruction and then wait till the ring is empty. 167428d7b3dSmrg * This is stronger than waiting for the blitter to finish as it also 168428d7b3dSmrg * flushes the internal graphics caches. 169428d7b3dSmrg */ 170428d7b3dSmrg { 171428d7b3dSmrg BEGIN_LP_RING(2); 172428d7b3dSmrg OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 173428d7b3dSmrg OUT_RING(0); /* pad to quadword */ 174428d7b3dSmrg ADVANCE_LP_RING(); 175428d7b3dSmrg } 176428d7b3dSmrg 177428d7b3dSmrg I810WaitLpRing(pScrn, pI810->LpRing->mem.Size - 8, 0); 178428d7b3dSmrg 179428d7b3dSmrg pI810->LpRing->space = pI810->LpRing->mem.Size - 8; 180428d7b3dSmrg pI810->nextColorExpandBuf = 0; 181428d7b3dSmrg} 182428d7b3dSmrg 183428d7b3dSmrgvoid 184428d7b3dSmrgI810SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, 185428d7b3dSmrg unsigned int planemask) 186428d7b3dSmrg{ 187428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 188428d7b3dSmrg 189428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 190428d7b3dSmrg ErrorF("I810SetupForFillRectSolid color: %x rop: %x mask: %x\n", 191428d7b3dSmrg color, rop, planemask); 192428d7b3dSmrg 193428d7b3dSmrg /* Color blit, p166 */ 194428d7b3dSmrg pI810->BR[13] = (BR13_SOLID_PATTERN | 195428d7b3dSmrg (I810PatternROP[rop] << 16) | 196428d7b3dSmrg (pScrn->displayWidth * pI810->cpp)); 197428d7b3dSmrg pI810->BR[16] = color; 198428d7b3dSmrg} 199428d7b3dSmrg 200428d7b3dSmrgvoid 201428d7b3dSmrgI810SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) 202428d7b3dSmrg{ 203428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 204428d7b3dSmrg 205428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 206428d7b3dSmrg ErrorF("I810SubsequentFillRectSolid %d,%d %dx%d\n", x, y, w, h); 207428d7b3dSmrg 208428d7b3dSmrg { 209428d7b3dSmrg BEGIN_LP_RING(6); 210428d7b3dSmrg 211428d7b3dSmrg OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3); 212428d7b3dSmrg OUT_RING(pI810->BR[13]); 213428d7b3dSmrg OUT_RING((h << 16) | (w * pI810->cpp)); 214428d7b3dSmrg OUT_RING(pI810->bufferOffset + 215428d7b3dSmrg (y * pScrn->displayWidth + x) * pI810->cpp); 216428d7b3dSmrg 217428d7b3dSmrg OUT_RING(pI810->BR[16]); 218428d7b3dSmrg OUT_RING(0); /* pad to quadword */ 219428d7b3dSmrg 220428d7b3dSmrg ADVANCE_LP_RING(); 221428d7b3dSmrg } 222428d7b3dSmrg} 223428d7b3dSmrg 224428d7b3dSmrgvoid 225428d7b3dSmrgI810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, 226428d7b3dSmrg unsigned int planemask, int transparency_color) 227428d7b3dSmrg{ 228428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 229428d7b3dSmrg 230428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 231428d7b3dSmrg ErrorF("I810SetupForScreenToScreenCopy %d %d %x %x %d\n", 232428d7b3dSmrg xdir, ydir, rop, planemask, transparency_color); 233428d7b3dSmrg 234428d7b3dSmrg pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); 235428d7b3dSmrg 236428d7b3dSmrg if (ydir == -1) 237428d7b3dSmrg pI810->BR[13] = (-pI810->BR[13]) & 0xFFFF; 238428d7b3dSmrg if (xdir == -1) 239428d7b3dSmrg pI810->BR[13] |= BR13_RIGHT_TO_LEFT; 240428d7b3dSmrg 241428d7b3dSmrg pI810->BR[13] |= I810CopyROP[rop] << 16; 242428d7b3dSmrg 243428d7b3dSmrg pI810->BR[18] = 0; 244428d7b3dSmrg} 245428d7b3dSmrg 246428d7b3dSmrgvoid 247428d7b3dSmrgI810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, 248428d7b3dSmrg int x2, int y2, int w, int h) 249428d7b3dSmrg{ 250428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 251428d7b3dSmrg int src, dst; 252428d7b3dSmrg int w_back = w; 253428d7b3dSmrg 254428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 255428d7b3dSmrg ErrorF( "I810SubsequentScreenToScreenCopy %d,%d - %d,%d %dx%d\n", 256428d7b3dSmrg x1,y1,x2,y2,w,h); 257428d7b3dSmrg /* 258428d7b3dSmrg * This works around a bug in the i810 drawing engine. 259428d7b3dSmrg * This was developed empirically so it may not catch all 260428d7b3dSmrg * cases. 261428d7b3dSmrg */ 262428d7b3dSmrg#define I810_MWIDTH 8 263428d7b3dSmrg 264428d7b3dSmrg if ( !(pI810->BR[13] & BR13_RIGHT_TO_LEFT) && (y2 - y1) < 3 265428d7b3dSmrg && (y2 - y1) >= 0 && (x2 - x1) <= (w + I810_MWIDTH) 266428d7b3dSmrg && (w > I810_MWIDTH)) 267428d7b3dSmrg w = I810_MWIDTH; 268428d7b3dSmrg do { 269428d7b3dSmrg 270428d7b3dSmrg if (pI810->BR[13] & BR13_PITCH_SIGN_BIT) { 271428d7b3dSmrg src = (y1 + h - 1) * pScrn->displayWidth * pI810->cpp; 272428d7b3dSmrg dst = (y2 + h - 1) * pScrn->displayWidth * pI810->cpp; 273428d7b3dSmrg } else { 274428d7b3dSmrg src = y1 * pScrn->displayWidth * pI810->cpp; 275428d7b3dSmrg dst = y2 * pScrn->displayWidth * pI810->cpp; 276428d7b3dSmrg } 277428d7b3dSmrg 278428d7b3dSmrg if (pI810->BR[13] & BR13_RIGHT_TO_LEFT) { 279428d7b3dSmrg src += (x1 + w - 1) * pI810->cpp + pI810->cpp - 1; 280428d7b3dSmrg dst += (x2 + w - 1) * pI810->cpp + pI810->cpp - 1; 281428d7b3dSmrg } else { 282428d7b3dSmrg src += x1 * pI810->cpp; 283428d7b3dSmrg dst += x2 * pI810->cpp; 284428d7b3dSmrg } 285428d7b3dSmrg 286428d7b3dSmrg 287428d7b3dSmrg /* SRC_COPY_BLT, p169 */ 288428d7b3dSmrg { 289428d7b3dSmrg BEGIN_LP_RING(6); 290428d7b3dSmrg OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); 291428d7b3dSmrg OUT_RING( pI810->BR[13]); 292428d7b3dSmrg 293428d7b3dSmrg OUT_RING( (h << 16) | (w * pI810->cpp)); 294428d7b3dSmrg OUT_RING( pI810->bufferOffset + dst); 295428d7b3dSmrg 296428d7b3dSmrg OUT_RING( pI810->BR[13] & 0xFFFF); 297428d7b3dSmrg OUT_RING( pI810->bufferOffset + src); 298428d7b3dSmrg ADVANCE_LP_RING(); 299428d7b3dSmrg } 300428d7b3dSmrg w_back -= w; 301428d7b3dSmrg if (w_back <= 0) 302428d7b3dSmrg break; 303428d7b3dSmrg x2 += w; 304428d7b3dSmrg x1 += w; 305428d7b3dSmrg if (w_back > I810_MWIDTH) 306428d7b3dSmrg w = I810_MWIDTH; 307428d7b3dSmrg else 308428d7b3dSmrg w = w_back; 309428d7b3dSmrg } while (1); 310428d7b3dSmrg} 311428d7b3dSmrg 312428d7b3dSmrgvoid 313428d7b3dSmrgI810EmitFlush(ScrnInfoPtr pScrn) 314428d7b3dSmrg{ 315428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 316428d7b3dSmrg 317428d7b3dSmrg BEGIN_LP_RING(2); 318428d7b3dSmrg OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); 319428d7b3dSmrg OUT_RING(0); 320428d7b3dSmrg ADVANCE_LP_RING(); 321428d7b3dSmrg} 322428d7b3dSmrg 323428d7b3dSmrgvoid 324428d7b3dSmrgI810SelectBuffer(ScrnInfoPtr pScrn, int buffer) 325428d7b3dSmrg{ 326428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 327428d7b3dSmrg 328428d7b3dSmrg switch (buffer) { 329428d7b3dSmrg case I810_SELECT_BACK: 330428d7b3dSmrg pI810->bufferOffset = pI810->BackBuffer.Start; 331428d7b3dSmrg break; 332428d7b3dSmrg case I810_SELECT_DEPTH: 333428d7b3dSmrg pI810->bufferOffset = pI810->DepthBuffer.Start; 334428d7b3dSmrg break; 335428d7b3dSmrg default: 336428d7b3dSmrg case I810_SELECT_FRONT: 337428d7b3dSmrg pI810->bufferOffset = pI810->FrontBuffer.Start; 338428d7b3dSmrg break; 339428d7b3dSmrg } 340428d7b3dSmrg 341428d7b3dSmrg if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) 342428d7b3dSmrg ErrorF("I810SelectBuffer %d --> offset %x\n", 343428d7b3dSmrg buffer, pI810->bufferOffset); 344428d7b3dSmrg} 345428d7b3dSmrg 346428d7b3dSmrgvoid 347428d7b3dSmrgI810RefreshRing(ScrnInfoPtr pScrn) 348428d7b3dSmrg{ 349428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 350428d7b3dSmrg 351428d7b3dSmrg pI810->LpRing->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; 352428d7b3dSmrg pI810->LpRing->tail = INREG(LP_RING + RING_TAIL); 353428d7b3dSmrg pI810->LpRing->space = pI810->LpRing->head - (pI810->LpRing->tail + 8); 354428d7b3dSmrg if (pI810->LpRing->space < 0) 355428d7b3dSmrg pI810->LpRing->space += pI810->LpRing->mem.Size; 356428d7b3dSmrg 357428d7b3dSmrg#if HAVE_XAA_H 358428d7b3dSmrg if (pI810->AccelInfoRec) 359428d7b3dSmrg pI810->AccelInfoRec->NeedToSync = TRUE; 360428d7b3dSmrg#endif 361428d7b3dSmrg} 362