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