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