xref: /openbsd-src/sys/arch/sparc64/dev/creator.c (revision 898184e3e61f9129feb5978fad5a8c6865f00b92)
1 /*	$OpenBSD: creator.c,v 1.45 2009/12/16 11:06:17 jasper 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/malloc.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 
54 void	creator_ras_fifo_wait(struct creator_softc *, int);
55 void	creator_ras_wait(struct creator_softc *);
56 void	creator_ras_init(struct creator_softc *);
57 int	creator_ras_copyrows(void *, int, int, int);
58 int	creator_ras_erasecols(void *, int, int, int, long int);
59 int	creator_ras_eraserows(void *, int, int, long int);
60 void	creator_ras_fill(struct creator_softc *);
61 void	creator_ras_setfg(struct creator_softc *, int32_t);
62 
63 int	creator_setcursor(struct creator_softc *, struct wsdisplay_cursor *);
64 int	creator_updatecursor(struct creator_softc *, u_int);
65 void	creator_curs_enable(struct creator_softc *, u_int);
66 
67 #ifndef SMALL_KERNEL
68 void	creator_load_firmware(void *);
69 #endif /* SMALL_KERNEL */
70 void	creator_load_sram(struct creator_softc *, u_int32_t *, u_int32_t);
71 
72 struct wsdisplay_accessops creator_accessops = {
73 	creator_ioctl,
74 	creator_mmap,
75 	NULL,	/* alloc_screen */
76 	NULL,	/* free_screen */
77 	NULL,	/* show_screen */
78 	NULL,	/* load_font */
79 	NULL,	/* scrollback */
80 	NULL,	/* getchar */
81 	NULL,	/* burner */
82 };
83 
84 struct cfdriver creator_cd = {
85 	NULL, "creator", DV_DULL
86 };
87 
88 struct cfattach creator_ca = {
89 	sizeof(struct creator_softc), creator_match, creator_attach
90 };
91 
92 int
93 creator_match(parent, match, aux)
94 	struct device *parent;
95 	void *match, *aux;
96 {
97 	struct mainbus_attach_args *ma = aux;
98 
99 	if (strcmp(ma->ma_name, "SUNW,ffb") == 0 ||
100 	    strcmp(ma->ma_name, "SUNW,afb") == 0)
101 		return (1);
102 	return (0);
103 }
104 
105 void
106 creator_attach(parent, self, aux)
107 	struct device *parent, *self;
108 	void *aux;
109 {
110 	struct creator_softc *sc = (struct creator_softc *)self;
111 	struct mainbus_attach_args *ma = aux;
112 	extern int fbnode;
113 	int i, nregs;
114 	char *model;
115 	int btype;
116 
117 	sc->sc_bt = ma->ma_bustag;
118 
119 	nregs = min(ma->ma_nreg, FFB_NREGS);
120 
121 	if (nregs <= FFB_REG_DFB24) {
122 		printf(": no dfb24 regs found\n");
123 		return;
124 	}
125 
126 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DFB24].ur_paddr,
127 	    ma->ma_reg[FFB_REG_DFB24].ur_len, BUS_SPACE_MAP_LINEAR,
128 	    &sc->sc_pixel_h)) {
129 		printf(": failed to map dfb24\n");
130 		return;
131 	}
132 
133 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_FBC].ur_paddr,
134 	    ma->ma_reg[FFB_REG_FBC].ur_len, 0, &sc->sc_fbc_h)) {
135 		printf(": failed to map fbc\n");
136 		goto unmap_dfb24;
137 	}
138 
139 	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DAC].ur_paddr,
140 	    ma->ma_reg[FFB_REG_DAC].ur_len, 0, &sc->sc_dac_h)) {
141 		printf(": failed to map dac\n");
142 		goto unmap_fbc;
143 	}
144 
145 	for (i = 0; i < nregs; i++) {
146 		sc->sc_addrs[i] = ma->ma_reg[i].ur_paddr;
147 		sc->sc_sizes[i] = ma->ma_reg[i].ur_len;
148 	}
149 	sc->sc_nreg = nregs;
150 
151 	sc->sc_console = (fbnode == ma->ma_node);
152 	sc->sc_node = ma->ma_node;
153 
154 	if (strcmp(ma->ma_name, "SUNW,afb") == 0)
155 		sc->sc_type = FFB_AFB;
156 
157 	/*
158 	 * Prom reports only the length of the fcode header, we need
159 	 * the whole thing.
160 	 */
161 	sc->sc_sizes[0] = 0x00400000;
162 
163 	if (sc->sc_type == FFB_CREATOR) {
164 		btype = getpropint(sc->sc_node, "board_type", 0);
165 		if ((btype & 7) == 3)
166 			printf(": Creator3D");
167 		else
168 			printf(": Creator");
169 	} else
170 		printf(": Elite3D");
171 
172 	model = getpropstring(sc->sc_node, "model");
173 	if (model == NULL || strlen(model) == 0)
174 		model = "unknown";
175 
176 	DAC_WRITE(sc, FFB_DAC_TYPE, DAC_TYPE_GETREV);
177 	sc->sc_dacrev = DAC_READ(sc, FFB_DAC_VALUE) >> 28;
178 
179 	printf(", model %s, dac %u\n", model, sc->sc_dacrev);
180 
181 	if (sc->sc_type == FFB_AFB)
182 		sc->sc_dacrev = 10;
183 
184 	fb_setsize(&sc->sc_sunfb, 32, 1152, 900, sc->sc_node, 0);
185 	/* linesize has a fixed value, compensate */
186 	sc->sc_sunfb.sf_linebytes = 8192;
187 	sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height * 8192;
188 
189 	sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bt,
190 	    sc->sc_pixel_h);
191 	sc->sc_sunfb.sf_ro.ri_hw = sc;
192 	fbwscons_init(&sc->sc_sunfb, 0, sc->sc_console);
193 
194 	if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CREATOR_CFFLAG_NOACCEL)
195 	    == 0) {
196 		sc->sc_sunfb.sf_ro.ri_ops.eraserows = creator_ras_eraserows;
197 		sc->sc_sunfb.sf_ro.ri_ops.erasecols = creator_ras_erasecols;
198 		sc->sc_sunfb.sf_ro.ri_ops.copyrows = creator_ras_copyrows;
199 		creator_ras_init(sc);
200 
201 #ifndef SMALL_KERNEL
202 		/*
203 		 * Elite3D cards need a firmware for accelerated X to
204 		 * work.  Console framebuffer acceleration will work
205 		 * without it though, so doing this late should be
206 		 * fine.
207 		 */
208 		if (sc->sc_type == FFB_AFB)
209 			mountroothook_establish(creator_load_firmware, sc);
210 #endif /* SMALL_KERNEL */
211 	}
212 
213 	if (sc->sc_console)
214 		fbwscons_console_init(&sc->sc_sunfb, -1);
215 
216 	fbwscons_attach(&sc->sc_sunfb, &creator_accessops, sc->sc_console);
217 	return;
218 
219 unmap_fbc:
220 	bus_space_unmap(sc->sc_bt, sc->sc_fbc_h,
221 	    ma->ma_reg[FFB_REG_FBC].ur_len);
222 unmap_dfb24:
223 	bus_space_unmap(sc->sc_bt, sc->sc_pixel_h,
224 	    ma->ma_reg[FFB_REG_DFB24].ur_len);
225 }
226 
227 int
228 creator_ioctl(v, cmd, data, flags, p)
229 	void *v;
230 	u_long cmd;
231 	caddr_t data;
232 	int flags;
233 	struct proc *p;
234 {
235 	struct creator_softc *sc = v;
236 	struct wsdisplay_cursor *curs;
237 	struct wsdisplay_fbinfo *wdf;
238 	struct wsdisplay_curpos *pos;
239 	u_char r[2], g[2], b[2];
240 	int error;
241 
242 	switch (cmd) {
243 	case WSDISPLAYIO_GTYPE:
244 		*(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
245 		break;
246 	case WSDISPLAYIO_SMODE:
247 		sc->sc_mode = *(u_int *)data;
248 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
249 			struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
250 			long attr;
251 
252 			if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags &
253 			    CREATOR_CFFLAG_NOACCEL) == 0)
254 				creator_ras_init(sc);
255 
256 			/* Clear screen. */
257 			ri->ri_ops.alloc_attr(ri,
258 			    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &attr);
259 			ri->ri_ops.eraserows(ri, 0, ri->ri_rows, attr);
260 		}
261 		break;
262 	case WSDISPLAYIO_GINFO:
263 		wdf = (void *)data;
264 		wdf->height = sc->sc_sunfb.sf_height;
265 		wdf->width  = sc->sc_sunfb.sf_width;
266 		wdf->depth  = 32;
267 		wdf->cmsize = 0;
268 		break;
269 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
270 		*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
271 		break;
272 	case WSDISPLAYIO_LINEBYTES:
273 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
274 		break;
275 	case WSDISPLAYIO_GCURSOR:
276 		curs = (struct wsdisplay_cursor *)data;
277 		if (curs->which & WSDISPLAY_CURSOR_DOCUR)
278 			curs->enable = sc->sc_curs_enabled;
279 		if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
280 			curs->pos.x = sc->sc_curs_pos.x;
281 			curs->pos.y = sc->sc_curs_pos.y;
282 		}
283 		if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
284 			curs->hot.x = sc->sc_curs_hot.x;
285 			curs->hot.y = sc->sc_curs_hot.y;
286 		}
287 		if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
288 			curs->cmap.index = 0;
289 			curs->cmap.count = 2;
290 			r[0] = sc->sc_curs_fg >> 0;
291 			g[0] = sc->sc_curs_fg >> 8;
292 			b[0] = sc->sc_curs_fg >> 16;
293 			r[1] = sc->sc_curs_bg >> 0;
294 			g[1] = sc->sc_curs_bg >> 8;
295 			b[1] = sc->sc_curs_bg >> 16;
296 			error = copyout(r, curs->cmap.red, sizeof(r));
297 			if (error)
298 				return (error);
299 			error = copyout(g, curs->cmap.green, sizeof(g));
300 			if (error)
301 				return (error);
302 			error = copyout(b, curs->cmap.blue, sizeof(b));
303 			if (error)
304 				return (error);
305 		}
306 		if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
307 			size_t l;
308 
309 			curs->size.x = sc->sc_curs_size.x;
310 			curs->size.y = sc->sc_curs_size.y;
311 			l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
312 			error = copyout(sc->sc_curs_image, curs->image, l);
313 			if (error)
314 				return (error);
315 			error = copyout(sc->sc_curs_mask, curs->mask, l);
316 			if (error)
317 				return (error);
318 		}
319 		break;
320 	case WSDISPLAYIO_SCURPOS:
321 		pos = (struct wsdisplay_curpos *)data;
322 		sc->sc_curs_pos.x = pos->x;
323 		sc->sc_curs_pos.y = pos->y;
324 		creator_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
325 		break;
326 	case WSDISPLAYIO_GCURPOS:
327 		pos = (struct wsdisplay_curpos *)data;
328 		pos->x = sc->sc_curs_pos.x;
329 		pos->y = sc->sc_curs_pos.y;
330 		break;
331 	case WSDISPLAYIO_SCURSOR:
332 		curs = (struct wsdisplay_cursor *)data;
333 		return (creator_setcursor(sc, curs));
334 	case WSDISPLAYIO_GCURMAX:
335 		pos = (struct wsdisplay_curpos *)data;
336 		pos->x = CREATOR_CURS_MAX;
337 		pos->y = CREATOR_CURS_MAX;
338 		break;
339 	case WSDISPLAYIO_SVIDEO:
340 	case WSDISPLAYIO_GVIDEO:
341 		break;
342 
343 	case WSDISPLAYIO_GETCMAP:
344 	case WSDISPLAYIO_PUTCMAP:
345 	default:
346 		return -1; /* not supported yet */
347         }
348 
349 	return (0);
350 }
351 
352 int
353 creator_setcursor(struct creator_softc *sc, struct wsdisplay_cursor *curs)
354 {
355 	u_int8_t r[2], g[2], b[2], image[128], mask[128];
356 	int error;
357 	size_t imcount;
358 
359 	/*
360 	 * Do stuff that can generate errors first, then we'll blast it
361 	 * all at once.
362 	 */
363 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
364 		if (curs->cmap.count < 2)
365 			return (EINVAL);
366 		error = copyin(curs->cmap.red, r, sizeof(r));
367 		if (error)
368 			return (error);
369 		error = copyin(curs->cmap.green, g, sizeof(g));
370 		if (error)
371 			return (error);
372 		error = copyin(curs->cmap.blue, b, sizeof(b));
373 		if (error)
374 			return (error);
375 	}
376 
377 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
378 		if (curs->size.x > CREATOR_CURS_MAX ||
379 		    curs->size.y > CREATOR_CURS_MAX)
380 			return (EINVAL);
381 		imcount = (curs->size.x * curs->size.y) / NBBY;
382 		error = copyin(curs->image, image, imcount);
383 		if (error)
384 			return (error);
385 		error = copyin(curs->mask, mask, imcount);
386 		if (error)
387 			return (error);
388 	}
389 
390 	/*
391 	 * Ok, everything is in kernel space and sane, update state.
392 	 */
393 
394 	if (curs->which & WSDISPLAY_CURSOR_DOCUR)
395 		sc->sc_curs_enabled = curs->enable;
396 	if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
397 		sc->sc_curs_pos.x = curs->pos.x;
398 		sc->sc_curs_pos.y = curs->pos.y;
399 	}
400 	if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
401 		sc->sc_curs_hot.x = curs->hot.x;
402 		sc->sc_curs_hot.y = curs->hot.y;
403 	}
404 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
405 		sc->sc_curs_fg = ((r[0] << 0) | (g[0] << 8) | (b[0] << 16));
406 		sc->sc_curs_bg = ((r[1] << 0) | (g[1] << 8) | (b[1] << 16));
407 	}
408 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
409 		sc->sc_curs_size.x = curs->size.x;
410 		sc->sc_curs_size.y = curs->size.y;
411 		bcopy(image, sc->sc_curs_image, imcount);
412 		bcopy(mask, sc->sc_curs_mask, imcount);
413 	}
414 
415 	creator_updatecursor(sc, curs->which);
416 
417 	return (0);
418 }
419 
420 void
421 creator_curs_enable(struct creator_softc *sc, u_int ena)
422 {
423 	u_int32_t v;
424 
425 	DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSENAB);
426 	if (sc->sc_dacrev <= 2)
427 		v = ena ? 3 : 0;
428 	else
429 		v = ena ? 0 : 3;
430 	DAC_WRITE(sc, FFB_DAC_VALUE2, v);
431 }
432 
433 int
434 creator_updatecursor(struct creator_softc *sc, u_int which)
435 {
436 	creator_curs_enable(sc, 0);
437 
438 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
439 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSCMAP);
440 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_fg);
441 		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_bg);
442 	}
443 
444 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
445 		u_int32_t x, y;
446 
447 		x = sc->sc_curs_pos.x + CREATOR_CURS_MAX - sc->sc_curs_hot.x;
448 		y = sc->sc_curs_pos.y + CREATOR_CURS_MAX - sc->sc_curs_hot.y;
449 		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSPOS);
450 		DAC_WRITE(sc, FFB_DAC_VALUE2,
451 		    ((x & 0xffff) << 16) | (y & 0xffff));
452 	}
453 
454 	if (which & WSDISPLAY_CURSOR_DOCUR)
455 		creator_curs_enable(sc, sc->sc_curs_enabled);
456 
457 	return (0);
458 }
459 
460 const struct creator_mappings {
461 	bus_addr_t uoff;
462 	bus_addr_t poff;
463 	bus_size_t ulen;
464 } creator_map[] = {
465 	{ FFB_VOFF_SFB8R, FFB_POFF_SFB8R, FFB_VLEN_SFB8R },
466 	{ FFB_VOFF_SFB8G, FFB_POFF_SFB8G, FFB_VLEN_SFB8G },
467 	{ FFB_VOFF_SFB8B, FFB_POFF_SFB8B, FFB_VLEN_SFB8B },
468 	{ FFB_VOFF_SFB8X, FFB_POFF_SFB8X, FFB_VLEN_SFB8X },
469 	{ FFB_VOFF_SFB32, FFB_POFF_SFB32, FFB_VLEN_SFB32 },
470 	{ FFB_VOFF_SFB64, FFB_POFF_SFB64, FFB_VLEN_SFB64 },
471 	{ FFB_VOFF_FBC_REGS, FFB_POFF_FBC_REGS, FFB_VLEN_FBC_REGS },
472 	{ FFB_VOFF_BM_FBC_REGS, FFB_POFF_BM_FBC_REGS, FFB_VLEN_BM_FBC_REGS },
473 	{ FFB_VOFF_DFB8R, FFB_POFF_DFB8R, FFB_VLEN_DFB8R },
474 	{ FFB_VOFF_DFB8G, FFB_POFF_DFB8G, FFB_VLEN_DFB8G },
475 	{ FFB_VOFF_DFB8B, FFB_POFF_DFB8B, FFB_VLEN_DFB8B },
476 	{ FFB_VOFF_DFB8X, FFB_POFF_DFB8X, FFB_VLEN_DFB8X },
477 	{ FFB_VOFF_DFB24, FFB_POFF_DFB24, FFB_VLEN_DFB24 },
478 	{ FFB_VOFF_DFB32, FFB_POFF_DFB32, FFB_VLEN_DFB32 },
479 	{ FFB_VOFF_DFB422A, FFB_POFF_DFB422A, FFB_VLEN_DFB422A },
480 	{ FFB_VOFF_DFB422AD, FFB_POFF_DFB422AD, FFB_VLEN_DFB422AD },
481 	{ FFB_VOFF_DFB24B, FFB_POFF_DFB24B, FFB_VLEN_DFB24B },
482 	{ FFB_VOFF_DFB422B, FFB_POFF_DFB422B, FFB_VLEN_DFB422B },
483 	{ FFB_VOFF_DFB422BD, FFB_POFF_DFB422BD, FFB_VLEN_DFB422BD },
484 	{ FFB_VOFF_SFB16Z, FFB_POFF_SFB16Z, FFB_VLEN_SFB16Z },
485 	{ FFB_VOFF_SFB8Z, FFB_POFF_SFB8Z, FFB_VLEN_SFB8Z },
486 	{ FFB_VOFF_SFB422, FFB_POFF_SFB422, FFB_VLEN_SFB422 },
487 	{ FFB_VOFF_SFB422D, FFB_POFF_SFB422D, FFB_VLEN_SFB422D },
488 	{ FFB_VOFF_FBC_KREGS, FFB_POFF_FBC_KREGS, FFB_VLEN_FBC_KREGS },
489 	{ FFB_VOFF_DAC, FFB_POFF_DAC, FFB_VLEN_DAC },
490 	{ FFB_VOFF_PROM, FFB_POFF_PROM, FFB_VLEN_PROM },
491 	{ FFB_VOFF_EXP, FFB_POFF_EXP, FFB_VLEN_EXP },
492 };
493 #define	CREATOR_NMAPPINGS       nitems(creator_map)
494 
495 paddr_t
496 creator_mmap(vsc, off, prot)
497 	void *vsc;
498 	off_t off;
499 	int prot;
500 {
501 	paddr_t x;
502 	struct creator_softc *sc = vsc;
503 	int i;
504 
505 	switch (sc->sc_mode) {
506 	case WSDISPLAYIO_MODE_MAPPED:
507 		/* Turn virtual offset into physical offset */
508 		for (i = 0; i < CREATOR_NMAPPINGS; i++) {
509 			if (off >= creator_map[i].uoff &&
510 			    off < (creator_map[i].uoff + creator_map[i].ulen))
511 				break;
512 		}
513 		if (i == CREATOR_NMAPPINGS)
514 			break;
515 
516 		off -= creator_map[i].uoff;
517 		off += creator_map[i].poff;
518 		off += sc->sc_addrs[0];
519 
520 		/* Map based on physical offset */
521 		for (i = 0; i < sc->sc_nreg; i++) {
522 			/* Before this set? */
523 			if (off < sc->sc_addrs[i])
524 				continue;
525 			/* After this set? */
526 			if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
527 				continue;
528 
529 			x = bus_space_mmap(sc->sc_bt, 0, off, prot,
530 			    BUS_SPACE_MAP_LINEAR);
531 			return (x);
532 		}
533 		break;
534 	case WSDISPLAYIO_MODE_DUMBFB:
535 		if (sc->sc_nreg <= FFB_REG_DFB24)
536 			break;
537 		if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
538 			return (bus_space_mmap(sc->sc_bt,
539 			    sc->sc_addrs[FFB_REG_DFB24], off, prot,
540 			    BUS_SPACE_MAP_LINEAR));
541 		break;
542 	}
543 
544 	return (-1);
545 }
546 
547 void
548 creator_ras_fifo_wait(sc, n)
549 	struct creator_softc *sc;
550 	int n;
551 {
552 	int32_t cache = sc->sc_fifo_cache;
553 
554 	if (cache < n) {
555 		do {
556 			cache = FBC_READ(sc, FFB_FBC_UCSR);
557 			cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
558 		} while (cache < n);
559 	}
560 	sc->sc_fifo_cache = cache - n;
561 }
562 
563 void
564 creator_ras_wait(sc)
565 	struct creator_softc *sc;
566 {
567 	u_int32_t ucsr, r;
568 
569 	while (1) {
570 		ucsr = FBC_READ(sc, FFB_FBC_UCSR);
571 		if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
572 			break;
573 		r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
574 		if (r != 0)
575 			FBC_WRITE(sc, FFB_FBC_UCSR, r);
576 	}
577 }
578 
579 void
580 creator_ras_init(sc)
581 	struct creator_softc *sc;
582 {
583 	creator_ras_fifo_wait(sc, 7);
584 	FBC_WRITE(sc, FFB_FBC_PPC,
585 	    FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
586 	    FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
587 	FBC_WRITE(sc, FFB_FBC_FBC,
588 	    FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
589 	    FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
590 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
591 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
592 	FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
593 	FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
594 	sc->sc_fg_cache = 0;
595 	FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
596 	creator_ras_wait(sc);
597 }
598 
599 int
600 creator_ras_eraserows(cookie, row, n, attr)
601 	void *cookie;
602 	int row, n;
603 	long int attr;
604 {
605 	struct rasops_info *ri = cookie;
606 	struct creator_softc *sc = ri->ri_hw;
607 	int bg, fg;
608 
609 	if (row < 0) {
610 		n += row;
611 		row = 0;
612 	}
613 	if (row + n > ri->ri_rows)
614 		n = ri->ri_rows - row;
615 	if (n <= 0)
616 		return 0;
617 
618 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
619 	creator_ras_fill(sc);
620 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
621 	creator_ras_fifo_wait(sc, 4);
622 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
623 		FBC_WRITE(sc, FFB_FBC_BY, 0);
624 		FBC_WRITE(sc, FFB_FBC_BX, 0);
625 		FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
626 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
627 	} else {
628 		row *= ri->ri_font->fontheight;
629 		FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
630 		FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
631 		FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
632 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
633 	}
634 	creator_ras_wait(sc);
635 
636 	return 0;
637 }
638 
639 int
640 creator_ras_erasecols(cookie, row, col, n, attr)
641 	void *cookie;
642 	int row, col, n;
643 	long int attr;
644 {
645 	struct rasops_info *ri = cookie;
646 	struct creator_softc *sc = ri->ri_hw;
647 	int fg, bg;
648 
649 	if ((row < 0) || (row >= ri->ri_rows))
650 		return 0;
651 	if (col < 0) {
652 		n += col;
653 		col = 0;
654 	}
655 	if (col + n > ri->ri_cols)
656 		n = ri->ri_cols - col;
657 	if (n <= 0)
658 		return 0;
659 	n *= ri->ri_font->fontwidth;
660 	col *= ri->ri_font->fontwidth;
661 	row *= ri->ri_font->fontheight;
662 
663 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
664 	creator_ras_fill(sc);
665 	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
666 	creator_ras_fifo_wait(sc, 4);
667 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
668 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
669 	FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
670 	FBC_WRITE(sc, FFB_FBC_BW, n - 1);
671 	creator_ras_wait(sc);
672 
673 	return 0;
674 }
675 
676 void
677 creator_ras_fill(sc)
678 	struct creator_softc *sc;
679 {
680 	creator_ras_fifo_wait(sc, 2);
681 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
682 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
683 	creator_ras_wait(sc);
684 }
685 
686 int
687 creator_ras_copyrows(cookie, src, dst, n)
688 	void *cookie;
689 	int src, dst, n;
690 {
691 	struct rasops_info *ri = cookie;
692 	struct creator_softc *sc = ri->ri_hw;
693 
694 	if (dst == src)
695 		return 0;
696 	if (src < 0) {
697 		n += src;
698 		src = 0;
699 	}
700 	if ((src + n) > ri->ri_rows)
701 		n = ri->ri_rows - src;
702 	if (dst < 0) {
703 		n += dst;
704 		dst = 0;
705 	}
706 	if ((dst + n) > ri->ri_rows)
707 		n = ri->ri_rows - dst;
708 	if (n <= 0)
709 		return 0;
710 	n *= ri->ri_font->fontheight;
711 	src *= ri->ri_font->fontheight;
712 	dst *= ri->ri_font->fontheight;
713 
714 	creator_ras_fifo_wait(sc, 8);
715 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
716 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
717 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
718 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
719 	FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
720 	FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
721 	FBC_WRITE(sc, FFB_FBC_BH, n);
722 	FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
723 	creator_ras_wait(sc);
724 
725 	return 0;
726 }
727 
728 void
729 creator_ras_setfg(sc, fg)
730 	struct creator_softc *sc;
731 	int32_t fg;
732 {
733 	creator_ras_fifo_wait(sc, 1);
734 	if (fg == sc->sc_fg_cache)
735 		return;
736 	sc->sc_fg_cache = fg;
737 	FBC_WRITE(sc, FFB_FBC_FG, fg);
738 	creator_ras_wait(sc);
739 }
740 
741 #ifndef SMALL_KERNEL
742 struct creator_firmware {
743 	char		fw_ident[8];
744 	u_int32_t	fw_size;
745 	u_int32_t	fw_reserved[2];
746 	u_int32_t	fw_ucode[0];
747 };
748 
749 #define CREATOR_FIRMWARE_REV	0x101
750 
751 void
752 creator_load_firmware(void *vsc)
753 {
754 	struct creator_softc *sc = vsc;
755 	struct creator_firmware *fw;
756 	u_int32_t ascr;
757 	size_t buflen;
758 	u_char *buf;
759 	int error;
760 
761 	error = loadfirmware("afb", &buf, &buflen);
762 	if (error) {
763 		printf("%s: error %d, could not read firmware %s\n",
764 		       sc->sc_sunfb.sf_dev.dv_xname, error, "afb");
765 		return;
766 	}
767 
768 	fw = (struct creator_firmware *)buf;
769 	if (sizeof(*fw) > buflen ||
770 	    fw->fw_size * sizeof(u_int32_t) > (buflen - sizeof(*fw))) {
771 		printf("%s: corrupt firmware\n", sc->sc_sunfb.sf_dev.dv_xname);
772 		free(buf, M_DEVBUF);
773 		return;
774 	}
775 
776 	printf("%s: firmware rev %d.%d.%d\n", sc->sc_sunfb.sf_dev.dv_xname,
777 	       (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 16) & 0xff,
778 	       (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 8) & 0xff,
779 	       fw->fw_ucode[CREATOR_FIRMWARE_REV] & 0xff);
780 
781 	ascr = FBC_READ(sc, FFB_FBC_ASCR);
782 
783 	/* Stop all floats. */
784 	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
785 	FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_STOP);
786 
787 	creator_ras_wait(sc);
788 
789 	/* Load firmware into all secondary floats. */
790 	if (ascr & 0x3e) {
791 		FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3e);
792 		creator_load_sram(sc, fw->fw_ucode, fw->fw_size);
793 	}
794 
795 	/* Load firmware into primary float. */
796 	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x01);
797 	creator_load_sram(sc, fw->fw_ucode, fw->fw_size);
798 
799 	/* Restart all floats. */
800 	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
801 	FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_RESTART);
802 
803 	creator_ras_wait(sc);
804 
805 	free(buf, M_DEVBUF);
806 }
807 #endif /* SMALL_KERNEL */
808 
809 void
810 creator_load_sram(struct creator_softc *sc, u_int32_t *ucode, u_int32_t size)
811 {
812 	uint64_t pstate, fprs;
813 	caddr_t sram;
814 
815 	sram = bus_space_vaddr(sc->sc_bt, sc->sc_fbc_h) + FFB_FBC_SRAM36;
816 
817 	/*
818 	 * Apparently, loading the firmware into SRAM needs to be done
819 	 * using block copies.  And block copies use the
820 	 * floating-point registers.  Generally, using the FPU in the
821 	 * kernel is verboten.  But since we load the firmware before
822 	 * userland processes are started, thrashing the
823 	 * floating-point registers is fine.  We do need to enable the
824 	 * FPU before we access them though, otherwise we'll trap.
825 	 */
826 	pstate = sparc_rdpr(pstate);
827 	sparc_wrpr(pstate, pstate | PSTATE_PEF, 0);
828 	fprs = sparc_rd(fprs);
829 	sparc_wr(fprs, FPRS_FEF, 0);
830 
831 	FBC_WRITE(sc, FFB_FBC_SRAMAR, 0);
832 
833 	while (size > 0) {
834 		creator_ras_fifo_wait(sc, 16);
835 
836 		__asm__ __volatile__("ld	[%0 + 0x00], %%f1\n\t"
837 				     "ld	[%0 + 0x04], %%f0\n\t"
838 				     "ld	[%0 + 0x08], %%f3\n\t"
839 				     "ld	[%0 + 0x0c], %%f2\n\t"
840 				     "ld	[%0 + 0x10], %%f5\n\t"
841 				     "ld	[%0 + 0x14], %%f4\n\t"
842 				     "ld	[%0 + 0x18], %%f7\n\t"
843 				     "ld	[%0 + 0x1c], %%f6\n\t"
844 				     "ld	[%0 + 0x20], %%f9\n\t"
845 				     "ld	[%0 + 0x24], %%f8\n\t"
846 				     "ld	[%0 + 0x28], %%f11\n\t"
847 				     "ld	[%0 + 0x2c], %%f10\n\t"
848 				     "ld	[%0 + 0x30], %%f13\n\t"
849 				     "ld	[%0 + 0x34], %%f12\n\t"
850 				     "ld	[%0 + 0x38], %%f15\n\t"
851 				     "ld	[%0 + 0x3c], %%f14\n\t"
852 				     "membar	#Sync\n\t"
853 				     "stda	%%f0, [%1] 240\n\t"
854 				     "membar	#Sync"
855 				     : : "r" (ucode), "r" (sram));
856 
857 		ucode += 16;
858 		size -= 16;
859 	}
860 
861 	sparc_wr(fprs, fprs, 0);
862 	sparc_wrpr(pstate, pstate, 0);
863 
864 	creator_ras_wait(sc);
865 }
866