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