ngle_accel.c revision ce159321
1727c6de2Smacallan/*
2727c6de2Smacallan * NGLE - hardware acceleration.
3727c6de2Smacallan *
4727c6de2Smacallan * Copyright (C) 2024 Michael Lorenz
5727c6de2Smacallan *
6727c6de2Smacallan * Permission is hereby granted, free of charge, to any person obtaining a copy
7727c6de2Smacallan * of this software and associated documentation files (the "Software"), to deal
8727c6de2Smacallan * in the Software without restriction, including without limitation the rights
9727c6de2Smacallan * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10727c6de2Smacallan * copies of the Software, and to permit persons to whom the Software is
11727c6de2Smacallan * furnished to do so, subject to the following conditions:
12727c6de2Smacallan *
13727c6de2Smacallan * The above copyright notice and this permission notice shall be included in
14727c6de2Smacallan * all copies or substantial portions of the Software.
15727c6de2Smacallan *
16727c6de2Smacallan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17727c6de2Smacallan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18727c6de2Smacallan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19727c6de2Smacallan * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20727c6de2Smacallan * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21727c6de2Smacallan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22727c6de2Smacallan */
23727c6de2Smacallan
24ce159321Smacallan/* $NetBSD: ngle_accel.c,v 1.3 2024/10/22 08:46:07 macallan Exp $ */
25727c6de2Smacallan
26727c6de2Smacallan#include <sys/types.h>
27727c6de2Smacallan#include <dev/ic/stireg.h>
28727c6de2Smacallan
29727c6de2Smacallan
30727c6de2Smacallan#include "ngle.h"
31727c6de2Smacallan
32727c6de2Smacallan//#define DEBUG
33727c6de2Smacallan
34727c6de2Smacallan#ifdef DEBUG
35727c6de2Smacallan#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
36727c6de2Smacallan#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
37727c6de2Smacallan#define DBGMSG xf86Msg
38727c6de2Smacallan#else
39727c6de2Smacallan#define ENTER
40727c6de2Smacallan#define DBGMSG if (0) xf86Msg
41727c6de2Smacallan#define LEAVE
42727c6de2Smacallan#endif
43727c6de2Smacallan
44727c6de2Smacallanstatic inline void
45727c6de2SmacallanNGLEWrite4(NGLEPtr fPtr, int offset, uint32_t val)
46727c6de2Smacallan{
47727c6de2Smacallan	volatile uint32_t *ptr = (uint32_t *)((uint8_t *)fPtr->regs + offset);
48727c6de2Smacallan	*ptr = val;
49727c6de2Smacallan}
50727c6de2Smacallan
51727c6de2Smacallanstatic inline void
52727c6de2SmacallanNGLEWrite1(NGLEPtr fPtr, int offset, uint8_t val)
53727c6de2Smacallan{
54727c6de2Smacallan	volatile uint8_t *ptr = (uint8_t *)fPtr->regs + offset;
55727c6de2Smacallan	*ptr = val;
56727c6de2Smacallan}
57727c6de2Smacallan
58727c6de2Smacallanstatic inline uint32_t
59727c6de2SmacallanNGLERead4(NGLEPtr fPtr, int offset)
60727c6de2Smacallan{
61727c6de2Smacallan	volatile uint32_t *ptr = (uint32_t *)((uint8_t *)fPtr->regs + offset);
62727c6de2Smacallan	return *ptr;
63727c6de2Smacallan}
64727c6de2Smacallan
65727c6de2Smacallanstatic inline uint8_t
66727c6de2SmacallanNGLERead1(NGLEPtr fPtr, int offset)
67727c6de2Smacallan{
68727c6de2Smacallan	volatile uint8_t *ptr = (uint8_t *)fPtr->regs + offset;
69727c6de2Smacallan	return *ptr;
70727c6de2Smacallan}
71727c6de2Smacallan
72727c6de2Smacallanstatic void
73727c6de2SmacallanNGLEWaitMarker(ScreenPtr pScreen, int Marker)
74727c6de2Smacallan{
75727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
76727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
77727c6de2Smacallan	uint8_t stat;
78727c6de2Smacallan
79727c6de2Smacallan	ENTER;
80727c6de2Smacallan	do {
81727c6de2Smacallan		stat = NGLERead1(fPtr, NGLE_REG_15b0);
82727c6de2Smacallan		if (stat == 0)
83727c6de2Smacallan			stat = NGLERead1(fPtr, NGLE_REG_15b0);
84727c6de2Smacallan	} while (stat != 0);
85727c6de2Smacallan	LEAVE;
86727c6de2Smacallan}
87727c6de2Smacallan
88727c6de2Smacallanstatic void
89727c6de2SmacallanNGLEWaitFifo(NGLEPtr fPtr, int slots)
90727c6de2Smacallan{
91727c6de2Smacallan	uint32_t reg;
92727c6de2Smacallan
93727c6de2Smacallan	ENTER;
94727c6de2Smacallan	do {
95727c6de2Smacallan		reg = NGLERead4(fPtr, NGLE_REG_34);
96727c6de2Smacallan	} while (reg < slots);
97727c6de2Smacallan	LEAVE;
98727c6de2Smacallan}
99727c6de2Smacallan
100727c6de2Smacallanstatic Bool
101ce159321SmacallanNGLEPrepareCopy_EG
102727c6de2Smacallan(
103727c6de2Smacallan    PixmapPtr pSrcPixmap,
104727c6de2Smacallan    PixmapPtr pDstPixmap,
105727c6de2Smacallan    int       xdir,
106727c6de2Smacallan    int       ydir,
107727c6de2Smacallan    int       alu,
108727c6de2Smacallan    Pixel     planemask
109727c6de2Smacallan)
110727c6de2Smacallan{
111727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
112727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
113727c6de2Smacallan	int srcpitch = exaGetPixmapPitch(pSrcPixmap);
114727c6de2Smacallan	int srcoff = exaGetPixmapOffset(pSrcPixmap);
115727c6de2Smacallan
116727c6de2Smacallan	ENTER;
117727c6de2Smacallan
118727c6de2Smacallan	DBGMSG(X_ERROR, "%s %d %d\n", __func__, srcoff, srcpitch);
119727c6de2Smacallan	fPtr->offset = srcoff / srcpitch;
120727c6de2Smacallan	NGLEWaitMarker(pDstPixmap->drawable.pScreen, 0);
121727c6de2Smacallan	/* XXX HCRX needs ifferent values here */
122727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_10,
123727c6de2Smacallan	    BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0));
124727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_14, ((alu << 8) & 0xf00) | 0x23000000);
125727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
126727c6de2Smacallan
127727c6de2Smacallan	fPtr->hwmode = HW_BLIT;
128727c6de2Smacallan
129727c6de2Smacallan	LEAVE;
130727c6de2Smacallan	return TRUE;
131727c6de2Smacallan}
132727c6de2Smacallan
133ce159321Smacallanstatic Bool
134ce159321SmacallanNGLEPrepareCopy_HCRX
135ce159321Smacallan(
136ce159321Smacallan    PixmapPtr pSrcPixmap,
137ce159321Smacallan    PixmapPtr pDstPixmap,
138ce159321Smacallan    int       xdir,
139ce159321Smacallan    int       ydir,
140ce159321Smacallan    int       alu,
141ce159321Smacallan    Pixel     planemask
142ce159321Smacallan)
143ce159321Smacallan{
144ce159321Smacallan	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
145ce159321Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
146ce159321Smacallan	int srcpitch = exaGetPixmapPitch(pSrcPixmap);
147ce159321Smacallan	int srcoff = exaGetPixmapOffset(pSrcPixmap);
148ce159321Smacallan
149ce159321Smacallan	ENTER;
150ce159321Smacallan
151ce159321Smacallan	DBGMSG(X_ERROR, "%s %d %d\n", __func__, srcoff, srcpitch);
152ce159321Smacallan	fPtr->offset = srcoff / srcpitch;
153ce159321Smacallan	NGLEWaitMarker(pDstPixmap->drawable.pScreen, 0);
154ce159321Smacallan	/* XXX HCRX needs ifferent values here */
155ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_10,
156ce159321Smacallan	    BA(FractDcd, Otc24, Ots08, AddrLong, 0, BINapp0F8, 0));
157ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_14, IBOvals(RopSrc, 0, BitmapExtent32, 0, DataDynamic, MaskOtc,
158ce159321Smacallan			0, 0));
159ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
160ce159321Smacallan
161ce159321Smacallan	fPtr->hwmode = HW_BLIT;
162ce159321Smacallan
163ce159321Smacallan	LEAVE;
164ce159321Smacallan	return TRUE;
165ce159321Smacallan}
166ce159321Smacallan
167727c6de2Smacallanstatic void
168727c6de2SmacallanNGLECopy
169727c6de2Smacallan(
170727c6de2Smacallan    PixmapPtr pDstPixmap,
171727c6de2Smacallan    int       xs,
172727c6de2Smacallan    int       ys,
173727c6de2Smacallan    int       xd,
174727c6de2Smacallan    int       yd,
175727c6de2Smacallan    int       wi,
176727c6de2Smacallan    int       he
177727c6de2Smacallan)
178727c6de2Smacallan{
179727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
180727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
181727c6de2Smacallan	int dstpitch = exaGetPixmapPitch(pDstPixmap);
182727c6de2Smacallan	int dstoff = exaGetPixmapOffset(pDstPixmap);
183727c6de2Smacallan
184727c6de2Smacallan	ENTER;
185727c6de2Smacallan	NGLEWaitFifo(fPtr, 3);
186727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_24, (xs << 16) | (ys + fPtr->offset));
187727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_7, (wi << 16) | he);
188727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_25, (xd << 16) | (yd + (dstoff / dstpitch)));
189727c6de2Smacallan
190727c6de2Smacallan	exaMarkSync(pDstPixmap->drawable.pScreen);
191727c6de2Smacallan	LEAVE;
192727c6de2Smacallan}
193727c6de2Smacallan
194727c6de2Smacallanstatic void
195727c6de2SmacallanNGLEDoneCopy(PixmapPtr pDstPixmap)
196727c6de2Smacallan{
197727c6de2Smacallan    ENTER;
198727c6de2Smacallan    LEAVE;
199727c6de2Smacallan}
200727c6de2Smacallan
201727c6de2Smacallanstatic Bool
202ce159321SmacallanNGLEPrepareSolid_EG(
203727c6de2Smacallan    PixmapPtr pPixmap,
204727c6de2Smacallan    int alu,
205727c6de2Smacallan    Pixel planemask,
206727c6de2Smacallan    Pixel fg)
207727c6de2Smacallan{
208727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
209727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
210727c6de2Smacallan
211727c6de2Smacallan	ENTER;
212727c6de2Smacallan	NGLEWaitFifo(fPtr, 4);
213727c6de2Smacallan	/* plane mask */
214727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
215727c6de2Smacallan	/* bitmap op */
216727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_14,
217727c6de2Smacallan	    IBOvals(alu, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 1, 0));
218727c6de2Smacallan
219bc460d0dSmacallan	/* XXX HCRX needs different values here */
220727c6de2Smacallan	/* dst bitmap access */
221727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_11,
222727c6de2Smacallan	    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0));
223727c6de2Smacallan    	NGLEWrite4(fPtr, NGLE_REG_35, fg);
224727c6de2Smacallan	fPtr->hwmode = HW_FILL;
225727c6de2Smacallan
226727c6de2Smacallan	LEAVE;
227727c6de2Smacallan	return TRUE;
228727c6de2Smacallan}
229727c6de2Smacallan
230ce159321Smacallanstatic Bool
231ce159321SmacallanNGLEPrepareSolid_HCRX(
232ce159321Smacallan    PixmapPtr pPixmap,
233ce159321Smacallan    int alu,
234ce159321Smacallan    Pixel planemask,
235ce159321Smacallan    Pixel fg)
236ce159321Smacallan{
237ce159321Smacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
238ce159321Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
239ce159321Smacallan
240ce159321Smacallan	ENTER;
241ce159321Smacallan	NGLEWaitFifo(fPtr, 4);
242ce159321Smacallan	/* plane mask */
243ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
244ce159321Smacallan	/* bitmap op */
245ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_14,
246ce159321Smacallan	    IBOvals(alu, 0, BitmapExtent32, 0, DataDynamic, MaskOtc, 1, 0));
247ce159321Smacallan
248ce159321Smacallan	/* XXX HCRX needs different values here */
249ce159321Smacallan	/* dst bitmap access */
250ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_11,
251ce159321Smacallan	    BA(FractDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0F8, 0));
252ce159321Smacallan    	NGLEWrite4(fPtr, NGLE_REG_35, fg);
253ce159321Smacallan	fPtr->hwmode = HW_FILL;
254ce159321Smacallan
255ce159321Smacallan	LEAVE;
256ce159321Smacallan	return TRUE;
257ce159321Smacallan}
258ce159321Smacallan
259727c6de2Smacallanstatic void
260727c6de2SmacallanNGLESolid(
261727c6de2Smacallan    PixmapPtr pPixmap,
262727c6de2Smacallan    int x1,
263727c6de2Smacallan    int y1,
264727c6de2Smacallan    int x2,
265727c6de2Smacallan    int y2)
266727c6de2Smacallan{
267727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
268727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
269727c6de2Smacallan	int w = x2 - x1, h = y2 - y1;
270727c6de2Smacallan	int pitch = exaGetPixmapPitch(pPixmap);
271727c6de2Smacallan	int offset = exaGetPixmapOffset(pPixmap);
272727c6de2Smacallan	uint32_t mask;
273727c6de2Smacallan	int wi, rest;
274727c6de2Smacallan
275727c6de2Smacallan	ENTER;
276727c6de2Smacallan
277727c6de2Smacallan	y1 += offset >> 11;
278727c6de2Smacallan
279bc460d0dSmacallan	/*
280bc460d0dSmacallan	 * XXX
281bc460d0dSmacallan	 * Turns out this thing always fills rectangles to the next 32 pixel
282bc460d0dSmacallan	 * boundary on te right. To get around this we split the rectangle
283bc460d0dSmacallan	 * into a multiples-of-32 part and the rest, so we can mask off the
284bc460d0dSmacallan	 * excess pixels.
285bc460d0dSmacallan	 */
286727c6de2Smacallan	rest = w & 0x1f;
287727c6de2Smacallan	wi = w & 0xffffe0;
288727c6de2Smacallan	if (wi > 0) {
289727c6de2Smacallan		NGLEWaitFifo(fPtr, 3);
290727c6de2Smacallan		/* transfer data */
291727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_8, 0xffffffff);
292727c6de2Smacallan		/* dst XY */
293727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_6, (x1 << 16) | y1);
294727c6de2Smacallan		/* len XY start */
295727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_9, (wi << 16) | h);
296727c6de2Smacallan	}
297727c6de2Smacallan	if (rest > 0) {
298727c6de2Smacallan		mask = 0xffffffff << (32 - w);
299727c6de2Smacallan		/* transfer data */
300bc460d0dSmacallan		NGLEWaitFifo(fPtr, 3);
301727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_8, mask);
302727c6de2Smacallan		/* dst XY */
303727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_6, ((x1 + wi) << 16) | y1);
304727c6de2Smacallan		/* len XY start */
305727c6de2Smacallan		NGLEWrite4(fPtr, NGLE_REG_9, (rest << 16) | h);
306727c6de2Smacallan	}
307727c6de2Smacallan	exaMarkSync(pPixmap->drawable.pScreen);
308727c6de2Smacallan	LEAVE;
309727c6de2Smacallan}
310727c6de2Smacallan
311727c6de2SmacallanBool
312ce159321SmacallanNGLEPrepareAccess_EG(PixmapPtr pPixmap, int index)
313727c6de2Smacallan{
314727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
315727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
316727c6de2Smacallan
317727c6de2Smacallan	if (fPtr->hwmode == HW_FB) return TRUE;
318727c6de2Smacallan
319727c6de2Smacallan	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
320ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_10,
321ce159321Smacallan	    BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, BINapp0I, 0));
322727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_14, 0x83000300);
323727c6de2Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, 0xff);
324727c6de2Smacallan	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
325727c6de2Smacallan	NGLEWrite1(fPtr, NGLE_REG_16b1, 1);
326727c6de2Smacallan	fPtr->hwmode = HW_FB;
327727c6de2Smacallan	return TRUE;
328727c6de2Smacallan}
329727c6de2Smacallan
330ce159321SmacallanBool
331ce159321SmacallanNGLEPrepareAccess_HCRX(PixmapPtr pPixmap, int index)
332ce159321Smacallan{
333ce159321Smacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
334ce159321Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
335ce159321Smacallan
336ce159321Smacallan	if (fPtr->hwmode == HW_FB) return TRUE;
337ce159321Smacallan
338ce159321Smacallan	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
339ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_10,
340ce159321Smacallan	    BA(FractDcd, Otc24, Ots08, AddrLong, 0, BINapp0F8, 0));
341ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_14, 0x83000300);
342ce159321Smacallan	NGLEWrite4(fPtr, NGLE_REG_13, 0xffffffff);
343ce159321Smacallan	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
344ce159321Smacallan	NGLEWrite1(fPtr, NGLE_REG_16b1, 1);
345ce159321Smacallan	fPtr->hwmode = HW_FB;
346ce159321Smacallan	return TRUE;
347ce159321Smacallan}
348727c6de2SmacallanBool
349727c6de2SmacallanNGLEInitAccel(ScreenPtr pScreen)
350727c6de2Smacallan{
351727c6de2Smacallan	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
352727c6de2Smacallan	NGLEPtr fPtr = NGLEPTR(pScrn);
353727c6de2Smacallan	ExaDriverPtr pExa;
354727c6de2Smacallan	int lines, bpp = pScrn->bitsPerPixel >> 3;
355727c6de2Smacallan
356727c6de2Smacallan	pExa = exaDriverAlloc();
357727c6de2Smacallan	if (!pExa)
358727c6de2Smacallan		return FALSE;
359727c6de2Smacallan
360727c6de2Smacallan	fPtr->pExa = pExa;
361727c6de2Smacallan
362727c6de2Smacallan	pExa->exa_major = EXA_VERSION_MAJOR;
363727c6de2Smacallan	pExa->exa_minor = EXA_VERSION_MINOR;
364727c6de2Smacallan
365727c6de2Smacallan	pExa->memoryBase = fPtr->fbmem;
366727c6de2Smacallan	lines = fPtr->fbmem_len / fPtr->fbi.fbi_stride;
367727c6de2Smacallan	DBGMSG(X_ERROR, "lines %d\n", lines);
368727c6de2Smacallan	pExa->memorySize = fPtr->fbmem_len;
369727c6de2Smacallan	pExa->offScreenBase = fPtr->fbi.fbi_stride * fPtr->fbi.fbi_height;
370727c6de2Smacallan	pExa->pixmapOffsetAlign = fPtr->fbi.fbi_stride;
371727c6de2Smacallan	pExa->pixmapPitchAlign = fPtr->fbi.fbi_stride;
372727c6de2Smacallan
373727c6de2Smacallan	pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_MIXED_PIXMAPS;
374727c6de2Smacallan
375727c6de2Smacallan	pExa->maxX = 2048;
376727c6de2Smacallan	pExa->maxY = 2048;
377727c6de2Smacallan
378727c6de2Smacallan	fPtr->hwmode = -1;
379727c6de2Smacallan
380727c6de2Smacallan	pExa->WaitMarker = NGLEWaitMarker;
381727c6de2Smacallan	pExa->Solid = NGLESolid;
382727c6de2Smacallan	pExa->DoneSolid = NGLEDoneCopy;
383727c6de2Smacallan	pExa->Copy = NGLECopy;
384727c6de2Smacallan	pExa->DoneCopy = NGLEDoneCopy;
385ce159321Smacallan	switch (fPtr->gid) {
386ce159321Smacallan		case STI_DD_EG:
387ce159321Smacallan			pExa->PrepareCopy = NGLEPrepareCopy_EG;
388ce159321Smacallan			pExa->PrepareSolid = NGLEPrepareSolid_EG;
389ce159321Smacallan			pExa->PrepareAccess = NGLEPrepareAccess_EG;
390ce159321Smacallan			break;
391ce159321Smacallan		case STI_DD_HCRX:
392ce159321Smacallan			pExa->PrepareCopy = NGLEPrepareCopy_HCRX;
393ce159321Smacallan			pExa->PrepareSolid = NGLEPrepareSolid_HCRX;
394ce159321Smacallan			pExa->PrepareAccess = NGLEPrepareAccess_HCRX;
395ce159321Smacallan			break;
396ce159321Smacallan		default:
397ce159321Smacallan			xf86Msg(X_ERROR,
398ce159321Smacallan			    "unsupported dvice GID %08x\n", fPtr->gid);
399ce159321Smacallan			return FALSE;
400ce159321Smacallan	}
401727c6de2Smacallan	NGLEWaitMarker(pScreen, 0);
402727c6de2Smacallan
403727c6de2Smacallan	return exaDriverInit(pScreen, pExa);
404727c6de2Smacallan}
405