igs_accel.c revision 2e72e74d
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.8 2011/12/14 23:58:54 macallan Exp $ */
25
26#include <sys/types.h>
27
28/* all driver need this */
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "compiler.h"
32
33#include "igs.h"
34
35/*#define DEBUG*/
36
37#ifdef DEBUG
38#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
39#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
40#else
41#define ENTER
42#define LEAVE
43#endif
44
45static inline void IgsWrite1(IgsPtr fPtr, int offset, uint8_t val)
46{
47	*(fPtr->reg + offset) = val;
48}
49
50
51static inline void IgsWrite2(IgsPtr fPtr, int offset, uint16_t val)
52{
53	*(volatile uint16_t *)(fPtr->reg + offset) = val;
54}
55
56static inline void IgsWrite4(IgsPtr fPtr, int offset, uint32_t val)
57{
58	*(volatile uint32_t *)(fPtr->reg + offset) = val;
59}
60
61static inline uint8_t IgsRead1(IgsPtr fPtr, int offset)
62{
63	return *(fPtr->reg + offset);
64}
65
66static inline uint16_t IgsRead2(IgsPtr fPtr, int offset)
67{
68	return *(volatile uint16_t *)(fPtr->reg + offset);
69}
70
71static void
72IgsWaitMarker(ScreenPtr pScreen, int Marker)
73{
74	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
75	IgsPtr fPtr = IGSPTR(pScrn);
76	int bail = 0x0fffffff;
77
78	ENTER;
79	IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, fPtr->mapfmt);
80	while ((IgsRead1(fPtr,
81	    IGS_COP_CTL_REG) & (IGS_COP_CTL_BUSY | IGS_COP_CTL_HFEMPTZ) != 0)
82	    && (bail > 0)) {
83		bail--;
84		IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, fPtr->mapfmt);
85	}
86
87	/* reset the coprocessor if we run into a timeout */
88	if (bail == 0) {
89		xf86Msg(X_ERROR, "%s: timeout\n", __func__);
90		IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
91	}
92	LEAVE;
93}
94
95static void
96IgsWaitReady(IgsPtr fPtr)
97{
98	int bail = 0x0fffffff;
99
100	ENTER;
101	IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, fPtr->mapfmt);
102	while (((IgsRead1(fPtr,
103	    IGS_COP_CTL_REG) & (IGS_COP_CTL_BUSY | IGS_COP_CTL_HFEMPTZ)) != 0)
104	    && (bail > 0)) {
105		bail--;
106		IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, fPtr->mapfmt);
107	}
108
109	/* reset the coprocessor if we run into a timeout */
110	if (bail == 0) {
111		xf86Msg(X_ERROR, "%s: timeout\n", __func__);
112		IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
113	}
114	LEAVE;
115}
116
117static Bool
118IgsPrepareCopy
119(
120    PixmapPtr pSrcPixmap,
121    PixmapPtr pDstPixmap,
122    int       xdir,
123    int       ydir,
124    int       alu,
125    Pixel     planemask
126)
127{
128	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
129	IgsPtr fPtr = IGSPTR(pScrn);
130
131	ENTER;
132	fPtr->cmd = IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC |
133	    IGS_COP_PPM_FIXED_FG;
134	if (xdir < 0)
135		fPtr->cmd |= IGS_COP_OCTANT_X_NEG;
136	if (ydir < 0)
137		fPtr->cmd |= IGS_COP_OCTANT_Y_NEG;
138
139	IgsWaitReady(fPtr);
140	IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
141	fPtr->srcoff = exaGetPixmapOffset(pSrcPixmap) >> fPtr->shift;
142	fPtr->srcpitch = exaGetPixmapPitch(pSrcPixmap) >> fPtr->shift;
143
144	IgsWrite2(fPtr, IGS_COP_SRC_MAP_WIDTH_REG, fPtr->srcpitch - 1);
145	IgsWrite2(fPtr, IGS_COP_DST_MAP_WIDTH_REG,
146	    (exaGetPixmapPitch(pDstPixmap) >> fPtr->shift) - 1);
147	IgsWrite1(fPtr, IGS_COP_FG_MIX_REG, alu);
148	IgsWrite4(fPtr, IGS_PLANE_MASK_REG, planemask);
149	LEAVE;
150	return TRUE;
151}
152
153static void
154IgsCopy
155(
156    PixmapPtr pDstPixmap,
157    int       srcX,
158    int       srcY,
159    int       dstX,
160    int       dstY,
161    int       w,
162    int       h
163)
164{
165	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
166	IgsPtr fPtr = IGSPTR(pScrn);
167	int dstpitch, dstoff;
168
169	if (fPtr->cmd & IGS_COP_OCTANT_X_NEG) {
170		srcX += (w - 1);
171		dstX += (w - 1);
172	}
173
174	if (fPtr->cmd & IGS_COP_OCTANT_Y_NEG) {
175		srcY += (h - 1);
176		dstY += (h - 1);
177	}
178	IgsWaitReady(fPtr);
179	IgsWrite4(fPtr, IGS_COP_SRC_START_REG, fPtr->srcoff + srcX +
180	    fPtr->srcpitch * srcY);
181	dstpitch = exaGetPixmapPitch(pDstPixmap) >> fPtr->shift;
182	dstoff = exaGetPixmapOffset(pDstPixmap) >> fPtr->shift;
183	IgsWrite4(fPtr, IGS_COP_DST_START_REG, dstoff + dstX +
184	    dstpitch * dstY);
185	IgsWrite2(fPtr, IGS_COP_WIDTH_REG, w - 1);
186	IgsWrite2(fPtr, IGS_COP_HEIGHT_REG, h - 1);
187	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG, fPtr->cmd & 0xffff);
188	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG + 2, (fPtr->cmd >> 16) & 0xffff);
189	exaMarkSync(pDstPixmap->drawable.pScreen);
190	LEAVE;
191}
192
193static void
194IgsDoneCopy(PixmapPtr pDstPixmap)
195{
196    ENTER;
197    LEAVE;
198}
199
200static Bool
201IgsPrepareSolid(
202    PixmapPtr pPixmap,
203    int alu,
204    Pixel planemask,
205    Pixel fg)
206{
207	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
208	IgsPtr fPtr = IGSPTR(pScrn);
209
210	ENTER;
211	fPtr->cmd = IGS_COP_OP_PXBLT | IGS_COP_PPM_FIXED_FG;
212
213	IgsWaitReady(fPtr);
214
215	IgsWrite1(fPtr, IGS_COP_CTL_REG, 0);
216
217	IgsWrite2(fPtr, IGS_COP_DST_MAP_WIDTH_REG,
218	    (exaGetPixmapPitch(pPixmap) >> fPtr->shift) - 1);
219	IgsWrite1(fPtr, IGS_COP_FG_MIX_REG, alu);
220	IgsWrite4(fPtr, IGS_PLANE_MASK_REG, planemask);
221	IgsWrite4(fPtr, IGS_COP_FG_REG, fg);
222	LEAVE;
223	return TRUE;
224}
225
226static void
227IgsSolid(
228    PixmapPtr pPixmap,
229    int x1,
230    int y1,
231    int x2,
232    int y2)
233{
234	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
235	IgsPtr fPtr = IGSPTR(pScrn);
236	int w = x2 - x1, h = y2 - y1, dstoff, dstpitch;
237
238	ENTER;
239	IgsWaitReady(fPtr);
240	dstpitch = exaGetPixmapPitch(pPixmap) >> fPtr->shift;
241	dstoff = exaGetPixmapOffset(pPixmap) >> fPtr->shift;
242	IgsWrite4(fPtr, IGS_COP_DST_START_REG, dstoff + x1 +
243	    dstpitch * y1);
244	IgsWrite2(fPtr, IGS_COP_WIDTH_REG, w - 1);
245	IgsWrite2(fPtr, IGS_COP_HEIGHT_REG, h - 1);
246	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG, fPtr->cmd & 0xffff);
247	IgsWrite2(fPtr, IGS_COP_PIXEL_OP_REG + 2, (fPtr->cmd >> 16) & 0xffff);
248	exaMarkSync(pPixmap->drawable.pScreen);
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) >> 3;
265	int wBytes = w * cpp;
266
267	ENTER;
268	dst += (x * cpp) + (y * dst_pitch);
269
270	IgsWaitReady(fPtr);
271
272	while (h--) {
273		memcpy(dst, src, wBytes);
274		src += src_pitch;
275		dst += dst_pitch;
276	}
277	LEAVE;
278	return TRUE;
279}
280
281/*
282 * Memcpy-based DFS.
283 */
284static Bool
285IgsDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
286    char *dst, int dst_pitch)
287{
288	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
289	IgsPtr fPtr = IGSPTR(pScrn);
290	char  *src        = fPtr->fbmem + exaGetPixmapOffset(pSrc);
291	int    src_pitch  = exaGetPixmapPitch(pSrc);
292
293	int bpp    = pSrc->drawable.bitsPerPixel;
294	int cpp    = (bpp + 7) >> 3;
295	int wBytes = w * cpp;
296
297	ENTER;
298	src += (x * cpp) + (y * src_pitch);
299
300	IgsWaitReady(fPtr);
301
302	while (h--) {
303		memcpy(dst, src, wBytes);
304		src += src_pitch;
305		dst += dst_pitch;
306	}
307	LEAVE;
308	return TRUE;
309}
310
311#ifdef __arm__
312static Bool
313IgsPrepareAccess(PixmapPtr pPix, int index)
314{
315	ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
316	IgsPtr fPtr = IGSPTR(pScrn);
317
318	IgsWaitReady(fPtr);
319	return TRUE;
320}
321
322static void
323IgsFinishAccess(PixmapPtr pPix, int index)
324{
325}
326#endif
327
328Bool
329IgsInitAccel(ScreenPtr pScreen)
330{
331	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
332	IgsPtr fPtr = IGSPTR(pScrn);
333	ExaDriverPtr pExa;
334
335	pExa = exaDriverAlloc();
336	if (!pExa)
337		return FALSE;
338
339	fPtr->pExa = pExa;
340
341	pExa->exa_major = EXA_VERSION_MAJOR;
342	pExa->exa_minor = EXA_VERSION_MINOR;
343
344	pExa->memoryBase = fPtr->fbmem;
345	pExa->memorySize = fPtr->fbmem_len;
346	pExa->offScreenBase = fPtr->linebytes * fPtr->info.height;
347	pExa->pixmapOffsetAlign = 4;
348	pExa->pixmapPitchAlign = 4;
349
350	pExa->flags = EXA_OFFSCREEN_PIXMAPS;
351
352	pExa->maxX = 2048;
353	pExa->maxY = 2048;
354
355	pExa->WaitMarker = IgsWaitMarker;
356	pExa->PrepareSolid = IgsPrepareSolid;
357	pExa->Solid = IgsSolid;
358	pExa->DoneSolid = IgsDoneCopy;
359	pExa->PrepareCopy = IgsPrepareCopy;
360	pExa->Copy = IgsCopy;
361	pExa->DoneCopy = IgsDoneCopy;
362
363	switch(fPtr->info.depth) {
364		case 8:
365			fPtr->shift = 0;
366			fPtr->mapfmt = IGS_COP_MAP_8BPP;
367			break;
368		case 16:
369			fPtr->shift = 1;
370			fPtr->mapfmt = IGS_COP_MAP_16BPP;
371			break;
372		case 24:
373		case 32:
374			fPtr->shift = 2;
375			fPtr->mapfmt = IGS_COP_MAP_32BPP;
376			break;
377		default:
378			ErrorF("Unsupported depth: %d\n", fPtr->info.depth);
379	}
380	IgsWrite1(fPtr, IGS_COP_MAP_FMT_REG, fPtr->mapfmt);
381
382	/* EXA hits more optimized paths when it does not have to fallback
383	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
384	 */
385	pExa->UploadToScreen = IgsUploadToScreen;
386	pExa->DownloadFromScreen = IgsDownloadFromScreen;
387#ifdef __arm__
388	pExa->PrepareAccess = IgsPrepareAccess;
389	pExa->FinishAccess = IgsFinishAccess;
390#endif
391	return exaDriverInit(pScreen, pExa);
392}
393