xref: /plan9-contrib/sys/src/9/pc/vgaradeon.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
1b2495906SDavid du Colombier /*
2b2495906SDavid du Colombier  * ATI Radeon [789]XXX vga driver
3b2495906SDavid du Colombier  * see /sys/src/cmd/aux/vga/radeon.c
4b2495906SDavid du Colombier  */
5b2495906SDavid du Colombier #include "u.h"
6b2495906SDavid du Colombier #include "../port/lib.h"
7b2495906SDavid du Colombier #include "mem.h"
8b2495906SDavid du Colombier #include "dat.h"
9b2495906SDavid du Colombier #include "fns.h"
10b2495906SDavid du Colombier #include "io.h"
11b2495906SDavid du Colombier #include "../port/error.h"
12b2495906SDavid du Colombier 
13b2495906SDavid du Colombier #define Image	IMAGE
14b2495906SDavid du Colombier #include <draw.h>
15b2495906SDavid du Colombier #include <memdraw.h>
16b2495906SDavid du Colombier #include <cursor.h>
17b2495906SDavid du Colombier #include "screen.h"
18b2495906SDavid du Colombier 
19b2495906SDavid du Colombier #include "/sys/src/cmd/aux/vga/radeon.h"	/* ugh */
20b2495906SDavid du Colombier 
21b2495906SDavid du Colombier /* #define HW_ACCEL */
22b2495906SDavid du Colombier 
23b2495906SDavid du Colombier enum {
24b2495906SDavid du Colombier 	Kilo	= 1024,
25b2495906SDavid du Colombier 	Meg	= Kilo * Kilo,
26b2495906SDavid du Colombier };
27b2495906SDavid du Colombier 
28b2495906SDavid du Colombier static Pcidev*
radeonpci(void)29b2495906SDavid du Colombier radeonpci(void)
30b2495906SDavid du Colombier {
31b2495906SDavid du Colombier 	static Pcidev *p = nil;
32b2495906SDavid du Colombier 	struct pciids *ids;
33b2495906SDavid du Colombier 
34b2495906SDavid du Colombier 	while ((p = pcimatch(p, ATI_PCIVID, 0)) != nil)
35b2495906SDavid du Colombier 		for (ids = radeon_pciids; ids->did; ids++)
36b2495906SDavid du Colombier 			if (ids->did == p->did)
37b2495906SDavid du Colombier 				return p;
38b2495906SDavid du Colombier 	return nil;
39b2495906SDavid du Colombier }
40b2495906SDavid du Colombier 
41b2495906SDavid du Colombier /* mmio access */
42b2495906SDavid du Colombier 
43b2495906SDavid du Colombier static void
OUTREG8(ulong mmio,ulong offset,uchar val)44b2495906SDavid du Colombier OUTREG8(ulong mmio, ulong offset, uchar val)
45b2495906SDavid du Colombier {
46b2495906SDavid du Colombier 	((uchar*)KADDR((mmio + offset)))[0] = val;
47b2495906SDavid du Colombier }
48b2495906SDavid du Colombier 
49b2495906SDavid du Colombier static void
OUTREG(ulong mmio,ulong offset,ulong val)50b2495906SDavid du Colombier OUTREG(ulong mmio, ulong offset, ulong val)
51b2495906SDavid du Colombier {
52b2495906SDavid du Colombier 	((ulong*)KADDR((mmio + offset)))[0] = val;
53b2495906SDavid du Colombier }
54b2495906SDavid du Colombier 
55b2495906SDavid du Colombier static ulong
INREG(ulong mmio,ulong offset)56b2495906SDavid du Colombier INREG(ulong mmio, ulong offset)
57b2495906SDavid du Colombier {
58b2495906SDavid du Colombier 	return ((ulong*)KADDR((mmio + offset)))[0];
59b2495906SDavid du Colombier }
60b2495906SDavid du Colombier 
61b2495906SDavid du Colombier static void
OUTREGP(ulong mmio,ulong offset,ulong val,ulong mask)62b2495906SDavid du Colombier OUTREGP(ulong mmio, ulong offset, ulong val, ulong mask)
63b2495906SDavid du Colombier {
64b2495906SDavid du Colombier 	OUTREG(mmio, offset, (INREG(mmio, offset) & mask) | val);
65b2495906SDavid du Colombier }
66b2495906SDavid du Colombier 
67b2495906SDavid du Colombier static void
OUTPLL(ulong mmio,ulong offset,ulong val)68b2495906SDavid du Colombier OUTPLL(ulong mmio, ulong offset, ulong val)
69b2495906SDavid du Colombier {
70b2495906SDavid du Colombier 	OUTREG8(mmio, CLOCK_CNTL_INDEX, (offset & 0x3f) | PLL_WR_EN);
71b2495906SDavid du Colombier 	OUTREG(mmio, CLOCK_CNTL_DATA, val);
72b2495906SDavid du Colombier }
73b2495906SDavid du Colombier 
74b2495906SDavid du Colombier static ulong
INPLL(ulong mmio,ulong offset)75b2495906SDavid du Colombier INPLL(ulong mmio, ulong offset)
76b2495906SDavid du Colombier {
77b2495906SDavid du Colombier 	OUTREG8(mmio, CLOCK_CNTL_INDEX, offset & 0x3f);
78b2495906SDavid du Colombier 	return INREG(mmio, CLOCK_CNTL_DATA);
79b2495906SDavid du Colombier }
80b2495906SDavid du Colombier 
81b2495906SDavid du Colombier static void
OUTPLLP(ulong mmio,ulong offset,ulong val,ulong mask)82b2495906SDavid du Colombier OUTPLLP(ulong mmio, ulong offset, ulong val, ulong mask)
83b2495906SDavid du Colombier {
84b2495906SDavid du Colombier 	OUTPLL(mmio, offset, (INPLL(mmio, offset) & mask) | val);
85b2495906SDavid du Colombier }
86b2495906SDavid du Colombier 
87b2495906SDavid du Colombier static void
radeonlinear(VGAscr *,int,int)88b2495906SDavid du Colombier radeonlinear(VGAscr *, int, int)
89b2495906SDavid du Colombier {
90b2495906SDavid du Colombier }
91b2495906SDavid du Colombier 
92b2495906SDavid du Colombier static void
radeonenable(VGAscr * scr)93b2495906SDavid du Colombier radeonenable(VGAscr *scr)
94b2495906SDavid du Colombier {
95b2495906SDavid du Colombier 	Pcidev *p;
96b2495906SDavid du Colombier 
97b2495906SDavid du Colombier 	if (scr->mmio)
98b2495906SDavid du Colombier 		return;
99b2495906SDavid du Colombier 	p = radeonpci();
100b2495906SDavid du Colombier 	if (p == nil)
101b2495906SDavid du Colombier 		return;
102b2495906SDavid du Colombier 	scr->id = p->did;
103b2495906SDavid du Colombier 	scr->pci = p;
104b2495906SDavid du Colombier 
105b2495906SDavid du Colombier 	scr->mmio = vmap(p->mem[2].bar & ~0x0f, p->mem[2].size);
106b2495906SDavid du Colombier 	if(scr->mmio == 0)
107b2495906SDavid du Colombier 		return;
108b2495906SDavid du Colombier 	addvgaseg("radeonmmio", p->mem[2].bar & ~0x0f, p->mem[2].size);
109b2495906SDavid du Colombier 
110b2495906SDavid du Colombier 	vgalinearpci(scr);
111*cb8c047aSDavid du Colombier 	if(scr->apsize)
112b2495906SDavid du Colombier 		addvgaseg("radeonscreen", scr->paddr, scr->apsize);
113b2495906SDavid du Colombier }
114b2495906SDavid du Colombier 
115b2495906SDavid du Colombier static void
radeoncurload(VGAscr * scr,Cursor * curs)116b2495906SDavid du Colombier radeoncurload(VGAscr *scr, Cursor *curs)
117b2495906SDavid du Colombier {
118b2495906SDavid du Colombier 	int x, y;
119b2495906SDavid du Colombier 	ulong *p;
120b2495906SDavid du Colombier 
121b2495906SDavid du Colombier 	if(scr->mmio == nil)
122b2495906SDavid du Colombier 		return;
123b2495906SDavid du Colombier 
124b2495906SDavid du Colombier 	p = (ulong*)KADDR(scr->storage);
125b2495906SDavid du Colombier 
126b2495906SDavid du Colombier 	for(y = 0; y < 64; y++){
127b2495906SDavid du Colombier 		int cv, sv;
128b2495906SDavid du Colombier 
129b2495906SDavid du Colombier 		if (y < 16) {
130b2495906SDavid du Colombier 			cv = curs->clr[2*y] << 8 | curs->clr[2*y+1];
131b2495906SDavid du Colombier 			sv = curs->set[2*y] << 8 | curs->set[2*y+1];
132b2495906SDavid du Colombier 		} else
133b2495906SDavid du Colombier 			cv = sv = 0;
134b2495906SDavid du Colombier 
135b2495906SDavid du Colombier 		for(x = 0; x < 64; x++){
136b2495906SDavid du Colombier 			ulong col = 0;
137b2495906SDavid du Colombier 			int c, s;
138b2495906SDavid du Colombier 
139b2495906SDavid du Colombier 			if (x < 16) {
140b2495906SDavid du Colombier 				c = (cv >> (15 - x)) & 1;
141b2495906SDavid du Colombier 				s = (sv >> (15 - x)) & 1;
142b2495906SDavid du Colombier 			} else
143b2495906SDavid du Colombier 				c = s = 0;
144b2495906SDavid du Colombier 
145b2495906SDavid du Colombier 			switch(c | s<<1) {
146b2495906SDavid du Colombier 			case 0:
147b2495906SDavid du Colombier 				col = 0;
148b2495906SDavid du Colombier 				break;
149b2495906SDavid du Colombier 			case 1:
150b2495906SDavid du Colombier 				col = ~0ul;		/* white */
151b2495906SDavid du Colombier 				break;
152b2495906SDavid du Colombier 			case 2:
153b2495906SDavid du Colombier 			case 3:
154b2495906SDavid du Colombier 				col = 0xff000000;	/* black */
155b2495906SDavid du Colombier 				break;
156b2495906SDavid du Colombier 			}
157b2495906SDavid du Colombier 
158b2495906SDavid du Colombier 			*p++ = col;
159b2495906SDavid du Colombier 		}
160b2495906SDavid du Colombier 	}
161b2495906SDavid du Colombier 
162b2495906SDavid du Colombier 	scr->offset.x = curs->offset.x;
163b2495906SDavid du Colombier 	scr->offset.y = curs->offset.y;
164b2495906SDavid du Colombier }
165b2495906SDavid du Colombier 
166b2495906SDavid du Colombier static int
radeoncurmove(VGAscr * scr,Point p)167b2495906SDavid du Colombier radeoncurmove(VGAscr *scr, Point p)
168b2495906SDavid du Colombier {
169b2495906SDavid du Colombier 	int x, y, ox, oy;
170b2495906SDavid du Colombier 	static ulong storage = 0;
171b2495906SDavid du Colombier 
172b2495906SDavid du Colombier 	if(scr->mmio == nil)
173b2495906SDavid du Colombier 		return 1;
174b2495906SDavid du Colombier 
175b2495906SDavid du Colombier 	if (storage == 0)
176b2495906SDavid du Colombier 		storage = scr->apsize - 1*Meg;
177b2495906SDavid du Colombier 
178b2495906SDavid du Colombier 	x = p.x + scr->offset.x;
179b2495906SDavid du Colombier 	y = p.y + scr->offset.y;
180b2495906SDavid du Colombier 	ox = oy = 0;
181b2495906SDavid du Colombier 
182b2495906SDavid du Colombier 	if (x < 0) {
183b2495906SDavid du Colombier 		ox = -x - 1;
184b2495906SDavid du Colombier 		x = 0;
185b2495906SDavid du Colombier 	}
186b2495906SDavid du Colombier 	if (y < 0) {
187b2495906SDavid du Colombier 		oy = -y - 1;
188b2495906SDavid du Colombier 		y = 0;
189b2495906SDavid du Colombier 	}
190b2495906SDavid du Colombier 
191b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, CUR_OFFSET, storage + oy * 256);
192b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_OFF,
193b2495906SDavid du Colombier 		(ox & 0x7fff) << 16 | (oy & 0x7fff));
194b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_POSN,
195b2495906SDavid du Colombier 		(x & 0x7fff) << 16 | (y & 0x7fff));
196b2495906SDavid du Colombier 	return 0;
197b2495906SDavid du Colombier }
198b2495906SDavid du Colombier 
199b2495906SDavid du Colombier static void
radeoncurdisable(VGAscr * scr)200b2495906SDavid du Colombier radeoncurdisable(VGAscr *scr)
201b2495906SDavid du Colombier {
202b2495906SDavid du Colombier 	if(scr->mmio == nil)
203b2495906SDavid du Colombier 		return;
204b2495906SDavid du Colombier 	OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, 0, ~CRTC_CUR_EN);
205b2495906SDavid du Colombier }
206b2495906SDavid du Colombier 
207b2495906SDavid du Colombier static void
radeoncurenable(VGAscr * scr)208b2495906SDavid du Colombier radeoncurenable(VGAscr *scr)
209b2495906SDavid du Colombier {
210b2495906SDavid du Colombier 	ulong storage;
211b2495906SDavid du Colombier 
212b2495906SDavid du Colombier 	if(scr->mmio == 0)
213b2495906SDavid du Colombier 		return;
214b2495906SDavid du Colombier 
215b2495906SDavid du Colombier 	radeoncurdisable(scr);
216b2495906SDavid du Colombier 	storage = scr->apsize - 1*Meg;
217b2495906SDavid du Colombier 	scr->storage = (ulong)KADDR(scr->paddr + storage);
218b2495906SDavid du Colombier 	radeoncurload(scr, &arrow);
219b2495906SDavid du Colombier 	radeoncurmove(scr, ZP);
220b2495906SDavid du Colombier 
221b2495906SDavid du Colombier 	OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, CRTC_CUR_EN | 2<<20,
222b2495906SDavid du Colombier 		~(CRTC_CUR_EN | 3<<20));
223b2495906SDavid du Colombier }
224b2495906SDavid du Colombier 
225b2495906SDavid du Colombier /* hw blank */
226b2495906SDavid du Colombier 
227b2495906SDavid du Colombier static void
radeonblank(VGAscr * scr,int blank)228b2495906SDavid du Colombier radeonblank(VGAscr* scr, int blank)
229b2495906SDavid du Colombier {
230b2495906SDavid du Colombier 	ulong mask;
231b2495906SDavid du Colombier 	char *cp;
232b2495906SDavid du Colombier 
233b2495906SDavid du Colombier 	if (scr->mmio == 0)
234b2495906SDavid du Colombier 		return;
235b2495906SDavid du Colombier 
236b2495906SDavid du Colombier //	iprint("radeon: hwblank(%d)\n", blank);
237b2495906SDavid du Colombier 
238b2495906SDavid du Colombier 	mask = CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
239b2495906SDavid du Colombier 	if (blank == 0) {
240b2495906SDavid du Colombier 		OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, 0, ~mask);
241b2495906SDavid du Colombier 		return;
242b2495906SDavid du Colombier 	}
243b2495906SDavid du Colombier 
244b2495906SDavid du Colombier 	cp = getconf("*dpms");
245b2495906SDavid du Colombier 	if (cp) {
246b2495906SDavid du Colombier 		if (strcmp(cp, "standby") == 0)
247b2495906SDavid du Colombier 			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
248b2495906SDavid du Colombier 				CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS, ~mask);
249b2495906SDavid du Colombier 		else if (strcmp(cp, "suspend") == 0)
250b2495906SDavid du Colombier 			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
251b2495906SDavid du Colombier 				CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS, ~mask);
252b2495906SDavid du Colombier 		else if (strcmp(cp, "off") == 0)
253b2495906SDavid du Colombier 			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
254b2495906SDavid du Colombier 		return;
255b2495906SDavid du Colombier 	}
256b2495906SDavid du Colombier 
257b2495906SDavid du Colombier 	OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
258b2495906SDavid du Colombier }
259b2495906SDavid du Colombier 
260b2495906SDavid du Colombier /* hw acceleration */
261b2495906SDavid du Colombier 
262b2495906SDavid du Colombier static void
radeonwaitfifo(VGAscr * scr,int entries)263b2495906SDavid du Colombier radeonwaitfifo(VGAscr *scr, int entries)
264b2495906SDavid du Colombier {
265b2495906SDavid du Colombier 	int i;
266b2495906SDavid du Colombier 
267b2495906SDavid du Colombier 	for (i = 0; i < 2000000; i++)
268b2495906SDavid du Colombier 		if (INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK >=
269b2495906SDavid du Colombier 		    entries)
270b2495906SDavid du Colombier 			return;
271b2495906SDavid du Colombier 	iprint("radeon: fifo timeout\n");
272b2495906SDavid du Colombier }
273b2495906SDavid du Colombier 
274b2495906SDavid du Colombier static void
radeonwaitidle(VGAscr * scr)275b2495906SDavid du Colombier radeonwaitidle(VGAscr *scr)
276b2495906SDavid du Colombier {
277b2495906SDavid du Colombier 	radeonwaitfifo(scr, 64);
278b2495906SDavid du Colombier 
279b2495906SDavid du Colombier 	for (; ; ) {
280b2495906SDavid du Colombier 		int i;
281b2495906SDavid du Colombier 
282b2495906SDavid du Colombier 		for (i = 0; i < 2000000; i++)
283b2495906SDavid du Colombier 			if (!(INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_ACTIVE))
284b2495906SDavid du Colombier 				return;
285b2495906SDavid du Colombier 
286b2495906SDavid du Colombier 		iprint("radeon: idle timed out: %uld entries, stat=0x%.8ulx\n",
287b2495906SDavid du Colombier 			INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK,
288b2495906SDavid du Colombier 			INREG((ulong)scr->mmio, RBBM_STATUS));
289b2495906SDavid du Colombier 	}
290b2495906SDavid du Colombier }
291b2495906SDavid du Colombier 
292b2495906SDavid du Colombier static ulong dp_gui_master_cntl = 0;
293b2495906SDavid du Colombier 
294b2495906SDavid du Colombier static int
radeonfill(VGAscr * scr,Rectangle r,ulong color)295b2495906SDavid du Colombier radeonfill(VGAscr *scr, Rectangle r, ulong color)
296b2495906SDavid du Colombier {
297b2495906SDavid du Colombier 	if (scr->mmio == nil)
298b2495906SDavid du Colombier 		return 0;
299b2495906SDavid du Colombier 
300b2495906SDavid du Colombier 	radeonwaitfifo(scr, 6);
301b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
302b2495906SDavid du Colombier 		dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR |
303b2495906SDavid du Colombier 		GMC_SRC_DATATYPE_COLOR | ROP3_P);
304b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, color);
305b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
306b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_CNTL,
307b2495906SDavid du Colombier 		DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
308b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_Y_X, r.min.y << 16 | r.min.x);
309b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, Dx(r) << 16 | Dy(r));
310b2495906SDavid du Colombier 
311b2495906SDavid du Colombier 	radeonwaitidle(scr);
312b2495906SDavid du Colombier 	return 1;
313b2495906SDavid du Colombier }
314b2495906SDavid du Colombier 
315b2495906SDavid du Colombier static int
radeonscroll(VGAscr * scr,Rectangle dst,Rectangle src)316b2495906SDavid du Colombier radeonscroll(VGAscr*scr, Rectangle dst, Rectangle src)
317b2495906SDavid du Colombier {
318b2495906SDavid du Colombier 	int xs, ys, xd, yd, w, h;
319b2495906SDavid du Colombier 	ulong dp_cntl = 0x20;
320b2495906SDavid du Colombier 
321b2495906SDavid du Colombier 	if (scr->mmio == nil)
322b2495906SDavid du Colombier 		return 0;
323b2495906SDavid du Colombier 
324b2495906SDavid du Colombier 	// iprint("radeon: hwscroll(dst:%R, src:%R)\n", dst, src);
325b2495906SDavid du Colombier 
326b2495906SDavid du Colombier 	xd = dst.min.x;
327b2495906SDavid du Colombier 	yd = dst.min.y;
328b2495906SDavid du Colombier 	xs = src.min.x;
329b2495906SDavid du Colombier 	ys = src.min.y;
330b2495906SDavid du Colombier 	w = Dx(dst);
331b2495906SDavid du Colombier 	h = Dy(dst);
332b2495906SDavid du Colombier 
333b2495906SDavid du Colombier 	if (ys < yd) {
334b2495906SDavid du Colombier 		ys += h - 1;
335b2495906SDavid du Colombier 		yd += h - 1;
336b2495906SDavid du Colombier 	} else
337b2495906SDavid du Colombier 		dp_cntl |= DST_Y_TOP_TO_BOTTOM;
338b2495906SDavid du Colombier 
339b2495906SDavid du Colombier 	if (xs < xd) {
340b2495906SDavid du Colombier 		xs += w - 1;
341b2495906SDavid du Colombier 		xd += w - 1;
342b2495906SDavid du Colombier 	} else
343b2495906SDavid du Colombier 		dp_cntl |= DST_X_LEFT_TO_RIGHT;
344b2495906SDavid du Colombier 
345b2495906SDavid du Colombier 	radeonwaitfifo(scr, 6);
346b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL, dp_gui_master_cntl |
347b2495906SDavid du Colombier 		GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | DP_SRC_SOURCE_MEMORY |
348b2495906SDavid du Colombier 		ROP3_S);
349b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
350b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_CNTL, dp_cntl);
351b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, SRC_Y_X, ys << 16 | xs);
352b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_Y_X, yd << 16 | xd);
353b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, w << 16 | h);
354b2495906SDavid du Colombier 
355b2495906SDavid du Colombier 	radeonwaitidle(scr);
356b2495906SDavid du Colombier 
357b2495906SDavid du Colombier 	// iprint("radeon: hwscroll(xs=%d ys=%d xd=%d yd=%d w=%d h=%d)\n",
358b2495906SDavid du Colombier 	//	xs, ys, xd, yd, w, h);
359b2495906SDavid du Colombier 	return 1;
360b2495906SDavid du Colombier }
361b2495906SDavid du Colombier 
362b2495906SDavid du Colombier static void
radeondrawinit(VGAscr * scr)363b2495906SDavid du Colombier radeondrawinit(VGAscr*scr)
364b2495906SDavid du Colombier {
365b2495906SDavid du Colombier 	ulong bpp, dtype, i, pitch, clock_cntl_index, mclk_cntl, rbbm_soft_reset;
366b2495906SDavid du Colombier 
367b2495906SDavid du Colombier 	if (scr->mmio == 0)
368b2495906SDavid du Colombier 		return;
369b2495906SDavid du Colombier 
370b2495906SDavid du Colombier 	switch (scr->gscreen->depth) {
371b2495906SDavid du Colombier 	case 6:
372b2495906SDavid du Colombier 	case 8:
373b2495906SDavid du Colombier 		dtype = 2;
374b2495906SDavid du Colombier 		bpp = 1;
375b2495906SDavid du Colombier 		break;
376b2495906SDavid du Colombier 	case 15:
377b2495906SDavid du Colombier 		dtype = 3;
378b2495906SDavid du Colombier 		bpp = 2;
379b2495906SDavid du Colombier 		break;
380b2495906SDavid du Colombier 	case 16:
381b2495906SDavid du Colombier 		dtype = 4;
382b2495906SDavid du Colombier 		bpp = 2;
383b2495906SDavid du Colombier 		break;
384b2495906SDavid du Colombier 	case 32:
385b2495906SDavid du Colombier 		dtype = 6;
386b2495906SDavid du Colombier 		bpp = 4;
387b2495906SDavid du Colombier 		break;
388b2495906SDavid du Colombier 	default:
389b2495906SDavid du Colombier 		return;
390b2495906SDavid du Colombier 	}
391b2495906SDavid du Colombier 
392b2495906SDavid du Colombier 	/* disable 3D */
393b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, RB3D_CNTL, 0);
394b2495906SDavid du Colombier 
395b2495906SDavid du Colombier 	/* flush engine */
396b2495906SDavid du Colombier 	OUTREGP((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT,
397b2495906SDavid du Colombier 		RB2D_DC_FLUSH_ALL, ~RB2D_DC_FLUSH_ALL);
398b2495906SDavid du Colombier 	for (i = 0; i < 2000000; i++)
399b2495906SDavid du Colombier 		if (!(INREG((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT) &
400b2495906SDavid du Colombier 		    RB2D_DC_BUSY))
401b2495906SDavid du Colombier 			break;
402b2495906SDavid du Colombier 
403b2495906SDavid du Colombier 	/* reset 2D engine */
404b2495906SDavid du Colombier 	clock_cntl_index = INREG((ulong)scr->mmio, CLOCK_CNTL_INDEX);
405b2495906SDavid du Colombier 
406b2495906SDavid du Colombier 	mclk_cntl = INPLL((ulong)scr->mmio, MCLK_CNTL);
407b2495906SDavid du Colombier 	OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl | FORCEON_MCLKA |
408b2495906SDavid du Colombier 		FORCEON_MCLKB | FORCEON_YCLKA | FORCEON_YCLKB | FORCEON_MC |
409b2495906SDavid du Colombier 		FORCEON_AIC);
410b2495906SDavid du Colombier 	rbbm_soft_reset = INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
411b2495906SDavid du Colombier 
412b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset |
413b2495906SDavid du Colombier 		SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
414b2495906SDavid du Colombier 		SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB);
415b2495906SDavid du Colombier 	INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
416b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset &
417b2495906SDavid du Colombier 		~(SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
418b2495906SDavid du Colombier 		SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB));
419b2495906SDavid du Colombier 	INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
420b2495906SDavid du Colombier 
421b2495906SDavid du Colombier 	OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl);
422b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, CLOCK_CNTL_INDEX, clock_cntl_index);
423b2495906SDavid du Colombier 
424b2495906SDavid du Colombier 	/* init 2D engine */
425b2495906SDavid du Colombier 	radeonwaitfifo(scr, 1);
426b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, RB2D_DSTCACHE_MODE, 0);
427b2495906SDavid du Colombier 
428b2495906SDavid du Colombier 	pitch = Dx(scr->gscreen->r) * bpp;
429b2495906SDavid du Colombier 	radeonwaitfifo(scr, 4);
430b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DEFAULT_PITCH, pitch);
431b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_PITCH, pitch);
432b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, SRC_PITCH, pitch);
433b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_PITCH_OFFSET_C, 0);
434b2495906SDavid du Colombier 
435b2495906SDavid du Colombier 	radeonwaitfifo(scr, 3);
436b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DEFAULT_OFFSET, 0);
437b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_OFFSET, 0);
438b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, SRC_OFFSET, 0);
439b2495906SDavid du Colombier 
440b2495906SDavid du Colombier 	radeonwaitfifo(scr, 1);
441b2495906SDavid du Colombier 	OUTREGP((ulong)scr->mmio, DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
442b2495906SDavid du Colombier 
443b2495906SDavid du Colombier 	radeonwaitfifo(scr, 1);
444b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DEFAULT_SC_BOTTOM_RIGHT,
445b2495906SDavid du Colombier 		DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX);
446b2495906SDavid du Colombier 
447b2495906SDavid du Colombier 	dp_gui_master_cntl = dtype << GMC_DST_DATATYPE_SHIFT |
448b2495906SDavid du Colombier 		GMC_SRC_PITCH_OFFSET_CNTL | GMC_DST_PITCH_OFFSET_CNTL |
449b2495906SDavid du Colombier 		GMC_CLR_CMP_CNTL_DIS;
450b2495906SDavid du Colombier 	radeonwaitfifo(scr, 1);
451b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
452b2495906SDavid du Colombier 	    dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR);
453b2495906SDavid du Colombier 
454b2495906SDavid du Colombier 	radeonwaitfifo(scr, 7);
455b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_LINE_START,    0);
456b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DST_LINE_END,      0);
457b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, ~0ul);
458b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_BRUSH_BKGD_CLR, 0);
459b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_SRC_FRGD_CLR,   ~0ul);
460b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_SRC_BKGD_CLR,   0);
461b2495906SDavid du Colombier 	OUTREG((ulong)scr->mmio, DP_WRITE_MASK,     ~0ul);
462b2495906SDavid du Colombier 
463b2495906SDavid du Colombier 	radeonwaitidle(scr);
464b2495906SDavid du Colombier 
465b2495906SDavid du Colombier 	scr->fill = radeonfill;
466b2495906SDavid du Colombier 	scr->scroll = radeonscroll;
467b2495906SDavid du Colombier 	hwaccel = 1;
468b2495906SDavid du Colombier 
469b2495906SDavid du Colombier 	scr->blank = radeonblank;
470b2495906SDavid du Colombier 	hwblank = 1;
471b2495906SDavid du Colombier }
472b2495906SDavid du Colombier 
473b2495906SDavid du Colombier /* hw overlay */
474b2495906SDavid du Colombier 
475b2495906SDavid du Colombier static void
radeonovlctl(VGAscr * scr,Chan * c,void * data,int len)476b2495906SDavid du Colombier radeonovlctl(VGAscr *scr, Chan *c, void *data, int len)
477b2495906SDavid du Colombier {
478b2495906SDavid du Colombier 	USED(scr, c, data, len);
479b2495906SDavid du Colombier }
480b2495906SDavid du Colombier 
481b2495906SDavid du Colombier static int
radeonovlwrite(VGAscr * scr,void * data,int len,vlong opt)482b2495906SDavid du Colombier radeonovlwrite(VGAscr *scr, void *data, int len, vlong opt)
483b2495906SDavid du Colombier {
484b2495906SDavid du Colombier 	USED(scr, data, len, opt);
485b2495906SDavid du Colombier 	return -1;
486b2495906SDavid du Colombier }
487b2495906SDavid du Colombier 
488b2495906SDavid du Colombier static void
radeonflush(VGAscr * scr,Rectangle r)489b2495906SDavid du Colombier radeonflush(VGAscr *scr, Rectangle r)
490b2495906SDavid du Colombier {
491b2495906SDavid du Colombier 	USED(scr, r);
492b2495906SDavid du Colombier }
493b2495906SDavid du Colombier 
494b2495906SDavid du Colombier /* Export */
495b2495906SDavid du Colombier 
496b2495906SDavid du Colombier VGAdev vgaradeondev = {
497b2495906SDavid du Colombier 	"radeon",
498b2495906SDavid du Colombier 
499b2495906SDavid du Colombier 	radeonenable,
500b2495906SDavid du Colombier 	0, 				/* disable */
501b2495906SDavid du Colombier 	0, 				/* page */
502b2495906SDavid du Colombier 	radeonlinear,
503b2495906SDavid du Colombier 
504b2495906SDavid du Colombier 	radeondrawinit,
505b2495906SDavid du Colombier #ifdef HW_ACCEL
506b2495906SDavid du Colombier 	radeonfill,
507b2495906SDavid du Colombier 
508b2495906SDavid du Colombier 	radeonovlctl,
509b2495906SDavid du Colombier 	radeonovlwrite,
510b2495906SDavid du Colombier 	radeonflush,
511b2495906SDavid du Colombier #endif
512b2495906SDavid du Colombier };
513b2495906SDavid du Colombier VGAcur vgaradeoncur = {
514b2495906SDavid du Colombier 	"radeonhwgc",
515b2495906SDavid du Colombier 	radeoncurenable,
516b2495906SDavid du Colombier 	radeoncurdisable,
517b2495906SDavid du Colombier 	radeoncurload,
518b2495906SDavid du Colombier 	radeoncurmove,
519b2495906SDavid du Colombier 	0				/* doespanning */
520b2495906SDavid du Colombier };
521