ngle_accel.c revision 7517da51
1/*
2 * NGLE - hardware acceleration.
3 *
4 * Copyright (C) 2024 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: ngle_accel.c,v 1.6 2024/12/07 10:48:38 macallan Exp $ */
25
26#include <sys/types.h>
27#include <dev/ic/stireg.h>
28
29
30#include "ngle.h"
31
32//#define DEBUG
33
34#ifdef DEBUG
35#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
36#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
37#define DBGMSG xf86Msg
38#else
39#define ENTER
40#define DBGMSG if (0) xf86Msg
41#define LEAVE
42#endif
43
44static void
45NGLEWaitMarker(ScreenPtr pScreen, int Marker)
46{
47	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
48	NGLEPtr fPtr = NGLEPTR(pScrn);
49	uint8_t stat;
50
51	ENTER;
52	do {
53		stat = NGLERead1(fPtr, NGLE_REG_15b0);
54		if (stat == 0)
55			stat = NGLERead1(fPtr, NGLE_REG_15b0);
56	} while (stat != 0);
57	LEAVE;
58}
59
60static void
61NGLEWaitFifo(NGLEPtr fPtr, int slots)
62{
63	uint32_t reg;
64
65	ENTER;
66	do {
67		reg = NGLERead4(fPtr, NGLE_REG_34);
68	} while (reg < slots);
69	LEAVE;
70}
71
72static Bool
73NGLEPrepareCopy_EG
74(
75    PixmapPtr pSrcPixmap,
76    PixmapPtr pDstPixmap,
77    int       xdir,
78    int       ydir,
79    int       alu,
80    Pixel     planemask
81)
82{
83	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
84	NGLEPtr fPtr = NGLEPTR(pScrn);
85	int srcpitch = exaGetPixmapPitch(pSrcPixmap);
86	int srcoff = exaGetPixmapOffset(pSrcPixmap);
87
88	ENTER;
89
90	DBGMSG(X_ERROR, "%s %d %d\n", __func__, srcoff, srcpitch);
91	fPtr->offset = srcoff >> 11;
92	NGLEWaitMarker(pDstPixmap->drawable.pScreen, 0);
93	NGLEWrite4(fPtr, NGLE_REG_10,
94	    BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, BINapp0I, 0));
95	NGLEWrite4(fPtr, NGLE_REG_14,
96	    IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0));
97	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
98
99	fPtr->hwmode = HW_BLIT;
100
101	LEAVE;
102	return TRUE;
103}
104
105static Bool
106NGLEPrepareCopy_HCRX
107(
108    PixmapPtr pSrcPixmap,
109    PixmapPtr pDstPixmap,
110    int       xdir,
111    int       ydir,
112    int       alu,
113    Pixel     planemask
114)
115{
116	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
117	NGLEPtr fPtr = NGLEPTR(pScrn);
118	int srcpitch = exaGetPixmapPitch(pSrcPixmap);
119	int srcoff = exaGetPixmapOffset(pSrcPixmap);
120
121	ENTER;
122
123	DBGMSG(X_ERROR, "%s %d %d\n", __func__, srcoff, srcpitch);
124	fPtr->offset = srcoff / srcpitch;
125	NGLEWaitMarker(pDstPixmap->drawable.pScreen, 0);
126	NGLEWrite4(fPtr, NGLE_REG_10,
127	    BA(FractDcd, Otc24, Ots08, AddrLong, 0, BINapp0F8, 0));
128	NGLEWrite4(fPtr, NGLE_REG_14,
129	    IBOvals(RopSrc, 0, BitmapExtent32, 0, DataDynamic, MaskOtc, 0, 0));
130	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
131
132	fPtr->hwmode = HW_BLIT;
133
134	LEAVE;
135	return TRUE;
136}
137
138static void
139NGLECopy
140(
141    PixmapPtr pDstPixmap,
142    int       xs,
143    int       ys,
144    int       xd,
145    int       yd,
146    int       wi,
147    int       he
148)
149{
150	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
151	NGLEPtr fPtr = NGLEPTR(pScrn);
152	int dstpitch = exaGetPixmapPitch(pDstPixmap);
153	int dstoff = exaGetPixmapOffset(pDstPixmap);
154
155	ENTER;
156	NGLEWaitFifo(fPtr, 3);
157	NGLEWrite4(fPtr, NGLE_REG_24, (xs << 16) | (ys + fPtr->offset));
158	NGLEWrite4(fPtr, NGLE_REG_7, (wi << 16) | he);
159	NGLEWrite4(fPtr, NGLE_REG_25, (xd << 16) | (yd + (dstoff / dstpitch)));
160
161	exaMarkSync(pDstPixmap->drawable.pScreen);
162	LEAVE;
163}
164
165static void
166NGLEDoneCopy(PixmapPtr pDstPixmap)
167{
168    ENTER;
169    LEAVE;
170}
171
172static Bool
173NGLEPrepareSolid_EG(
174    PixmapPtr pPixmap,
175    int alu,
176    Pixel planemask,
177    Pixel fg)
178{
179	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
180	NGLEPtr fPtr = NGLEPTR(pScrn);
181
182	ENTER;
183	NGLEWaitFifo(fPtr, 4);
184	/* plane mask */
185	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
186	/* bitmap op */
187	NGLEWrite4(fPtr, NGLE_REG_14,
188	    IBOvals(alu, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 1, 0));
189	/* dst bitmap access */
190	NGLEWrite4(fPtr, NGLE_REG_11,
191	    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0I, 0));
192    	NGLEWrite4(fPtr, NGLE_REG_35, fg);
193	fPtr->hwmode = HW_FILL;
194
195	LEAVE;
196	return TRUE;
197}
198
199static Bool
200NGLEPrepareSolid_HCRX(
201    PixmapPtr pPixmap,
202    int alu,
203    Pixel planemask,
204    Pixel fg)
205{
206	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
207	NGLEPtr fPtr = NGLEPTR(pScrn);
208
209	ENTER;
210	NGLEWaitFifo(fPtr, 4);
211	/* plane mask */
212	NGLEWrite4(fPtr, NGLE_REG_13, planemask);
213	/* bitmap op */
214	NGLEWrite4(fPtr, NGLE_REG_14,
215	    IBOvals(alu, 0, BitmapExtent32, 0, DataDynamic, MaskOtc, 1, 0));
216	/* dst bitmap access */
217	NGLEWrite4(fPtr, NGLE_REG_11,
218	    BA(FractDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0F8, 0));
219    	NGLEWrite4(fPtr, NGLE_REG_35, fg);
220	fPtr->hwmode = HW_FILL;
221
222	LEAVE;
223	return TRUE;
224}
225
226static void
227NGLESolid(
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	NGLEPtr fPtr = NGLEPTR(pScrn);
236	int w = x2 - x1, h = y2 - y1;
237	int pitch = exaGetPixmapPitch(pPixmap);
238	int offset = exaGetPixmapOffset(pPixmap);
239	uint32_t mask;
240	int wi, rest;
241
242	ENTER;
243
244	y1 += offset / pitch;
245
246	/*
247	 * XXX
248	 * Turns out this thing always fills rectangles to the next 32 pixel
249	 * boundary on te right. To get around this we split the rectangle
250	 * into a multiples-of-32 part and the rest, so we can mask off the
251	 * excess pixels.
252	 */
253	rest = w & 0x1f;
254	wi = w & 0xffffe0;
255	if (wi > 0) {
256		NGLEWaitFifo(fPtr, 3);
257		/* transfer data */
258		NGLEWrite4(fPtr, NGLE_REG_8, 0xffffffff);
259		/* dst XY */
260		NGLEWrite4(fPtr, NGLE_REG_6, (x1 << 16) | y1);
261		/* len XY start */
262		NGLEWrite4(fPtr, NGLE_REG_9, (wi << 16) | h);
263	}
264	if (rest > 0) {
265		mask = 0xffffffff << (32 - w);
266		/* transfer data */
267		NGLEWaitFifo(fPtr, 3);
268		NGLEWrite4(fPtr, NGLE_REG_8, mask);
269		/* dst XY */
270		NGLEWrite4(fPtr, NGLE_REG_6, ((x1 + wi) << 16) | y1);
271		/* len XY start */
272		NGLEWrite4(fPtr, NGLE_REG_9, (rest << 16) | h);
273	}
274	exaMarkSync(pPixmap->drawable.pScreen);
275	LEAVE;
276}
277
278Bool
279NGLEPrepareAccess_EG(PixmapPtr pPixmap, int index)
280{
281	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
282	NGLEPtr fPtr = NGLEPTR(pScrn);
283
284	if (fPtr->hwmode == HW_FB) return TRUE;
285
286	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
287	NGLEWrite4(fPtr, NGLE_REG_10,
288	    BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, BINapp0I, 0));
289	NGLEWrite4(fPtr, NGLE_REG_14, 0x83000300);
290	NGLEWrite4(fPtr, NGLE_REG_13, 0xff);
291	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
292	NGLEWrite1(fPtr, NGLE_REG_16b1, 1);
293	fPtr->hwmode = HW_FB;
294	return TRUE;
295}
296
297Bool
298NGLEPrepareAccess_HCRX(PixmapPtr pPixmap, int index)
299{
300	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
301	NGLEPtr fPtr = NGLEPTR(pScrn);
302
303	if (fPtr->hwmode == HW_FB) return TRUE;
304
305	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
306	NGLEWrite4(fPtr, NGLE_REG_10,
307	    BA(FractDcd, Otc24, Ots08, AddrLong, 0, BINapp0F8, 0));
308	NGLEWrite4(fPtr, NGLE_REG_14, 0x83000300);
309	NGLEWrite4(fPtr, NGLE_REG_13, 0xffffffff);
310	NGLEWaitMarker(pPixmap->drawable.pScreen, 0);
311	NGLEWrite1(fPtr, NGLE_REG_16b1, 1);
312	fPtr->hwmode = HW_FB;
313	return TRUE;
314}
315Bool
316NGLEInitAccel(ScreenPtr pScreen)
317{
318	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
319	NGLEPtr fPtr = NGLEPTR(pScrn);
320	ExaDriverPtr pExa;
321	int lines, bpp = pScrn->bitsPerPixel >> 3;
322
323	pExa = exaDriverAlloc();
324	if (!pExa)
325		return FALSE;
326
327	fPtr->pExa = pExa;
328
329	pExa->exa_major = EXA_VERSION_MAJOR;
330	pExa->exa_minor = EXA_VERSION_MINOR;
331
332	pExa->memoryBase = fPtr->fbmem;
333	lines = fPtr->fbmem_len / fPtr->fbi.fbi_stride;
334	DBGMSG(X_ERROR, "lines %d\n", lines);
335	pExa->memorySize = fPtr->fbmem_len;
336	pExa->offScreenBase = fPtr->fbi.fbi_stride * fPtr->fbi.fbi_height;
337	pExa->pixmapOffsetAlign = fPtr->fbi.fbi_stride;
338	pExa->pixmapPitchAlign = fPtr->fbi.fbi_stride;
339
340	pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_MIXED_PIXMAPS;
341
342	pExa->maxX = 2048;
343	pExa->maxY = 2048;
344
345	fPtr->hwmode = -1;
346
347	pExa->WaitMarker = NGLEWaitMarker;
348	pExa->Solid = NGLESolid;
349	pExa->DoneSolid = NGLEDoneCopy;
350	pExa->Copy = NGLECopy;
351	pExa->DoneCopy = NGLEDoneCopy;
352	switch (fPtr->gid) {
353		case STI_DD_EG:
354			pExa->PrepareCopy = NGLEPrepareCopy_EG;
355			pExa->PrepareSolid = NGLEPrepareSolid_EG;
356			pExa->PrepareAccess = NGLEPrepareAccess_EG;
357			break;
358		case STI_DD_HCRX:
359			pExa->PrepareCopy = NGLEPrepareCopy_HCRX;
360			pExa->PrepareSolid = NGLEPrepareSolid_HCRX;
361			pExa->PrepareAccess = NGLEPrepareAccess_HCRX;
362			break;
363		default:
364			xf86Msg(X_ERROR,
365			    "unsupported device GID %08x\n", fPtr->gid);
366			return FALSE;
367	}
368	NGLEWaitMarker(pScreen, 0);
369
370	return exaDriverInit(pScreen, pExa);
371}
372