xref: /openbsd-src/sys/arch/sparc64/dev/creator.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: creator.c,v 1.40 2008/12/27 17:23:01 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/device.h>
34 #include <sys/conf.h>
35 #include <sys/timeout.h>
36 
37 #include <machine/bus.h>
38 #include <machine/autoconf.h>
39 #include <machine/openfirm.h>
40 
41 #include <dev/wscons/wsconsio.h>
42 #include <dev/wscons/wsdisplayvar.h>
43 #include <dev/rasops/rasops.h>
44 #include <machine/fbvar.h>
45 
46 #include <sparc64/dev/creatorreg.h>
47 #include <sparc64/dev/creatorvar.h>
48 
49 int	creator_match(struct device *, void *, void *);
50 void	creator_attach(struct device *, struct device *, void *);
51 int	creator_ioctl(void *, u_long, caddr_t, int, struct proc *);
52 paddr_t creator_mmap(void *, off_t, int);
53 void	creator_ras_fifo_wait(struct creator_softc *, int);
54 void	creator_ras_wait(struct creator_softc *);
55 void	creator_ras_init(struct creator_softc *);
56 void	creator_ras_copyrows(void *, int, int, int);
57 void	creator_ras_erasecols(void *, int, int, int, long int);
58 void	creator_ras_eraserows(void *, int, int, long int);
59 void	creator_ras_fill(struct creator_softc *);
60 void	creator_ras_setfg(struct creator_softc *, int32_t);
61 int	creator_setcursor(struct creator_softc *, struct wsdisplay_cursor *);
62 int	creator_updatecursor(struct creator_softc *, u_int);
63 void	creator_curs_enable(struct creator_softc *, u_int);
64 
65 struct wsdisplay_accessops creator_accessops = {
66 	creator_ioctl,
67 	creator_mmap,
68 	NULL,	/* alloc_screen */
69 	NULL,	/* free_screen */
70 	NULL,	/* show_screen */
71 	NULL,	/* load_font */
72 	NULL,	/* scrollback */
73 	NULL,	/* getchar */
74 	NULL,	/* burner */
75 };
76 
77 struct cfdriver creator_cd = {
78 	NULL, "creator", DV_DULL
79 };
80 
81 struct cfattach creator_ca = {
82 	sizeof(struct creator_softc), creator_match, creator_attach
83 };
84 
85 int
86 creator_match(parent, match, aux)
87 	struct device *parent;
88 	void *match, *aux;
89 {
90 	struct mainbus_attach_args *ma = aux;
91 
92 	if (strcmp(ma->ma_name, "SUNW,ffb") == 0 ||
93 	    strcmp(ma->ma_name, "SUNW,afb") == 0)
94 		return (1);
95 	return (0);
96 }
97 
98 void
99 creator_attach(parent, self, aux)
100 	struct device *parent, *self;
101 	void *aux;
102 {
103 	struct creator_softc *sc = (struct creator_softc *)self;
104 	struct mainbus_attach_args *ma = aux;
105 	extern int fbnode;
106 	int i, nregs;
107 	char *model;
108 	int btype;
109 
110 	sc->sc_bt = ma->ma_bustag;
111 
112 	nregs = min(ma->ma_nreg, FFB_NREGS);
113 
114 	if (nregs <= FFB_REG_DFB24) {
115 		printf(": no dfb24 regs found\n");
116 		return;
117 	}
118 
119 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DFB24].ur_paddr,
120 	    ma->ma_reg[FFB_REG_DFB24].ur_len, BUS_SPACE_MAP_LINEAR,
121 	    &sc->sc_pixel_h)) {
122 		printf(": failed to map dfb24\n");
123 		return;
124 	}
125 
126 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_FBC].ur_paddr,
127 	    ma->ma_reg[FFB_REG_FBC].ur_len, 0, &sc->sc_fbc_h)) {
128 		printf(": failed to map fbc\n");
129 		goto unmap_dfb24;
130 	}
131 
132 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DAC].ur_paddr,
133 	    ma->ma_reg[FFB_REG_DAC].ur_len, 0, &sc->sc_dac_h)) {
134 		printf(": failed to map dac\n");
135 		goto unmap_fbc;
136 	}
137 
138 	for (i = 0; i < nregs; i++) {
139 		sc->sc_addrs[i] = ma->ma_reg[i].ur_paddr;
140 		sc->sc_sizes[i] = ma->ma_reg[i].ur_len;
141 	}
142 	sc->sc_nreg = nregs;
143 
144 	sc->sc_console = (fbnode == ma->ma_node);
145 	sc->sc_node = ma->ma_node;
146 
147 	if (strcmp(ma->ma_name, "SUNW,afb") == 0)
148 		sc->sc_type = FFB_AFB;
149 
150 	/*
151 	 * Prom reports only the length of the fcode header, we need
152 	 * the whole thing.
153 	 */
154 	sc->sc_sizes[0] = 0x00400000;
155 
156 	if (sc->sc_type == FFB_CREATOR) {
157 		btype = getpropint(sc->sc_node, "board_type", 0);
158 		if ((btype & 7) == 3)
159 			printf(": Creator3D");
160 		else
161 			printf(": Creator");
162 	} else
163 		printf(": Elite3D");
164 
165 	model = getpropstring(sc->sc_node, "model");
166 	if (model == NULL || strlen(model) == 0)
167 		model = "unknown";
168 
169 	DAC_WRITE(sc, FFB_DAC_TYPE, DAC_TYPE_GETREV);
170 	sc->sc_dacrev = DAC_READ(sc, FFB_DAC_VALUE) >> 28;
171 
172 	printf(", model %s, dac %u\n", model, sc->sc_dacrev);
173 
174 	if (sc->sc_type == FFB_AFB)
175 		sc->sc_dacrev = 10;
176 
177 	fb_setsize(&sc->sc_sunfb, 32, 1152, 900, sc->sc_node, 0);
178 	/* linesize has a fixed value, compensate */
179 	sc->sc_sunfb.sf_linebytes = 8192;
180 	sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height * 8192;
181 
182 	sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bt,
183 	    sc->sc_pixel_h);
184 	sc->sc_sunfb.sf_ro.ri_hw = sc;
185 	fbwscons_init(&sc->sc_sunfb, 0, sc->sc_console);
186 
187 	if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CREATOR_CFFLAG_NOACCEL)
188 	    == 0) {
189 		sc->sc_sunfb.sf_ro.ri_ops.eraserows = creator_ras_eraserows;
190 		sc->sc_sunfb.sf_ro.ri_ops.erasecols = creator_ras_erasecols;
191 		sc->sc_sunfb.sf_ro.ri_ops.copyrows = creator_ras_copyrows;
192 		creator_ras_init(sc);
193 	}
194 
195 	if (sc->sc_console)
196 		fbwscons_console_init(&sc->sc_sunfb, -1);
197 
198 	fbwscons_attach(&sc->sc_sunfb, &creator_accessops, sc->sc_console);
199 	return;
200 
201 unmap_fbc:
202 	bus_space_unmap(sc->sc_bt, sc->sc_fbc_h,
203 	    ma->ma_reg[FFB_REG_FBC].ur_len);
204 unmap_dfb24:
205 	bus_space_unmap(sc->sc_bt, sc->sc_pixel_h,
206 	    ma->ma_reg[FFB_REG_DFB24].ur_len);
207 }
208 
209 int
210 creator_ioctl(v, cmd, data, flags, p)
211 	void *v;
212 	u_long cmd;
213 	caddr_t data;
214 	int flags;
215 	struct proc *p;
216 {
217 	struct creator_softc *sc = v;
218 	struct wsdisplay_cursor *curs;
219 	struct wsdisplay_fbinfo *wdf;
220 	struct wsdisplay_curpos *pos;
221 	u_char r[2], g[2], b[2];
222 	int error;
223 
224 	switch (cmd) {
225 	case WSDISPLAYIO_GTYPE:
226 		*(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
227 		break;
228 	case WSDISPLAYIO_SMODE:
229 		sc->sc_mode = *(u_int *)data;
230 		break;
231 	case WSDISPLAYIO_GINFO:
232 		wdf = (void *)data;
233 		wdf->height = sc->sc_sunfb.sf_height;
234 		wdf->width  = sc->sc_sunfb.sf_width;
235 		wdf->depth  = 32;
236 		wdf->cmsize = 0;
237 		break;
238 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
239 		*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
240 		break;
241 	case WSDISPLAYIO_LINEBYTES:
242 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
243 		break;
244 	case WSDISPLAYIO_GCURSOR:
245 		curs = (struct wsdisplay_cursor *)data;
246 		if (curs->which & WSDISPLAY_CURSOR_DOCUR)
247 			curs->enable = sc->sc_curs_enabled;
248 		if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
249 			curs->pos.x = sc->sc_curs_pos.x;
250 			curs->pos.y = sc->sc_curs_pos.y;
251 		}
252 		if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
253 			curs->hot.x = sc->sc_curs_hot.x;
254 			curs->hot.y = sc->sc_curs_hot.y;
255 		}
256 		if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
257 			curs->cmap.index = 0;
258 			curs->cmap.count = 2;
259 			r[0] = sc->sc_curs_fg >> 0;
260 			g[0] = sc->sc_curs_fg >> 8;
261 			b[0] = sc->sc_curs_fg >> 16;
262 			r[1] = sc->sc_curs_bg >> 0;
263 			g[1] = sc->sc_curs_bg >> 8;
264 			b[1] = sc->sc_curs_bg >> 16;
265 			error = copyout(r, curs->cmap.red, sizeof(r));
266 			if (error)
267 				return (error);
268 			error = copyout(g, curs->cmap.green, sizeof(g));
269 			if (error)
270 				return (error);
271 			error = copyout(b, curs->cmap.blue, sizeof(b));
272 			if (error)
273 				return (error);
274 		}
275 		if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
276 			size_t l;
277 
278 			curs->size.x = sc->sc_curs_size.x;
279 			curs->size.y = sc->sc_curs_size.y;
280 			l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
281 			error = copyout(sc->sc_curs_image, curs->image, l);
282 			if (error)
283 				return (error);
284 			error = copyout(sc->sc_curs_mask, curs->mask, l);
285 			if (error)
286 				return (error);
287 		}
288 		break;
289 	case WSDISPLAYIO_SCURPOS:
290 		pos = (struct wsdisplay_curpos *)data;
291 		sc->sc_curs_pos.x = pos->x;
292 		sc->sc_curs_pos.y = pos->y;
293 		creator_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
294 		break;
295 	case WSDISPLAYIO_GCURPOS:
296 		pos = (struct wsdisplay_curpos *)data;
297 		pos->x = sc->sc_curs_pos.x;
298 		pos->y = sc->sc_curs_pos.y;
299 		break;
300 	case WSDISPLAYIO_SCURSOR:
301 		curs = (struct wsdisplay_cursor *)data;
302 		return (creator_setcursor(sc, curs));
303 	case WSDISPLAYIO_GCURMAX:
304 		pos = (struct wsdisplay_curpos *)data;
305 		pos->x = CREATOR_CURS_MAX;
306 		pos->y = CREATOR_CURS_MAX;
307 		break;
308 	case WSDISPLAYIO_SVIDEO:
309 	case WSDISPLAYIO_GVIDEO:
310 		break;
311 
312 	case WSDISPLAYIO_GETCMAP:
313 	case WSDISPLAYIO_PUTCMAP:
314 	default:
315 		return -1; /* not supported yet */
316         }
317 
318 	return (0);
319 }
320 
321 int
322 creator_setcursor(struct creator_softc *sc, struct wsdisplay_cursor *curs)
323 {
324 	u_int8_t r[2], g[2], b[2], image[128], mask[128];
325 	int error;
326 	size_t imcount;
327 
328 	/*
329 	 * Do stuff that can generate errors first, then we'll blast it
330 	 * all at once.
331 	 */
332 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
333 		if (curs->cmap.count < 2)
334 			return (EINVAL);
335 		error = copyin(curs->cmap.red, r, sizeof(r));
336 		if (error)
337 			return (error);
338 		error = copyin(curs->cmap.green, g, sizeof(g));
339 		if (error)
340 			return (error);
341 		error = copyin(curs->cmap.blue, b, sizeof(b));
342 		if (error)
343 			return (error);
344 	}
345 
346 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
347 		if (curs->size.x > CREATOR_CURS_MAX ||
348 		    curs->size.y > CREATOR_CURS_MAX)
349 			return (EINVAL);
350 		imcount = (curs->size.x * curs->size.y) / NBBY;
351 		error = copyin(curs->image, image, imcount);
352 		if (error)
353 			return (error);
354 		error = copyin(curs->mask, mask, imcount);
355 		if (error)
356 			return (error);
357 	}
358 
359 	/*
360 	 * Ok, everything is in kernel space and sane, update state.
361 	 */
362 
363 	if (curs->which & WSDISPLAY_CURSOR_DOCUR)
364 		sc->sc_curs_enabled = curs->enable;
365 	if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
366 		sc->sc_curs_pos.x = curs->pos.x;
367 		sc->sc_curs_pos.y = curs->pos.y;
368 	}
369 	if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
370 		sc->sc_curs_hot.x = curs->hot.x;
371 		sc->sc_curs_hot.y = curs->hot.y;
372 	}
373 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
374 		sc->sc_curs_fg = ((r[0] << 0) | (g[0] << 8) | (b[0] << 16));
375 		sc->sc_curs_bg = ((r[1] << 0) | (g[1] << 8) | (b[1] << 16));
376 	}
377 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
378 		sc->sc_curs_size.x = curs->size.x;
379 		sc->sc_curs_size.y = curs->size.y;
380 		bcopy(image, sc->sc_curs_image, imcount);
381 		bcopy(mask, sc->sc_curs_mask, imcount);
382 	}
383 
384 	creator_updatecursor(sc, curs->which);
385 
386 	return (0);
387 }
388 
389 void
390 creator_curs_enable(struct creator_softc *sc, u_int ena)
391 {
392 	u_int32_t v;
393 
394 	DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSENAB);
395 	if (sc->sc_dacrev <= 2)
396 		v = ena ? 3 : 0;
397 	else
398 		v = ena ? 0 : 3;
399 	DAC_WRITE(sc, FFB_DAC_VALUE2, v);
400 }
401 
402 int
403 creator_updatecursor(struct creator_softc *sc, u_int which)
404 {
405 	creator_curs_enable(sc, 0);
406 
407 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
408 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSCMAP);
409 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_fg);
410 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_bg);
411 	}
412 
413 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
414 		u_int32_t x, y;
415 
416 		x = sc->sc_curs_pos.x + CREATOR_CURS_MAX - sc->sc_curs_hot.x;
417 		y = sc->sc_curs_pos.y + CREATOR_CURS_MAX - sc->sc_curs_hot.y;
418 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSPOS);
419 		DAC_WRITE(sc, FFB_DAC_VALUE2,
420 		    ((x & 0xffff) << 16) | (y & 0xffff));
421 	}
422 
423 	if (which & WSDISPLAY_CURSOR_DOCUR)
424 		creator_curs_enable(sc, sc->sc_curs_enabled);
425 
426 	return (0);
427 }
428 
429 const struct creator_mappings {
430 	bus_addr_t uoff;
431 	bus_addr_t poff;
432 	bus_size_t ulen;
433 } creator_map[] = {
434 	{ FFB_VOFF_SFB8R, FFB_POFF_SFB8R, FFB_VLEN_SFB8R },
435 	{ FFB_VOFF_SFB8G, FFB_POFF_SFB8G, FFB_VLEN_SFB8G },
436 	{ FFB_VOFF_SFB8B, FFB_POFF_SFB8B, FFB_VLEN_SFB8B },
437 	{ FFB_VOFF_SFB8X, FFB_POFF_SFB8X, FFB_VLEN_SFB8X },
438 	{ FFB_VOFF_SFB32, FFB_POFF_SFB32, FFB_VLEN_SFB32 },
439 	{ FFB_VOFF_SFB64, FFB_POFF_SFB64, FFB_VLEN_SFB64 },
440 	{ FFB_VOFF_FBC_REGS, FFB_POFF_FBC_REGS, FFB_VLEN_FBC_REGS },
441 	{ FFB_VOFF_BM_FBC_REGS, FFB_POFF_BM_FBC_REGS, FFB_VLEN_BM_FBC_REGS },
442 	{ FFB_VOFF_DFB8R, FFB_POFF_DFB8R, FFB_VLEN_DFB8R },
443 	{ FFB_VOFF_DFB8G, FFB_POFF_DFB8G, FFB_VLEN_DFB8G },
444 	{ FFB_VOFF_DFB8B, FFB_POFF_DFB8B, FFB_VLEN_DFB8B },
445 	{ FFB_VOFF_DFB8X, FFB_POFF_DFB8X, FFB_VLEN_DFB8X },
446 	{ FFB_VOFF_DFB24, FFB_POFF_DFB24, FFB_VLEN_DFB24 },
447 	{ FFB_VOFF_DFB32, FFB_POFF_DFB32, FFB_VLEN_DFB32 },
448 	{ FFB_VOFF_DFB422A, FFB_POFF_DFB422A, FFB_VLEN_DFB422A },
449 	{ FFB_VOFF_DFB422AD, FFB_POFF_DFB422AD, FFB_VLEN_DFB422AD },
450 	{ FFB_VOFF_DFB24B, FFB_POFF_DFB24B, FFB_VLEN_DFB24B },
451 	{ FFB_VOFF_DFB422B, FFB_POFF_DFB422B, FFB_VLEN_DFB422B },
452 	{ FFB_VOFF_DFB422BD, FFB_POFF_DFB422BD, FFB_VLEN_DFB422BD },
453 	{ FFB_VOFF_SFB16Z, FFB_POFF_SFB16Z, FFB_VLEN_SFB16Z },
454 	{ FFB_VOFF_SFB8Z, FFB_POFF_SFB8Z, FFB_VLEN_SFB8Z },
455 	{ FFB_VOFF_SFB422, FFB_POFF_SFB422, FFB_VLEN_SFB422 },
456 	{ FFB_VOFF_SFB422D, FFB_POFF_SFB422D, FFB_VLEN_SFB422D },
457 	{ FFB_VOFF_FBC_KREGS, FFB_POFF_FBC_KREGS, FFB_VLEN_FBC_KREGS },
458 	{ FFB_VOFF_DAC, FFB_POFF_DAC, FFB_VLEN_DAC },
459 	{ FFB_VOFF_PROM, FFB_POFF_PROM, FFB_VLEN_PROM },
460 	{ FFB_VOFF_EXP, FFB_POFF_EXP, FFB_VLEN_EXP },
461 };
462 #define	CREATOR_NMAPPINGS	(sizeof(creator_map)/sizeof(creator_map[0]))
463 
464 paddr_t
465 creator_mmap(vsc, off, prot)
466 	void *vsc;
467 	off_t off;
468 	int prot;
469 {
470 	paddr_t x;
471 	struct creator_softc *sc = vsc;
472 	int i;
473 
474 	switch (sc->sc_mode) {
475 	case WSDISPLAYIO_MODE_MAPPED:
476 		/* Turn virtual offset into physical offset */
477 		for (i = 0; i < CREATOR_NMAPPINGS; i++) {
478 			if (off >= creator_map[i].uoff &&
479 			    off < (creator_map[i].uoff + creator_map[i].ulen))
480 				break;
481 		}
482 		if (i == CREATOR_NMAPPINGS)
483 			break;
484 
485 		off -= creator_map[i].uoff;
486 		off += creator_map[i].poff;
487 		off += sc->sc_addrs[0];
488 
489 		/* Map based on physical offset */
490 		for (i = 0; i < sc->sc_nreg; i++) {
491 			/* Before this set? */
492 			if (off < sc->sc_addrs[i])
493 				continue;
494 			/* After this set? */
495 			if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
496 				continue;
497 
498 			x = bus_space_mmap(sc->sc_bt, 0, off, prot,
499 			    BUS_SPACE_MAP_LINEAR);
500 			return (x);
501 		}
502 		break;
503 	case WSDISPLAYIO_MODE_DUMBFB:
504 		if (sc->sc_nreg <= FFB_REG_DFB24)
505 			break;
506 		if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
507 			return (bus_space_mmap(sc->sc_bt,
508 			    sc->sc_addrs[FFB_REG_DFB24], off, prot,
509 			    BUS_SPACE_MAP_LINEAR));
510 		break;
511 	}
512 
513 	return (-1);
514 }
515 
516 void
517 creator_ras_fifo_wait(sc, n)
518 	struct creator_softc *sc;
519 	int n;
520 {
521 	int32_t cache = sc->sc_fifo_cache;
522 
523 	if (cache < n) {
524 		do {
525 			cache = FBC_READ(sc, FFB_FBC_UCSR);
526 			cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
527 		} while (cache < n);
528 	}
529 	sc->sc_fifo_cache = cache - n;
530 }
531 
532 void
533 creator_ras_wait(sc)
534 	struct creator_softc *sc;
535 {
536 	u_int32_t ucsr, r;
537 
538 	while (1) {
539 		ucsr = FBC_READ(sc, FFB_FBC_UCSR);
540 		if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
541 			break;
542 		r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
543 		if (r != 0)
544 			FBC_WRITE(sc, FFB_FBC_UCSR, r);
545 	}
546 }
547 
548 void
549 creator_ras_init(sc)
550 	struct creator_softc *sc;
551 {
552 	creator_ras_fifo_wait(sc, 7);
553 	FBC_WRITE(sc, FFB_FBC_PPC,
554 	    FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
555 	    FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
556 	FBC_WRITE(sc, FFB_FBC_FBC,
557 	    FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
558 	    FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
559 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
560 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
561 	FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
562 	FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
563 	sc->sc_fg_cache = 0;
564 	FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
565 	creator_ras_wait(sc);
566 }
567 
568 void
569 creator_ras_eraserows(cookie, row, n, attr)
570 	void *cookie;
571 	int row, n;
572 	long int attr;
573 {
574 	struct rasops_info *ri = cookie;
575 	struct creator_softc *sc = ri->ri_hw;
576 	int bg, fg;
577 
578 	if (row < 0) {
579 		n += row;
580 		row = 0;
581 	}
582 	if (row + n > ri->ri_rows)
583 		n = ri->ri_rows - row;
584 	if (n <= 0)
585 		return;
586 
587 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
588 	creator_ras_fill(sc);
589 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
590 	creator_ras_fifo_wait(sc, 4);
591 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
592 		FBC_WRITE(sc, FFB_FBC_BY, 0);
593 		FBC_WRITE(sc, FFB_FBC_BX, 0);
594 		FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
595 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
596 	} else {
597 		row *= ri->ri_font->fontheight;
598 		FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
599 		FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
600 		FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
601 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
602 	}
603 	creator_ras_wait(sc);
604 }
605 
606 void
607 creator_ras_erasecols(cookie, row, col, n, attr)
608 	void *cookie;
609 	int row, col, n;
610 	long int attr;
611 {
612 	struct rasops_info *ri = cookie;
613 	struct creator_softc *sc = ri->ri_hw;
614 	int fg, bg;
615 
616 	if ((row < 0) || (row >= ri->ri_rows))
617 		return;
618 	if (col < 0) {
619 		n += col;
620 		col = 0;
621 	}
622 	if (col + n > ri->ri_cols)
623 		n = ri->ri_cols - col;
624 	if (n <= 0)
625 		return;
626 	n *= ri->ri_font->fontwidth;
627 	col *= ri->ri_font->fontwidth;
628 	row *= ri->ri_font->fontheight;
629 
630 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
631 	creator_ras_fill(sc);
632 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
633 	creator_ras_fifo_wait(sc, 4);
634 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
635 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
636 	FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
637 	FBC_WRITE(sc, FFB_FBC_BW, n - 1);
638 	creator_ras_wait(sc);
639 }
640 
641 void
642 creator_ras_fill(sc)
643 	struct creator_softc *sc;
644 {
645 	creator_ras_fifo_wait(sc, 2);
646 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
647 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
648 	creator_ras_wait(sc);
649 }
650 
651 void
652 creator_ras_copyrows(cookie, src, dst, n)
653 	void *cookie;
654 	int src, dst, n;
655 {
656 	struct rasops_info *ri = cookie;
657 	struct creator_softc *sc = ri->ri_hw;
658 
659 	if (dst == src)
660 		return;
661 	if (src < 0) {
662 		n += src;
663 		src = 0;
664 	}
665 	if ((src + n) > ri->ri_rows)
666 		n = ri->ri_rows - src;
667 	if (dst < 0) {
668 		n += dst;
669 		dst = 0;
670 	}
671 	if ((dst + n) > ri->ri_rows)
672 		n = ri->ri_rows - dst;
673 	if (n <= 0)
674 		return;
675 	n *= ri->ri_font->fontheight;
676 	src *= ri->ri_font->fontheight;
677 	dst *= ri->ri_font->fontheight;
678 
679 	creator_ras_fifo_wait(sc, 8);
680 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
681 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
682 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
683 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
684 	FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
685 	FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
686 	FBC_WRITE(sc, FFB_FBC_BH, n);
687 	FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
688 	creator_ras_wait(sc);
689 }
690 
691 void
692 creator_ras_setfg(sc, fg)
693 	struct creator_softc *sc;
694 	int32_t fg;
695 {
696 	creator_ras_fifo_wait(sc, 1);
697 	if (fg == sc->sc_fg_cache)
698 		return;
699 	sc->sc_fg_cache = fg;
700 	FBC_WRITE(sc, FFB_FBC_FG, fg);
701 	creator_ras_wait(sc);
702 }
703