igs_accel.c revision 9a5ed1c5
1/*
2 * IGS CyberPro - hardware acceleration.
3 *
4 * Copyright (C) 2009 Michael Lorenz
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24/* $NetBSD: igs_accel.c,v 1.2 2009/11/21 22:22:27 macallan Exp $ */
25
26#include <sys/types.h>
27
28#include "igs.h"
29
30/*#define DEBUG*/
31
32#ifdef DEBUG
33#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
34#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
35#else
36#define ENTER
37#define LEAVE
38#endif
39
40static inline void IgsWrite1(IgsPtr fPtr, int offset, uint8_t val)
41{
42	*(fPtr->reg + offset) = val;
43}
44
45
46static inline void IgsWrite2(IgsPtr fPtr, int offset, uint16_t val)
47{
48	*(uint16_t *)(fPtr->reg + offset) = val;
49}
50
51static inline void IgsWrite4(IgsPtr fPtr, int offset, uint32_t val)
52{
53	*(uint32_t *)(fPtr->reg + offset) = val;
54}
55
56static inline uint8_t IgsRead1(IgsPtr fPtr, int offset)
57{
58	return *(fPtr->reg + offset);
59}
60
61static inline uint16_t IgsRead2(IgsPtr fPtr, int offset)
62{
63	return *(uint16_t *)(fPtr->reg + offset);
64}
65
66static void
67IgsWaitMarker(ScreenPtr pScreen, int Marker)
68{
69	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
70	IgsPtr fPtr = IGSPTR(pScrn);
71	int bail = 0x0fffffff;
72
73	ENTER;
74	IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, (fPtr->info.depth >> 3) - 1);
75	while ((IgsRead1(fPtr,
76	    IGS_COP_CTL_REG) & (IGS_COP_CTL_BUSY | IGS_COP_CTL_HFEMPTZ) != 0)
77	    && (bail > 0)) {
78		bail--;
79		usleep(1);
80	}
81
82	/* reset the coprocessor if we run into a timeout */
83	if (bail == 0) {
84		xf86Msg(X_ERROR, "%s: timeout\n", __func__);
85		IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
86	}
87	LEAVE;
88}
89
90static int
91IgsMarkSync(ScreenPtr pScreenInfo)
92{
93	ENTER;
94	return 0;
95}
96
97static void
98IgsWaitReady(IgsPtr fPtr)
99{
100	int bail = 0x0fffffff;
101
102	ENTER;
103	IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, (fPtr->info.depth >> 3) - 1);
104	while (((IgsRead1(fPtr,
105	    IGS_COP_CTL_REG) & (IGS_COP_CTL_BUSY | IGS_COP_CTL_HFEMPTZ)) != 0)
106	    && (bail > 0)) {
107		bail--;
108		usleep(1);
109	}
110
111	/* reset the coprocessor if we run into a timeout */
112	if (bail == 0) {
113		xf86Msg(X_ERROR, "%s: timeout\n", __func__);
114		IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
115	}
116	LEAVE;
117}
118
119static Bool
120IgsPrepareCopy
121(
122    PixmapPtr pSrcPixmap,
123    PixmapPtr pDstPixmap,
124    int       xdir,
125    int       ydir,
126    int       alu,
127    Pixel     planemask
128)
129{
130	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
131	IgsPtr fPtr = IGSPTR(pScrn);
132
133	ENTER;
134	fPtr->cmd = IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC |
135	    IGS_COP_PPM_FIXED_FG;
136	if (xdir < 0)
137		fPtr->cmd |= IGS_COP_OCTANT_X_NEG;
138	if (ydir < 0)
139		fPtr->cmd |= IGS_COP_OCTANT_Y_NEG;
140
141	IgsWaitReady(fPtr);
142	IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
143	fPtr->srcoff = exaGetPixmapOffset(pSrcPixmap) >> fPtr->shift;
144	fPtr->srcpitch = exaGetPixmapPitch(pSrcPixmap) >> fPtr->shift;
145
146	IgsWrite2(fPtr, IGS_COP_SRC_MAP_WIDTH_REG, fPtr->srcpitch - 1);
147	IgsWrite2(fPtr, IGS_COP_DST_MAP_WIDTH_REG,
148	    (exaGetPixmapPitch(pDstPixmap) >> fPtr->shift) - 1);
149	IgsWrite1(fPtr, IGS_COP_FG_MIX_REG, alu);
150	IgsWrite4(fPtr, IGS_PLANE_MASK_REG, planemask);
151	LEAVE;
152	return TRUE;
153}
154
155static void
156IgsCopy
157(
158    PixmapPtr pDstPixmap,
159    int       srcX,
160    int       srcY,
161    int       dstX,
162    int       dstY,
163    int       w,
164    int       h
165)
166{
167	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
168	IgsPtr fPtr = IGSPTR(pScrn);
169	int dstpitch, dstoff;
170
171	if (fPtr->cmd & IGS_COP_OCTANT_X_NEG) {
172		srcX += (w - 1);
173		dstX += (w - 1);
174	}
175
176	if (fPtr->cmd & IGS_COP_OCTANT_Y_NEG) {
177		srcY += (h - 1);
178		dstY += (h - 1);
179	}
180	IgsWaitReady(fPtr);
181	IgsWrite4(fPtr, IGS_COP_SRC_START_REG, fPtr->srcoff + srcX +
182	    fPtr->srcpitch * srcY);
183	dstpitch = exaGetPixmapPitch(pDstPixmap) >> fPtr->shift;
184	dstoff = exaGetPixmapOffset(pDstPixmap) >> fPtr->shift;
185	IgsWrite4(fPtr, IGS_COP_DST_START_REG, dstoff + dstX +
186	    dstpitch * dstY);
187	IgsWrite2(fPtr, IGS_COP_WIDTH_REG, w - 1);
188	IgsWrite2(fPtr, IGS_COP_HEIGHT_REG, h - 1);
189	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG, fPtr->cmd & 0xffff);
190	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG + 2, (fPtr->cmd >> 16) & 0xffff);
191	LEAVE;
192}
193
194static void
195IgsDoneCopy(PixmapPtr pDstPixmap)
196{
197    ENTER;
198    LEAVE;
199}
200
201static Bool
202IgsPrepareSolid(
203    PixmapPtr pPixmap,
204    int alu,
205    Pixel planemask,
206    Pixel fg)
207{
208	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
209	IgsPtr fPtr = IGSPTR(pScrn);
210
211	ENTER;
212	fPtr->cmd = IGS_COP_OP_PXBLT | IGS_COP_PPM_FIXED_FG;
213
214	IgsWaitReady(fPtr);
215
216	IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
217
218	IgsWrite2(fPtr, IGS_COP_DST_MAP_WIDTH_REG,
219	    (exaGetPixmapPitch(pPixmap) >> fPtr->shift) - 1);
220	IgsWrite1(fPtr, IGS_COP_FG_MIX_REG, alu);
221	IgsWrite4(fPtr, IGS_PLANE_MASK_REG, planemask);
222	IgsWrite4(fPtr, IGS_COP_FG_REG, fg);
223	LEAVE;
224	return TRUE;
225}
226
227static void
228IgsSolid(
229    PixmapPtr pPixmap,
230    int x1,
231    int y1,
232    int x2,
233    int y2)
234{
235	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
236	IgsPtr fPtr = IGSPTR(pScrn);
237	int w = x2 - x1, h = y2 - y1, dstoff, dstpitch;
238
239	ENTER;
240	IgsWaitReady(fPtr);
241	dstpitch = exaGetPixmapPitch(pPixmap) >> fPtr->shift;
242	dstoff = exaGetPixmapOffset(pPixmap) >> fPtr->shift;
243	IgsWrite4(fPtr, IGS_COP_DST_START_REG, dstoff + x1 +
244	    dstpitch * y1);
245	IgsWrite2(fPtr, IGS_COP_WIDTH_REG, w - 1);
246	IgsWrite2(fPtr, IGS_COP_HEIGHT_REG, h - 1);
247	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG, fPtr->cmd & 0xffff);
248	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG + 2, (fPtr->cmd >> 16) & 0xffff);
249}
250
251/*
252 * Memcpy-based UTS.
253 */
254static Bool
255IgsUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
256    char *src, int src_pitch)
257{
258	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
259	IgsPtr fPtr = IGSPTR(pScrn);
260	char  *dst        = fPtr->fbmem + exaGetPixmapOffset(pDst);
261	int    dst_pitch  = exaGetPixmapPitch(pDst);
262
263	int bpp    = pDst->drawable.bitsPerPixel;
264	int cpp    = (bpp + 7) / 8;
265	int wBytes = w * cpp;
266
267	ENTER;
268	dst += (x * cpp) + (y * dst_pitch);
269
270	while (h--) {
271		memcpy(dst, src, wBytes);
272		src += src_pitch;
273		dst += dst_pitch;
274	}
275	LEAVE;
276	return TRUE;
277}
278
279/*
280 * Memcpy-based DFS.
281 */
282static Bool
283IgsDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
284    char *dst, int dst_pitch)
285{
286	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
287	IgsPtr fPtr = IGSPTR(pScrn);
288	char  *src        = fPtr->fbmem + exaGetPixmapOffset(pSrc);
289	int    src_pitch  = exaGetPixmapPitch(pSrc);
290
291	int bpp    = pSrc->drawable.bitsPerPixel;
292	int cpp    = (bpp + 7) / 8;
293	int wBytes = w * cpp;
294
295	ENTER;
296	src += (x * cpp) + (y * src_pitch);
297
298	while (h--) {
299		memcpy(dst, src, wBytes);
300		src += src_pitch;
301		dst += dst_pitch;
302	}
303	LEAVE;
304	return TRUE;
305}
306
307Bool
308IgsInitAccel(ScreenPtr pScreen)
309{
310	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
311	IgsPtr fPtr = IGSPTR(pScrn);
312	ExaDriverPtr pExa;
313
314	pExa = exaDriverAlloc();
315	if (!pExa)
316		return FALSE;
317
318	fPtr->pExa = pExa;
319
320	pExa->exa_major = EXA_VERSION_MAJOR;
321	pExa->exa_minor = EXA_VERSION_MINOR;
322
323	pExa->memoryBase = fPtr->fbmem;
324	pExa->memorySize = fPtr->fbmem_len;
325	pExa->offScreenBase = fPtr->linebytes * fPtr->info.height;
326	pExa->pixmapOffsetAlign = 4;
327	pExa->pixmapPitchAlign = 4;
328
329	pExa->flags = EXA_OFFSCREEN_PIXMAPS;
330
331	pExa->maxX = 2048;
332	pExa->maxY = 2048;
333
334	pExa->MarkSync = IgsMarkSync;
335	pExa->WaitMarker = IgsWaitMarker;
336	pExa->PrepareSolid = IgsPrepareSolid;
337	pExa->Solid = IgsSolid;
338	pExa->DoneSolid = IgsDoneCopy;
339	pExa->PrepareCopy = IgsPrepareCopy;
340	pExa->Copy = IgsCopy;
341	pExa->DoneCopy = IgsDoneCopy;
342
343	switch(fPtr->info.depth) {
344		case 8:
345			fPtr->shift = 0;
346			break;
347		case 16:
348			fPtr->shift = 1;
349			break;
350		case 32:
351			fPtr->shift = 2;
352			break;
353	}
354	/* EXA hits more optimized paths when it does not have to fallback
355	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
356	 */
357	pExa->UploadToScreen = IgsUploadToScreen;
358	pExa->DownloadFromScreen = IgsDownloadFromScreen;
359
360	return exaDriverInit(pScreen, pExa);
361}
362