xref: /openbsd-src/sys/arch/sparc64/dev/creator.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: creator.c,v 1.42 2009/09/05 14:09:35 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 int	creator_ras_copyrows(void *, int, int, int);
57 int	creator_ras_erasecols(void *, int, int, int, long int);
58 int	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 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
231 			struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
232 			long attr;
233 
234 			if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags &
235 			    CREATOR_CFFLAG_NOACCEL) == 0)
236 				creator_ras_init(sc);
237 
238 			/* Clear screen. */
239 			ri->ri_ops.alloc_attr(ri,
240 			    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &attr);
241 			ri->ri_ops.eraserows(ri, 0, ri->ri_rows, attr);
242 		}
243 		break;
244 	case WSDISPLAYIO_GINFO:
245 		wdf = (void *)data;
246 		wdf->height = sc->sc_sunfb.sf_height;
247 		wdf->width  = sc->sc_sunfb.sf_width;
248 		wdf->depth  = 32;
249 		wdf->cmsize = 0;
250 		break;
251 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
252 		*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
253 		break;
254 	case WSDISPLAYIO_LINEBYTES:
255 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
256 		break;
257 	case WSDISPLAYIO_GCURSOR:
258 		curs = (struct wsdisplay_cursor *)data;
259 		if (curs->which & WSDISPLAY_CURSOR_DOCUR)
260 			curs->enable = sc->sc_curs_enabled;
261 		if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
262 			curs->pos.x = sc->sc_curs_pos.x;
263 			curs->pos.y = sc->sc_curs_pos.y;
264 		}
265 		if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
266 			curs->hot.x = sc->sc_curs_hot.x;
267 			curs->hot.y = sc->sc_curs_hot.y;
268 		}
269 		if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
270 			curs->cmap.index = 0;
271 			curs->cmap.count = 2;
272 			r[0] = sc->sc_curs_fg >> 0;
273 			g[0] = sc->sc_curs_fg >> 8;
274 			b[0] = sc->sc_curs_fg >> 16;
275 			r[1] = sc->sc_curs_bg >> 0;
276 			g[1] = sc->sc_curs_bg >> 8;
277 			b[1] = sc->sc_curs_bg >> 16;
278 			error = copyout(r, curs->cmap.red, sizeof(r));
279 			if (error)
280 				return (error);
281 			error = copyout(g, curs->cmap.green, sizeof(g));
282 			if (error)
283 				return (error);
284 			error = copyout(b, curs->cmap.blue, sizeof(b));
285 			if (error)
286 				return (error);
287 		}
288 		if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
289 			size_t l;
290 
291 			curs->size.x = sc->sc_curs_size.x;
292 			curs->size.y = sc->sc_curs_size.y;
293 			l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
294 			error = copyout(sc->sc_curs_image, curs->image, l);
295 			if (error)
296 				return (error);
297 			error = copyout(sc->sc_curs_mask, curs->mask, l);
298 			if (error)
299 				return (error);
300 		}
301 		break;
302 	case WSDISPLAYIO_SCURPOS:
303 		pos = (struct wsdisplay_curpos *)data;
304 		sc->sc_curs_pos.x = pos->x;
305 		sc->sc_curs_pos.y = pos->y;
306 		creator_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
307 		break;
308 	case WSDISPLAYIO_GCURPOS:
309 		pos = (struct wsdisplay_curpos *)data;
310 		pos->x = sc->sc_curs_pos.x;
311 		pos->y = sc->sc_curs_pos.y;
312 		break;
313 	case WSDISPLAYIO_SCURSOR:
314 		curs = (struct wsdisplay_cursor *)data;
315 		return (creator_setcursor(sc, curs));
316 	case WSDISPLAYIO_GCURMAX:
317 		pos = (struct wsdisplay_curpos *)data;
318 		pos->x = CREATOR_CURS_MAX;
319 		pos->y = CREATOR_CURS_MAX;
320 		break;
321 	case WSDISPLAYIO_SVIDEO:
322 	case WSDISPLAYIO_GVIDEO:
323 		break;
324 
325 	case WSDISPLAYIO_GETCMAP:
326 	case WSDISPLAYIO_PUTCMAP:
327 	default:
328 		return -1; /* not supported yet */
329         }
330 
331 	return (0);
332 }
333 
334 int
335 creator_setcursor(struct creator_softc *sc, struct wsdisplay_cursor *curs)
336 {
337 	u_int8_t r[2], g[2], b[2], image[128], mask[128];
338 	int error;
339 	size_t imcount;
340 
341 	/*
342 	 * Do stuff that can generate errors first, then we'll blast it
343 	 * all at once.
344 	 */
345 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
346 		if (curs->cmap.count < 2)
347 			return (EINVAL);
348 		error = copyin(curs->cmap.red, r, sizeof(r));
349 		if (error)
350 			return (error);
351 		error = copyin(curs->cmap.green, g, sizeof(g));
352 		if (error)
353 			return (error);
354 		error = copyin(curs->cmap.blue, b, sizeof(b));
355 		if (error)
356 			return (error);
357 	}
358 
359 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
360 		if (curs->size.x > CREATOR_CURS_MAX ||
361 		    curs->size.y > CREATOR_CURS_MAX)
362 			return (EINVAL);
363 		imcount = (curs->size.x * curs->size.y) / NBBY;
364 		error = copyin(curs->image, image, imcount);
365 		if (error)
366 			return (error);
367 		error = copyin(curs->mask, mask, imcount);
368 		if (error)
369 			return (error);
370 	}
371 
372 	/*
373 	 * Ok, everything is in kernel space and sane, update state.
374 	 */
375 
376 	if (curs->which & WSDISPLAY_CURSOR_DOCUR)
377 		sc->sc_curs_enabled = curs->enable;
378 	if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
379 		sc->sc_curs_pos.x = curs->pos.x;
380 		sc->sc_curs_pos.y = curs->pos.y;
381 	}
382 	if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
383 		sc->sc_curs_hot.x = curs->hot.x;
384 		sc->sc_curs_hot.y = curs->hot.y;
385 	}
386 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
387 		sc->sc_curs_fg = ((r[0] << 0) | (g[0] << 8) | (b[0] << 16));
388 		sc->sc_curs_bg = ((r[1] << 0) | (g[1] << 8) | (b[1] << 16));
389 	}
390 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
391 		sc->sc_curs_size.x = curs->size.x;
392 		sc->sc_curs_size.y = curs->size.y;
393 		bcopy(image, sc->sc_curs_image, imcount);
394 		bcopy(mask, sc->sc_curs_mask, imcount);
395 	}
396 
397 	creator_updatecursor(sc, curs->which);
398 
399 	return (0);
400 }
401 
402 void
403 creator_curs_enable(struct creator_softc *sc, u_int ena)
404 {
405 	u_int32_t v;
406 
407 	DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSENAB);
408 	if (sc->sc_dacrev <= 2)
409 		v = ena ? 3 : 0;
410 	else
411 		v = ena ? 0 : 3;
412 	DAC_WRITE(sc, FFB_DAC_VALUE2, v);
413 }
414 
415 int
416 creator_updatecursor(struct creator_softc *sc, u_int which)
417 {
418 	creator_curs_enable(sc, 0);
419 
420 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
421 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSCMAP);
422 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_fg);
423 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_bg);
424 	}
425 
426 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
427 		u_int32_t x, y;
428 
429 		x = sc->sc_curs_pos.x + CREATOR_CURS_MAX - sc->sc_curs_hot.x;
430 		y = sc->sc_curs_pos.y + CREATOR_CURS_MAX - sc->sc_curs_hot.y;
431 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSPOS);
432 		DAC_WRITE(sc, FFB_DAC_VALUE2,
433 		    ((x & 0xffff) << 16) | (y & 0xffff));
434 	}
435 
436 	if (which & WSDISPLAY_CURSOR_DOCUR)
437 		creator_curs_enable(sc, sc->sc_curs_enabled);
438 
439 	return (0);
440 }
441 
442 const struct creator_mappings {
443 	bus_addr_t uoff;
444 	bus_addr_t poff;
445 	bus_size_t ulen;
446 } creator_map[] = {
447 	{ FFB_VOFF_SFB8R, FFB_POFF_SFB8R, FFB_VLEN_SFB8R },
448 	{ FFB_VOFF_SFB8G, FFB_POFF_SFB8G, FFB_VLEN_SFB8G },
449 	{ FFB_VOFF_SFB8B, FFB_POFF_SFB8B, FFB_VLEN_SFB8B },
450 	{ FFB_VOFF_SFB8X, FFB_POFF_SFB8X, FFB_VLEN_SFB8X },
451 	{ FFB_VOFF_SFB32, FFB_POFF_SFB32, FFB_VLEN_SFB32 },
452 	{ FFB_VOFF_SFB64, FFB_POFF_SFB64, FFB_VLEN_SFB64 },
453 	{ FFB_VOFF_FBC_REGS, FFB_POFF_FBC_REGS, FFB_VLEN_FBC_REGS },
454 	{ FFB_VOFF_BM_FBC_REGS, FFB_POFF_BM_FBC_REGS, FFB_VLEN_BM_FBC_REGS },
455 	{ FFB_VOFF_DFB8R, FFB_POFF_DFB8R, FFB_VLEN_DFB8R },
456 	{ FFB_VOFF_DFB8G, FFB_POFF_DFB8G, FFB_VLEN_DFB8G },
457 	{ FFB_VOFF_DFB8B, FFB_POFF_DFB8B, FFB_VLEN_DFB8B },
458 	{ FFB_VOFF_DFB8X, FFB_POFF_DFB8X, FFB_VLEN_DFB8X },
459 	{ FFB_VOFF_DFB24, FFB_POFF_DFB24, FFB_VLEN_DFB24 },
460 	{ FFB_VOFF_DFB32, FFB_POFF_DFB32, FFB_VLEN_DFB32 },
461 	{ FFB_VOFF_DFB422A, FFB_POFF_DFB422A, FFB_VLEN_DFB422A },
462 	{ FFB_VOFF_DFB422AD, FFB_POFF_DFB422AD, FFB_VLEN_DFB422AD },
463 	{ FFB_VOFF_DFB24B, FFB_POFF_DFB24B, FFB_VLEN_DFB24B },
464 	{ FFB_VOFF_DFB422B, FFB_POFF_DFB422B, FFB_VLEN_DFB422B },
465 	{ FFB_VOFF_DFB422BD, FFB_POFF_DFB422BD, FFB_VLEN_DFB422BD },
466 	{ FFB_VOFF_SFB16Z, FFB_POFF_SFB16Z, FFB_VLEN_SFB16Z },
467 	{ FFB_VOFF_SFB8Z, FFB_POFF_SFB8Z, FFB_VLEN_SFB8Z },
468 	{ FFB_VOFF_SFB422, FFB_POFF_SFB422, FFB_VLEN_SFB422 },
469 	{ FFB_VOFF_SFB422D, FFB_POFF_SFB422D, FFB_VLEN_SFB422D },
470 	{ FFB_VOFF_FBC_KREGS, FFB_POFF_FBC_KREGS, FFB_VLEN_FBC_KREGS },
471 	{ FFB_VOFF_DAC, FFB_POFF_DAC, FFB_VLEN_DAC },
472 	{ FFB_VOFF_PROM, FFB_POFF_PROM, FFB_VLEN_PROM },
473 	{ FFB_VOFF_EXP, FFB_POFF_EXP, FFB_VLEN_EXP },
474 };
475 #define	CREATOR_NMAPPINGS	(sizeof(creator_map)/sizeof(creator_map[0]))
476 
477 paddr_t
478 creator_mmap(vsc, off, prot)
479 	void *vsc;
480 	off_t off;
481 	int prot;
482 {
483 	paddr_t x;
484 	struct creator_softc *sc = vsc;
485 	int i;
486 
487 	switch (sc->sc_mode) {
488 	case WSDISPLAYIO_MODE_MAPPED:
489 		/* Turn virtual offset into physical offset */
490 		for (i = 0; i < CREATOR_NMAPPINGS; i++) {
491 			if (off >= creator_map[i].uoff &&
492 			    off < (creator_map[i].uoff + creator_map[i].ulen))
493 				break;
494 		}
495 		if (i == CREATOR_NMAPPINGS)
496 			break;
497 
498 		off -= creator_map[i].uoff;
499 		off += creator_map[i].poff;
500 		off += sc->sc_addrs[0];
501 
502 		/* Map based on physical offset */
503 		for (i = 0; i < sc->sc_nreg; i++) {
504 			/* Before this set? */
505 			if (off < sc->sc_addrs[i])
506 				continue;
507 			/* After this set? */
508 			if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
509 				continue;
510 
511 			x = bus_space_mmap(sc->sc_bt, 0, off, prot,
512 			    BUS_SPACE_MAP_LINEAR);
513 			return (x);
514 		}
515 		break;
516 	case WSDISPLAYIO_MODE_DUMBFB:
517 		if (sc->sc_nreg <= FFB_REG_DFB24)
518 			break;
519 		if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
520 			return (bus_space_mmap(sc->sc_bt,
521 			    sc->sc_addrs[FFB_REG_DFB24], off, prot,
522 			    BUS_SPACE_MAP_LINEAR));
523 		break;
524 	}
525 
526 	return (-1);
527 }
528 
529 void
530 creator_ras_fifo_wait(sc, n)
531 	struct creator_softc *sc;
532 	int n;
533 {
534 	int32_t cache = sc->sc_fifo_cache;
535 
536 	if (cache < n) {
537 		do {
538 			cache = FBC_READ(sc, FFB_FBC_UCSR);
539 			cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
540 		} while (cache < n);
541 	}
542 	sc->sc_fifo_cache = cache - n;
543 }
544 
545 void
546 creator_ras_wait(sc)
547 	struct creator_softc *sc;
548 {
549 	u_int32_t ucsr, r;
550 
551 	while (1) {
552 		ucsr = FBC_READ(sc, FFB_FBC_UCSR);
553 		if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
554 			break;
555 		r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
556 		if (r != 0)
557 			FBC_WRITE(sc, FFB_FBC_UCSR, r);
558 	}
559 }
560 
561 void
562 creator_ras_init(sc)
563 	struct creator_softc *sc;
564 {
565 	creator_ras_fifo_wait(sc, 7);
566 	FBC_WRITE(sc, FFB_FBC_PPC,
567 	    FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
568 	    FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
569 	FBC_WRITE(sc, FFB_FBC_FBC,
570 	    FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
571 	    FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
572 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
573 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
574 	FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
575 	FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
576 	sc->sc_fg_cache = 0;
577 	FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
578 	creator_ras_wait(sc);
579 }
580 
581 int
582 creator_ras_eraserows(cookie, row, n, attr)
583 	void *cookie;
584 	int row, n;
585 	long int attr;
586 {
587 	struct rasops_info *ri = cookie;
588 	struct creator_softc *sc = ri->ri_hw;
589 	int bg, fg;
590 
591 	if (row < 0) {
592 		n += row;
593 		row = 0;
594 	}
595 	if (row + n > ri->ri_rows)
596 		n = ri->ri_rows - row;
597 	if (n <= 0)
598 		return 0;
599 
600 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
601 	creator_ras_fill(sc);
602 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
603 	creator_ras_fifo_wait(sc, 4);
604 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
605 		FBC_WRITE(sc, FFB_FBC_BY, 0);
606 		FBC_WRITE(sc, FFB_FBC_BX, 0);
607 		FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
608 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
609 	} else {
610 		row *= ri->ri_font->fontheight;
611 		FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
612 		FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
613 		FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
614 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
615 	}
616 	creator_ras_wait(sc);
617 
618 	return 0;
619 }
620 
621 int
622 creator_ras_erasecols(cookie, row, col, n, attr)
623 	void *cookie;
624 	int row, col, n;
625 	long int attr;
626 {
627 	struct rasops_info *ri = cookie;
628 	struct creator_softc *sc = ri->ri_hw;
629 	int fg, bg;
630 
631 	if ((row < 0) || (row >= ri->ri_rows))
632 		return 0;
633 	if (col < 0) {
634 		n += col;
635 		col = 0;
636 	}
637 	if (col + n > ri->ri_cols)
638 		n = ri->ri_cols - col;
639 	if (n <= 0)
640 		return 0;
641 	n *= ri->ri_font->fontwidth;
642 	col *= ri->ri_font->fontwidth;
643 	row *= ri->ri_font->fontheight;
644 
645 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
646 	creator_ras_fill(sc);
647 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
648 	creator_ras_fifo_wait(sc, 4);
649 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
650 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
651 	FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
652 	FBC_WRITE(sc, FFB_FBC_BW, n - 1);
653 	creator_ras_wait(sc);
654 
655 	return 0;
656 }
657 
658 void
659 creator_ras_fill(sc)
660 	struct creator_softc *sc;
661 {
662 	creator_ras_fifo_wait(sc, 2);
663 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
664 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
665 	creator_ras_wait(sc);
666 }
667 
668 int
669 creator_ras_copyrows(cookie, src, dst, n)
670 	void *cookie;
671 	int src, dst, n;
672 {
673 	struct rasops_info *ri = cookie;
674 	struct creator_softc *sc = ri->ri_hw;
675 
676 	if (dst == src)
677 		return 0;
678 	if (src < 0) {
679 		n += src;
680 		src = 0;
681 	}
682 	if ((src + n) > ri->ri_rows)
683 		n = ri->ri_rows - src;
684 	if (dst < 0) {
685 		n += dst;
686 		dst = 0;
687 	}
688 	if ((dst + n) > ri->ri_rows)
689 		n = ri->ri_rows - dst;
690 	if (n <= 0)
691 		return 0;
692 	n *= ri->ri_font->fontheight;
693 	src *= ri->ri_font->fontheight;
694 	dst *= ri->ri_font->fontheight;
695 
696 	creator_ras_fifo_wait(sc, 8);
697 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
698 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
699 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
700 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
701 	FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
702 	FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
703 	FBC_WRITE(sc, FFB_FBC_BH, n);
704 	FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
705 	creator_ras_wait(sc);
706 
707 	return 0;
708 }
709 
710 void
711 creator_ras_setfg(sc, fg)
712 	struct creator_softc *sc;
713 	int32_t fg;
714 {
715 	creator_ras_fifo_wait(sc, 1);
716 	if (fg == sc->sc_fg_cache)
717 		return;
718 	sc->sc_fg_cache = fg;
719 	FBC_WRITE(sc, FFB_FBC_FG, fg);
720 	creator_ras_wait(sc);
721 }
722