1/*
2 * XAA acceleration for CL-GD546x -- The Laugna family
3 *
4 * lg_xaa.c
5 *
6 * (c) 1998 Corin Anderson.
7 *          corina@the4cs.com
8 *          Tukwila, WA
9 *
10 * Much of this code is inspired by the XAA acceleration from XFree86
11 * 3.3.3, laguna_acl.c
12 */
13
14#ifdef HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include "xf86.h"
19#include "xf86_OSproc.h"
20#include "compiler.h"
21
22#include "xf86Pci.h"
23
24#include "vgaHW.h"
25
26#include "cir.h"
27#define _LG_PRIVATE_
28#include "lg.h"
29
30#ifdef HAVE_XAA_H
31#include "lg_xaa.h"
32
33/* Laguna raster operations, source is OP1 and destination is OP0. */
34/* The order in this array is important! */
35static int lgRop[16] = {
36				/* Lg Op     X name          */
37
38	0x00,		/*     0     GXclear         */
39	0x88,		/*   S.D     GXand           */
40	0x44,		/*  S.~D     GXandReverse    */
41	0xCC,		/*     S     GXcopy          */
42	0x22,		/*  ~S.D     GXandInverted   */
43	0xAA,		/*     D     GXnoop          */
44	0x66,		/*  S~=D     GXxor           */
45	0xEE,		/*   S+D     GXor            */
46	0x77,		/* ~S.~D     GXnor           */
47	0x99,		/*   S=D     GXequiv         */
48	0x55,		/*    ~D     GXinvert        */
49	0xDD,		/*  S+~D     GXorReverse     */
50	0x33,		/*    ~S     GXcopyInverted  */
51	0xBB,		/*  ~S+D     GXorInverted    */
52	0x11,		/* ~S+~D     GXnand          */
53	0xFF		/*     1     GXset           */
54};
55
56#if 0
57/* Laguna raster operations, source is OP2 and destination is OP0. */
58static int lgPatRop[16] = {
59				/* Lg Op     X name          */
60
61	0x00,		/*     0     GXclear         */
62	0xA0,		/*   S.D     GXand           */
63	0x50,		/*  S.~D     GXandReverse    */
64	0xF0,		/*     S     GXcopy          */
65	0x0A,		/*  ~S.D     GXandInverted   */
66	0xAA,		/*     D     GXnoop          */
67	0x5A,		/*  S~=D     GXxor           */
68	0xFA,		/*   S+D     GXor            */
69	0x05,		/* ~S.~D     GXnor           */
70	0xA5,		/*   S=D     GXequiv         */
71	0x55,		/*    ~D     GXinvert        */
72	0xF5,		/*  S+~D     GXorReverse     */
73	0x0F,		/*    ~S     GXcopyInverted  */
74	0xAF,		/*  ~S+D     GXorInverted    */
75	0x5F,		/* ~S+~D     GXnand          */
76	0xFF		/*     1     GXset           */
77};
78#endif
79
80
81static void LgSetBitmask(CirPtr pCir, const CARD32 m);
82static void LgWaitQAvail(CirPtr pCir, int n);
83static CARD32 LgExpandColor(CARD32 color, int bpp);
84static void LgSync(ScrnInfoPtr pScrn);
85static void LgSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop,
86								unsigned int planemask);
87
88static void LgSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y,
89										int w, int h);
90static void LgSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir,
91											int rop, unsigned int planemask,
92											int transparency_color);
93static void LgSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1,
94											int x2, int y2, int w, int h);
95
96
97/**************************************************** LgXAAInit *****/
98
99Bool
100LgXAAInit(ScreenPtr pScreen)
101{
102    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
103    CirPtr pCir = CIRPTR(pScrn);
104    XAAInfoRecPtr XAAPtr;
105
106	XAAPtr = XAACreateInfoRec();
107	if (!XAAPtr)
108		return FALSE;
109
110	/*
111	 * Solid color fills.
112	 */
113	XAAPtr->SetupForSolidFill = LgSetupForSolidFill;
114	XAAPtr->SubsequentSolidFillRect = LgSubsequentSolidFillRect;
115	XAAPtr->SubsequentSolidFillTrap = NULL;
116	XAAPtr->SolidFillFlags = 0;
117
118	/*
119	 * Screen-to-screen copies.
120	 */
121	XAAPtr->SetupForScreenToScreenCopy = LgSetupForScreenToScreenCopy;
122	XAAPtr->SubsequentScreenToScreenCopy = LgSubsequentScreenToScreenCopy;
123	/* Maybe ONLY_LEFT_TO_RIGHT_BITBLT or ONLY_TWO_BITBLT_DIRECTIONS? */
124	XAAPtr->ScreenToScreenCopyFlags = ONLY_LEFT_TO_RIGHT_BITBLT;
125
126	/*
127	 * Miscellany.
128	 */
129	XAAPtr->Sync = LgSync;
130
131	pCir->AccelInfoRec = XAAPtr;
132
133	if (!XAAInit(pScreen, XAAPtr))
134		return FALSE;
135
136	return TRUE;
137}
138
139/******************************************** Lg XAA helper functions ***/
140
141/*
142 * The bitmask is usually all 1's, so it's silly to spend a DWORD write
143 * to program the register with the same value each time.  Bitmask is
144 * about the only register whose value is worth shadowing, so we special-
145 * case it.
146 */
147static void
148LgSetBitmask(CirPtr pCir, const CARD32 m)
149{
150	const LgPtr pLg = LGPTR(pCir);
151
152	if (m != pLg->oldBitmask) {
153		LgSETBITMASK(m);
154		pLg->oldBitmask = m;
155	}
156}
157
158/*
159 * Return from the function only when there's room somewhere for the
160 * upcoming register writes.  That means that either PCI retry is enabled
161 * (i.e., we let the PCI bus buffer the register writes), or we wait for
162 * room in the Laguna's command queue explicitly.
163 */
164static void
165LgWaitQAvail(CirPtr pCir, int n)
166{
167	if (!0/*lgUsePCIRetry*/) {
168		CARD8 qfree;
169
170		/* Wait until n entries are open in the command queue */
171		do
172			qfree = *(volatile CARD8 *)(pCir->IOBase + QFREE);
173		while (qfree < n);
174	}
175}
176
177
178/* We might want to make this a macro at some point. */
179static CARD32
180LgExpandColor(CARD32 color, int bpp)
181{
182	if (8 == bpp)
183		color = ((color&0xFF) << 8) | (color&0xFF);
184
185	if (8 == bpp || 16 == bpp)
186		color = ((color&0xFFFF) << 16) | (color&0xFFFF);
187
188	return color;
189}
190
191
192/*************************************************** Lg XAA functions ***/
193
194
195static void
196LgSync(ScrnInfoPtr pScrn)
197{
198	const CirPtr pCir = CIRPTR(pScrn);
199#if 0
200	LgPtr pLg = LGPTR(pScrn);
201#endif
202
203	while (!LgREADY())
204		;
205}
206
207static void
208LgSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop,
209			unsigned int planemask)
210{
211
212	const CirPtr pCir = CIRPTR(pScrn);
213
214	color = LgExpandColor(color, pScrn->bitsPerPixel);
215
216	LgWaitQAvail(pCir, 4);
217
218	LgSETBACKGROUND(color);
219	LgSETROP(lgRop[rop]);
220	LgSETMODE(SCR2SCR | COLORFILL);
221	LgSetBitmask(pCir, planemask);
222}
223
224static void
225LgSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h)
226{
227	const CirPtr pCir = CIRPTR(pScrn);
228
229	/* Wait for room in the command queue. */
230	LgWaitQAvail(pCir, 2);
231
232	LgSETDSTXY(x, y);
233	LgSETEXTENTS(w, h);
234}
235
236static void
237LgSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir,
238				int rop, unsigned int planemask, int transparency_color)
239{
240	int bltmode = 0;
241	const CirPtr pCir = CIRPTR(pScrn);
242	const LgPtr pLg = LGPTR(pCir);
243
244	pLg->blitTransparent = (transparency_color != -1);
245	pLg->blitYDir = ydir;
246
247	LgWaitQAvail(pCir, 4);
248
249	/* We set the rop up here because the LgSETROP macro conveniently
250	   (really -- it is convenient!) clears the transparency bits
251	   in DRAWDEF.  We'll set those bits appropriately later. */
252	LgSETROP(lgRop[rop]);
253
254	if (ydir < 0)
255		bltmode |= BLITUP;
256	if (pLg->blitTransparent) {
257		/* Gotta extend the transparency_color to the full 32-bit
258		   size of the register. */
259		transparency_color = LgExpandColor(transparency_color,
260										   pScrn->bitsPerPixel);
261
262		bltmode |= COLORTRANS;
263		LgSETBACKGROUND(transparency_color);
264		LgSETTRANSPARENCY(TRANSEQ);
265	} else {
266		LgSETTRANSPARENCY(TRANSNONE);
267	}
268
269	LgSETMODE(SCR2SCR | COLORSRC | bltmode);
270	LgSetBitmask(pCir, planemask);
271}
272
273static void
274LgSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1,
275								int x2, int y2, int w, int h)
276{
277	const CirPtr pCir = CIRPTR(pScrn);
278	const LgPtr pLg = LGPTR(pCir);
279
280	/*
281	 * We have set the flag indicating that xdir must be one,
282	 * so we can assume that here.
283	 */
284	if (pLg->blitYDir == -1) {
285		y1 += h - 1;
286		y2 += h - 1;
287	}
288
289	if (pLg->blitTransparent) {
290		/* We're doing a transparent blit.  We'll need to point
291		   OP2 to the color compare mask. */
292		LgWaitQAvail(pCir, 4);
293		LgSETTRANSMASK(x1, y1);
294	} else {
295		LgWaitQAvail(pCir, 3);
296	}
297	LgSETSRCXY(x1, y1);
298	LgSETDSTXY(x2, y2);
299	LgSETEXTENTS(w, h);
300}
301#endif
302