xref: /netbsd-src/sys/dev/tc/sfbplus.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* $NetBSD: sfbplus.c,v 1.20 2003/12/17 03:59:33 ad Exp $ */
2 
3 /*
4  * Copyright (c) 1999, 2000, 2001 Tohru Nishimura.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tohru Nishimura
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: sfbplus.c,v 1.20 2003/12/17 03:59:33 ad Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52 
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt459reg.h>
55 #include <dev/ic/bt463reg.h>
56 #include <dev/tc/sfbreg.h>
57 #include <dev/pci/tgareg.h>
58 
59 #include <uvm/uvm_extern.h>
60 
61 #if defined(pmax)
62 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
63 #endif
64 
65 #if defined(alpha)
66 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
67 #endif
68 
69 /* Bt459/Bt463 hardware registers */
70 #define bt_lo	0
71 #define bt_hi	1
72 #define bt_reg	2
73 #define bt_cmap 3
74 
75 #define REG(base, index)	*((u_int32_t *)(base) + (index))
76 #define SELECT(vdac, regno) do {			\
77 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
78 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
79 	tc_wmb();					\
80    } while (0)
81 
82 struct hwcmap256 {
83 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
84 	u_int8_t r[CMAP_SIZE];
85 	u_int8_t g[CMAP_SIZE];
86 	u_int8_t b[CMAP_SIZE];
87 };
88 
89 struct hwcursor64 {
90 	struct wsdisplay_curpos cc_pos;
91 	struct wsdisplay_curpos cc_hot;
92 	struct wsdisplay_curpos cc_size;
93 	struct wsdisplay_curpos cc_magic;
94 #define	CURSOR_MAX_SIZE	64
95 	u_int8_t cc_color[6];
96 	u_int64_t cc_image[CURSOR_MAX_SIZE];
97 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
98 };
99 
100 struct hwops {
101 	void (*setlut) __P((caddr_t, struct hwcmap256 *));
102 	void (*getlut) __P((caddr_t, struct hwcmap256 *));
103 	void (*visible) __P((caddr_t, int));
104 	void (*locate) __P((caddr_t, struct hwcursor64 *));
105 	void (*shape) __P((caddr_t, struct wsdisplay_curpos *, u_int64_t *));
106 	void (*color) __P((caddr_t, u_int8_t *));
107 };
108 
109 struct sfbp_softc {
110 	struct device sc_dev;
111 	vaddr_t sc_vaddr;
112 	size_t sc_size;
113 	struct rasops_info *sc_ri;
114 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
115 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
116 	int sc_blanked;
117 	int sc_curenb;			/* cursor sprite enabled */
118 	int sc_changed;			/* need update of hardware */
119 #define	WSDISPLAY_CMAP_DOLUT	0x20
120 	int nscreens;
121 	struct hwops sc_hwops;
122 };
123 
124 #define	HX_MAGIC_X	368
125 #define	HX_MAGIC_Y	38
126 
127 static int  sfbpmatch __P((struct device *, struct cfdata *, void *));
128 static void sfbpattach __P((struct device *, struct device *, void *));
129 
130 CFATTACH_DECL(sfbp, sizeof(struct sfbp_softc),
131     sfbpmatch, sfbpattach, NULL, NULL);
132 
133 static void sfbp_common_init __P((struct rasops_info *));
134 static struct rasops_info sfbp_console_ri;
135 static tc_addr_t sfbp_consaddr;
136 
137 static struct wsscreen_descr sfbp_stdscreen = {
138 	"std", 0, 0,
139 	NULL, /* textops */
140 	0, 0,
141 	WSSCREEN_REVERSE
142 };
143 
144 static const struct wsscreen_descr *_sfb_scrlist[] = {
145 	&sfbp_stdscreen,
146 };
147 
148 static const struct wsscreen_list sfb_screenlist = {
149 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
150 };
151 
152 static int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
153 static paddr_t	sfbmmap __P((void *, off_t, int));
154 
155 static int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
156 				      void **, int *, int *, long *));
157 static void	sfb_free_screen __P((void *, void *));
158 static int	sfb_show_screen __P((void *, void *, int,
159 				     void (*) (void *, int, int), void *));
160 static void sfbp_putchar __P((void *, int, int, u_int, long));
161 static void sfbp_erasecols __P((void *, int, int, int, long));
162 static void sfbp_eraserows __P((void *, int, int, long));
163 static void sfbp_copyrows __P((void *, int, int, int));
164 
165 static const struct wsdisplay_accessops sfb_accessops = {
166 	sfbioctl,
167 	sfbmmap,
168 	sfb_alloc_screen,
169 	sfb_free_screen,
170 	sfb_show_screen,
171 	0 /* load_font */
172 };
173 
174 static void bt459init __P((caddr_t));
175 static void bt459visible __P((caddr_t, int));
176 static void bt459locate __P((caddr_t, struct hwcursor64 *));
177 static void bt459shape __P((caddr_t, struct wsdisplay_curpos *, u_int64_t *));
178 static void bt459color __P((caddr_t, u_int8_t *));
179 static void bt459setlut __P((caddr_t, struct hwcmap256 *));
180 
181 static void sfbpvisible __P((caddr_t, int));
182 static void sfbplocate __P((caddr_t, struct hwcursor64 *));
183 static void sfbpshape __P((caddr_t, struct wsdisplay_curpos *, u_int64_t *));
184 static void bt463init __P((caddr_t));
185 static void bt463color __P((caddr_t, u_int8_t *));
186 static void noplut __P((caddr_t, struct hwcmap256 *));
187 
188 /* EXPORT */ int sfbp_cnattach __P((tc_addr_t));
189 static int  sfbpintr __P((void *));
190 static void sfbp_cmap_init __P((struct sfbp_softc *));
191 static void sfbp_screenblank __P((struct sfbp_softc *, int));
192 
193 static int  get_cmap __P((struct sfbp_softc *, struct wsdisplay_cmap *));
194 static int  set_cmap __P((struct sfbp_softc *, struct wsdisplay_cmap *));
195 static int  set_cursor __P((struct sfbp_softc *, struct wsdisplay_cursor *));
196 static int  get_cursor __P((struct sfbp_softc *, struct wsdisplay_cursor *));
197 static void set_curpos __P((struct sfbp_softc *, struct wsdisplay_curpos *));
198 
199 /*
200  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
201  *   M M M M I I I I		M I M I M I M I
202  *	[ before ]		   [ after ]
203  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
204  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
205  */
206 static const u_int8_t shuffle[256] = {
207 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
208 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
209 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
210 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
211 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
212 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
213 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
214 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
215 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
216 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
217 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
218 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
219 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
220 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
221 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
222 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
223 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
224 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
225 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
226 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
227 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
228 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
229 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
230 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
231 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
232 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
233 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
234 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
235 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
236 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
237 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
238 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
239 };
240 
241 static int
242 sfbpmatch(parent, match, aux)
243 	struct device *parent;
244 	struct cfdata *match;
245 	void *aux;
246 {
247 	struct tc_attach_args *ta = aux;
248 
249 	if (strncmp("PMAGD   ", ta->ta_modname, TC_ROM_LLEN) != 0)
250 		return (0);
251 
252 	return (1);
253 }
254 
255 static void
256 sfbpattach(parent, self, aux)
257 	struct device *parent, *self;
258 	void *aux;
259 {
260 	struct sfbp_softc *sc = (struct sfbp_softc *)self;
261 	struct tc_attach_args *ta = aux;
262 	struct rasops_info *ri;
263 	struct wsemuldisplaydev_attach_args waa;
264 	caddr_t asic;
265 	int console;
266 
267 	console = (ta->ta_addr == sfbp_consaddr);
268 	if (console) {
269 		sc->sc_ri = ri = &sfbp_console_ri;
270 		sc->nscreens = 1;
271 	}
272 	else {
273 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
274 			M_DEVBUF, M_NOWAIT);
275 		if (ri == NULL) {
276 			printf(": can't alloc memory\n");
277 			return;
278 		}
279 		memset(ri, 0, sizeof(struct rasops_info));
280 
281 		ri->ri_hw = (void *)ta->ta_addr;
282 		sfbp_common_init(ri);
283 		sc->sc_ri = ri;
284 	}
285 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height,
286 	    (ri->ri_depth != 32) ? 8 : 24);
287 
288 	sc->sc_vaddr = ta->ta_addr;
289 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
290 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
291 	sc->sc_blanked = sc->sc_curenb = 0;
292 
293 	if (ri->ri_depth == 8) {
294 		sc->sc_hwops.visible = bt459visible;
295 		sc->sc_hwops.locate = bt459locate;
296 		sc->sc_hwops.shape = bt459shape;
297 		sc->sc_hwops.color = bt459color;
298 		sc->sc_hwops.setlut = bt459setlut;
299 		sc->sc_hwops.getlut = noplut;
300 	} else {
301 		sc->sc_hwops.visible = sfbpvisible;
302 		sc->sc_hwops.locate = sfbplocate;
303 		sc->sc_hwops.shape = sfbpshape;
304 		sc->sc_hwops.color = bt463color;
305 		sc->sc_hwops.setlut = noplut;
306 		sc->sc_hwops.getlut = noplut;
307 	}
308 	sfbp_cmap_init(sc);
309 
310         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
311 
312 	asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
313 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
314 	*(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
315 
316 	waa.console = console;
317 	waa.scrdata = &sfb_screenlist;
318 	waa.accessops = &sfb_accessops;
319 	waa.accesscookie = sc;
320 
321 	config_found(self, &waa, wsemuldisplaydevprint);
322 }
323 
324 static void
325 sfbp_cmap_init(sc)
326 	struct sfb_softc *sc;
327 {
328 	struct hwcmap256 *cm;
329 	const u_int8_t *p;
330 	int index;
331 
332 	if (sc->sc_ri->ri_depth != 8)
333 		return;
334 
335 	cm = &sc->sc_cmap;
336 	p = rasops_cmap;
337 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
338 		cm->r[index] = p[0];
339 		cm->g[index] = p[1];
340 		cm->b[index] = p[2];
341 	}
342 }
343 
344 static void
345 sfbp_common_init(ri)
346 	struct rasops_info *ri;
347 {
348 	caddr_t base, asic;
349 	int i, depth, hsetup, vsetup, vbase, cookie;
350 
351 	base = (caddr_t)ri->ri_hw;
352 	asic = base + SFB_ASIC_OFFSET;
353 	hsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
354 	vsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
355 	i = *(u_int32_t *)(asic + SFB_ASIC_DEEP);
356 	depth = (i & 01) ? 32 : 8;
357 
358 	/*
359 	 * - neglect 0,1 cases of hsetup register.
360 	 * - observed 804x600?, 644x480? values.
361 	 */
362 
363 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
364 	vbase *= (i & 0x20) ? 2048 : 4096;	/* VRAM chip size */
365 	if (i & 1) vbase *= 4;			/* bytes per pixel */
366 
367 	*(u_int32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
368 	*(u_int32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
369 	*(u_int32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
370 	*(u_int32_t *)(asic + SFB_ASIC_ROP) = 3;	/* ROP_COPY */
371 
372 	/* initialize colormap and cursor hardware */
373 	if (depth != 32) {
374 		*(u_int32_t *)(asic + 0x180000) = 0;	/* Bt459 reset */
375 		bt459init(base + SFB_RAMDAC_OFFSET);
376 	}
377 	else {
378 		bt463init(base + SFB_RAMDAC_OFFSET);
379 	}
380 
381 	ri->ri_flg = RI_CENTER;
382 	ri->ri_flg = 0;			/* XXX 32bpp RI_CENTER fails XXX */
383 	ri->ri_depth = depth;
384 	ri->ri_width = (hsetup & 0x1ff) << 2;
385 	ri->ri_height = (vsetup & 0x7ff);
386 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
387 	ri->ri_bits = base + 0x800000 + vbase;
388 
389 	if (depth == 32) {
390 		ri->ri_rnum = 8;
391 		ri->ri_gnum = 8;
392 		ri->ri_bnum = 8;
393 		ri->ri_rpos = 16;
394 		ri->ri_gpos = 8;
395 		ri->ri_bpos = 0;
396 	}
397 
398 	/* clear the screen */
399 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
400 
401 	wsfont_init();
402 	/* prefer 12 pixel wide font */
403 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
404 	    WSDISPLAY_FONTORDER_L2R);
405 	if (cookie <= 0)
406 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
407 		    WSDISPLAY_FONTORDER_L2R);
408 	if (cookie <= 0) {
409 		printf("sfbp: font table is empty\n");
410 		return;
411 	}
412 
413 	/* the accelerated sfbp_putchar() needs LSbit left */
414 	if (wsfont_lock(cookie, &ri->ri_font)) {
415 		printf("sfb: couldn't lock font\n");
416 		return;
417 	}
418 	ri->ri_wsfcookie = cookie;
419 
420 	rasops_init(ri, 34, 80);
421 
422 	/* add our accelerated functions */
423 	ri->ri_ops.putchar = sfbp_putchar;
424 	ri->ri_ops.erasecols = sfbp_erasecols;
425 	ri->ri_ops.copyrows = sfbp_copyrows;
426 	ri->ri_ops.eraserows = sfbp_eraserows;
427 
428 	/* XXX shouldn't be global */
429 	sfbp_stdscreen.nrows = ri->ri_rows;
430 	sfbp_stdscreen.ncols = ri->ri_cols;
431 	sfbp_stdscreen.textops = &ri->ri_ops;
432 	sfbp_stdscreen.capabilities = ri->ri_caps;
433 	/* our accelerated putchar can't underline */
434 	sfbp_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE;
435 }
436 
437 static int
438 sfbioctl(v, cmd, data, flag, p)
439 	void *v;
440 	u_long cmd;
441 	caddr_t data;
442 	int flag;
443 	struct proc *p;
444 {
445 	struct sfbp_softc *sc = v;
446 	struct rasops_info *ri = sc->sc_ri;
447 	int turnoff, s;
448 
449 	switch (cmd) {
450 	case WSDISPLAYIO_GTYPE:
451 		*(u_int *)data = WSDISPLAY_TYPE_SFBP;
452 		return (0);
453 
454 	case WSDISPLAYIO_GINFO:
455 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
456 		wsd_fbip->height = ri->ri_height;
457 		wsd_fbip->width = ri->ri_width;
458 		wsd_fbip->depth = ri->ri_depth;
459 		wsd_fbip->cmsize = CMAP_SIZE;	/* XXX */
460 #undef fbt
461 		return (0);
462 
463 	case WSDISPLAYIO_GETCMAP:
464 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
465 
466 	case WSDISPLAYIO_PUTCMAP:
467 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
468 
469 	case WSDISPLAYIO_SVIDEO:
470 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
471 		if ((sc->sc_blanked == 0) ^ turnoff) {
472 			sc->sc_blanked = turnoff;
473 #if 0 /* XXX later XXX */
474 	Low order 3bit control visibilities of screen and builtin cursor.
475 #endif	/* XXX XXX XXX */
476 		}
477 		return (0);
478 
479 	case WSDISPLAYIO_GVIDEO:
480 		*(u_int *)data = sc->sc_blanked ?
481 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
482 		return (0);
483 
484 	case WSDISPLAYIO_GCURPOS:
485 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
486 		return (0);
487 
488 	case WSDISPLAYIO_SCURPOS:
489 		s = spltty();
490 		set_curpos(sc, (struct wsdisplay_curpos *)data);
491 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
492 		splx(s);
493 		return (0);
494 
495 	case WSDISPLAYIO_GCURMAX:
496 		((struct wsdisplay_curpos *)data)->x =
497 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
498 		return (0);
499 
500 	case WSDISPLAYIO_GCURSOR:
501 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
502 
503 	case WSDISPLAYIO_SCURSOR:
504 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
505 
506 	case WSDISPLAYIO_SMODE:
507 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
508 			s = spltty();
509 			sfbp_cmap_init(sc);
510 			sc->sc_curenb = 0;
511 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
512 			    WSDISPLAY_CMAP_DOLUT);
513 			splx(s);
514 		}
515 		return (0);
516 	}
517 	}
518 	return (EPASSTHROUGH);
519 }
520 
521 paddr_t
522 sfbmmap(v, offset, prot)
523 	void *v;
524 	off_t offset;
525 	int prot;
526 {
527 	struct sfbp_softc *sc = v;
528 
529 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
530 		return (-1);
531 	return machine_btop(sc->sc_vaddr + offset);
532 }
533 
534 static int
535 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
536 	void *v;
537 	const struct wsscreen_descr *type;
538 	void **cookiep;
539 	int *curxp, *curyp;
540 	long *attrp;
541 {
542 	struct sfbp_softc *sc = v;
543 	struct rasops_info *ri = sc->sc_ri;
544 	long defattr;
545 
546 	if (sc->nscreens > 0)
547 		return (ENOMEM);
548 
549 	*cookiep = ri;		 /* one and only for now */
550 	*curxp = 0;
551 	*curyp = 0;
552 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
553 	*attrp = defattr;
554 	sc->nscreens++;
555 	return (0);
556 }
557 
558 void
559 sfb_free_screen(v, cookie)
560 	void *v;
561 	void *cookie;
562 {
563 	struct sfbp_softc *sc = v;
564 
565 	if (sc->sc_ri == &sfbp_console_ri)
566 		panic("sfb_free_screen: console");
567 
568 	sc->nscreens--;
569 }
570 
571 static int
572 sfb_show_screen(v, cookie, waitok, cb, cbarg)
573 	void *v;
574 	void *cookie;
575 	int waitok;
576 	void (*cb) __P((void *, int, int));
577 	void *cbarg;
578 {
579 
580 	return (0);
581 }
582 
583 int
584 sfbp_cnattach(addr)
585 	tc_addr_t addr;
586 {
587 	struct rasops_info *ri;
588 	long defattr;
589 
590 	ri = &sfbp_console_ri;
591 	ri->ri_hw = (void *)addr;
592 	sfbp_common_init(ri);
593 	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
594 	wsdisplay_cnattach(&sfbp_stdscreen, ri, 0, 0, defattr);
595 	sfbp_consaddr = addr;
596 	return (0);
597 }
598 
599 static int
600 sfbpintr(arg)
601 	void *arg;
602 {
603 #define	cc (&sc->sc_cursor)
604 	struct sfbp_softc *sc = arg;
605 	caddr_t base, asic;
606 	u_int32_t sisr;
607 	int v;
608 
609 	base = (caddr_t)sc->sc_ri->ri_hw;
610 	asic = base + SFB_ASIC_OFFSET;
611 	sisr = *((u_int32_t *)asic + TGA_REG_SISR);
612 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
613 
614 	if (sc->sc_changed == 0)
615 		goto done;
616 
617 	v = sc->sc_changed;
618 	if (v & WSDISPLAY_CURSOR_DOCUR)
619 		(*sc->sc_hwops.visible)(base, sc->sc_curenb);
620 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT))
621 		(*sc->sc_hwops.locate)(base, cc);
622 	if (v & WSDISPLAY_CURSOR_DOCMAP)
623 		(*sc->sc_hwops.color)(base, cc->cc_color);
624 	if (v & WSDISPLAY_CURSOR_DOSHAPE)
625 		(*sc->sc_hwops.shape)(base, &cc->cc_size, cc->cc_image);
626 	if (v & WSDISPLAY_CMAP_DOLUT)
627 		(*sc->sc_hwops.setlut)(base, &sc->sc_cmap);
628 	sc->sc_changed = 0;
629 done:
630 	*((u_int32_t *)asic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
631 	return (1);
632 #undef cc
633 }
634 
635 static void
636 bt459init(vdac)
637 	caddr_t vdac;
638 {
639 	const u_int8_t *p;
640 	int i;
641 
642 	SELECT(vdac, BT459_IREG_COMMAND_0);
643 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
644 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
645 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
646 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
647 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
648 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
649 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
650 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
651 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
652 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
653 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
654 
655 	SELECT(vdac, BT459_IREG_CCR);
656 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
657 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
658 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
659 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
660 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
661 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
662 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
663 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
664 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
665 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
666 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
667 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
668 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
669 
670 	/* build sane colormap */
671 	SELECT(vdac, 0);
672 	p = rasops_cmap;
673 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
674 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
675 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
676 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
677 	}
678 
679 	/* clear out cursor image */
680 	SELECT(vdac, BT459_IREG_CRAM_BASE);
681 	for (i = 0; i < 1024; i++)
682 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
683 
684 	/*
685 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
686 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
687 	 * image color.  CCOLOR_1 will be never used.
688 	 */
689 	SELECT(vdac, BT459_IREG_CCOLOR_1);
690 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
691 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
692 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
693 
694 	REG(vdac, bt_reg) = 0;		tc_wmb();
695 	REG(vdac, bt_reg) = 0;		tc_wmb();
696 	REG(vdac, bt_reg) = 0;		tc_wmb();
697 
698 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
699 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
700 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
701 }
702 
703 static void
704 bt463init(vdac)
705 	caddr_t vdac;
706 {
707 	int i;
708 
709 	SELECT(vdac, BT463_IREG_COMMAND_0);
710 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
711 	REG(vdac, bt_reg) = 0x48;	tc_wmb();	/* CMD 1 */
712 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
713 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
714 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
715 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
716 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
717 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
718 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
719 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
720 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
721 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
722 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
723 
724 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
725 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
726 		REG(vdac, bt_reg) = 0x00;	/*   0:7  */
727 		REG(vdac, bt_reg) = 0xe1;	/*   8:15 */
728 		REG(vdac, bt_reg) = 0x81; 	/*  16:23 */
729 	}
730 }
731 
732 static int
733 get_cmap(sc, p)
734 	struct sfbp_softc *sc;
735 	struct wsdisplay_cmap *p;
736 {
737 	u_int index = p->index, count = p->count;
738 	int error;
739 
740 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
741 		return (EINVAL);
742 
743 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
744 	if (error)
745 		return error;
746 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
747 	if (error)
748 		return error;
749 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
750 	return error;
751 }
752 
753 static int
754 set_cmap(sc, p)
755 	struct sfbp_softc *sc;
756 	struct wsdisplay_cmap *p;
757 {
758 	struct hwcmap256 cmap;
759 	u_int index = p->index, count = p->count;
760 	int error, s;
761 
762 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
763 		return (EINVAL);
764 
765 	error = copyin(p->red, &cmap.r[index], count);
766 	if (error)
767 		return error;
768 	error = copyin(p->green, &cmap.g[index], count);
769 	if (error)
770 		return error;
771 	error = copyin(p->blue, &cmap.b[index], count);
772 	if (error)
773 		return error;
774 
775 	s = spltty();
776 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
777 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
778 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
779 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
780 	splx(s);
781 	return (0);
782 }
783 
784 static int
785 set_cursor(sc, p)
786 	struct sfbp_softc *sc;
787 	struct wsdisplay_cursor *p;
788 {
789 #define	cc (&sc->sc_cursor)
790 	u_int v, index = 0, count = 0, icount = 0;
791 	uint8_t r[2], g[2], b[2], image[512], mask[512];
792 	int error, s;
793 
794 	v = p->which;
795 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
796 		index = p->cmap.index;
797 		count = p->cmap.count;
798 		if (index >= 2 || (index + count) > 2)
799 			return (EINVAL);
800 		error = copyin(p->cmap.red, &r[index], count);
801 		if (error)
802 			return error;
803 		error = copyin(p->cmap.green, &g[index], count);
804 		if (error)
805 			return error;
806 		error = copyin(p->cmap.blue, &b[index], count);
807 		if (error)
808 			return error;
809 	}
810 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
811 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
812 			return (EINVAL);
813 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
814 		error = copyin(p->image, image, icount);
815 		if (error)
816 			return error;
817 		error = copyin(p->mask, mask, icount);
818 		if (error)
819 			return error;
820 	}
821 
822 	s = spltty();
823 	if (v & WSDISPLAY_CURSOR_DOCUR)
824 		sc->sc_curenb = p->enable;
825 	if (v & WSDISPLAY_CURSOR_DOPOS)
826 		set_curpos(sc, &p->pos);
827 	if (v & WSDISPLAY_CURSOR_DOHOT)
828 		cc->cc_hot = p->hot;
829 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
830 		memcpy(&cc->cc_color[index], &r[index], count);
831 		memcpy(&cc->cc_color[index + 2], &g[index], count);
832 		memcpy(&cc->cc_color[index + 4], &b[index], count);
833 	}
834 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
835 		cc->cc_size = p->size;
836 		memset(cc->cc_image, 0, sizeof cc->cc_image);
837 		memcpy(cc->cc_image, image, icount);
838 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
839 		memcpy(cc->cc_mask, mask, icount);
840 	}
841 	sc->sc_changed |= v;
842 	splx(s);
843 
844 	return (0);
845 #undef cc
846 }
847 
848 static int
849 get_cursor(sc, p)
850 	struct sfbp_softc *sc;
851 	struct wsdisplay_cursor *p;
852 {
853 	return (EPASSTHROUGH); /* XXX */
854 }
855 
856 static void
857 set_curpos(sc, curpos)
858 	struct sfbp_softc *sc;
859 	struct wsdisplay_curpos *curpos;
860 {
861 	struct rasops_info *ri = sc->sc_ri;
862 	int x = curpos->x, y = curpos->y;
863 
864 	if (y < 0)
865 		y = 0;
866 	else if (y > ri->ri_height)
867 		y = ri->ri_height;
868 	if (x < 0)
869 		x = 0;
870 	else if (x > ri->ri_width)
871 		x = ri->ri_width;
872 	sc->sc_cursor.cc_pos.x = x;
873 	sc->sc_cursor.cc_pos.y = y;
874 }
875 
876 static void
877 bt459visible(hw, on)
878 	caddr_t hw;
879 	int on;
880 {
881 	hw += SFB_RAMDAC_OFFSET;
882 	SELECT(hw, BT459_IREG_CCR);
883 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
884 	tc_wmb();
885 }
886 
887 static void
888 sfbpvisible(hw, on)
889 	caddr_t hw;
890 	int on;
891 {
892 	/* XXX use SFBplus ASIC XX */
893 }
894 
895 static void
896 bt459locate(hw, cc)
897 	caddr_t hw;
898 	struct hwcursor64 *cc;
899 {
900 	int x, y, s;
901 
902 	x = cc->cc_pos.x - cc->cc_hot.x;
903 	y = cc->cc_pos.y - cc->cc_hot.y;
904 	x += cc->cc_magic.x;
905 	y += cc->cc_magic.y;
906 
907 	hw += SFB_RAMDAC_OFFSET;
908 
909 	s = spltty();
910 	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
911 	REG(hw, bt_reg) = x;		tc_wmb();
912 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
913 	REG(hw, bt_reg) = y;		tc_wmb();
914 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
915 	splx(s);
916 }
917 
918 static void
919 sfbplocate(hw, cc)
920 	caddr_t hw;
921 	struct hwcursor64 *cc;
922 {
923 	int x, y;
924 
925 	x = cc->cc_pos.x - cc->cc_hot.x;
926 	y = cc->cc_pos.y - cc->cc_hot.y;
927 
928 	hw += SFB_ASIC_OFFSET;
929 	*((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
930 	tc_wmb();
931 }
932 
933 static void
934 bt459color(hw, cp)
935 	caddr_t hw;
936 	u_int8_t *cp;
937 {
938 
939 	hw += SFB_RAMDAC_OFFSET;
940 
941 	SELECT(hw, BT459_IREG_CCOLOR_2);
942 	REG(hw, bt_reg) = cp[1]; tc_wmb();
943 	REG(hw, bt_reg) = cp[3]; tc_wmb();
944 	REG(hw, bt_reg) = cp[5]; tc_wmb();
945 
946 	REG(hw, bt_reg) = cp[0]; tc_wmb();
947 	REG(hw, bt_reg) = cp[2]; tc_wmb();
948 	REG(hw, bt_reg) = cp[4]; tc_wmb();
949 }
950 
951 static void
952 bt463color(hw, cp)
953 	caddr_t hw;
954 	u_int8_t *cp;
955 {
956 }
957 
958 static void
959 bt459shape(hw, size, image)
960 	caddr_t hw;
961 	struct wsdisplay_curpos *size;
962 	u_int64_t *image;
963 {
964 	u_int8_t *ip, *mp, img, msk;
965 	u_int8_t u;
966 	int bcnt;
967 
968 	hw += SFB_RAMDAC_OFFSET;
969 	ip = (u_int8_t *)image;
970 	mp = (u_int8_t *)(image + CURSOR_MAX_SIZE);
971 
972 	bcnt = 0;
973 	SELECT(hw, BT459_IREG_CRAM_BASE+0);
974 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
975 	while (bcnt < size->y * 16) {
976 		/* pad right half 32 pixel when smaller than 33 */
977 		if ((bcnt & 0x8) && size->x < 33) {
978 			REG(hw, bt_reg) = 0; tc_wmb();
979 			REG(hw, bt_reg) = 0; tc_wmb();
980 		}
981 		else {
982 			img = *ip++;
983 			msk = *mp++;
984 			img &= msk;	/* cookie off image */
985 			u = (msk & 0x0f) << 4 | (img & 0x0f);
986 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
987 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
988 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
989 		}
990 		bcnt += 2;
991 	}
992 	/* pad unoccupied scan lines */
993 	while (bcnt < CURSOR_MAX_SIZE * 16) {
994 		REG(hw, bt_reg) = 0; tc_wmb();
995 		REG(hw, bt_reg) = 0; tc_wmb();
996 		bcnt += 2;
997 	}
998 }
999 
1000 static void
1001 sfbpshape(hw, size, image)
1002 	caddr_t hw;
1003 	struct wsdisplay_curpos *size;
1004 	u_int64_t *image;
1005 {
1006 	/* XXX use SFBplus ASIC XXX */
1007 }
1008 
1009 static void
1010 bt459setlut(hw, cm)
1011 	caddr_t hw;
1012 	struct hwcmap256 *cm;
1013 {
1014 	int index;
1015 
1016 	hw += SFB_RAMDAC_OFFSET;
1017 	SELECT(hw, 0);
1018 	for (index = 0; index < CMAP_SIZE; index++) {
1019 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
1020 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
1021 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
1022 	}
1023 }
1024 
1025 static void
1026 noplut(hw, cm)
1027 	caddr_t hw;
1028 	struct hwcmap256 *cm;
1029 {
1030 }
1031 
1032 #define SFBBPP 32
1033 
1034 #define	MODE_SIMPLE		0
1035 #define	MODE_OPAQUESTIPPLE	1
1036 #define	MODE_OPAQUELINE		2
1037 #define	MODE_TRANSPARENTSTIPPLE	5
1038 #define	MODE_TRANSPARENTLINE	6
1039 #define	MODE_COPY		7
1040 
1041 #if SFBBPP == 8
1042 /* parameters for 8bpp configuration */
1043 #define	SFBALIGNMASK		0x7
1044 #define	SFBPIXELBYTES		1
1045 #define	SFBSTIPPLEALL1		0xffffffff
1046 #define	SFBSTIPPLEBITS		32
1047 #define	SFBSTIPPLEBITMASK	0x1f
1048 #define	SFBSTIPPLEBYTESDONE	32
1049 #define	SFBCOPYALL1		0xffffffff
1050 #define	SFBCOPYBITS		32
1051 #define	SFBCOPYBITMASK		0x1f
1052 #define	SFBCOPYBYTESDONE	32
1053 
1054 #elif SFBBPP == 32
1055 /* parameters for 32bpp configuration */
1056 #define	SFBALIGNMASK		0x7
1057 #define	SFBPIXELBYTES		4
1058 #define	SFBSTIPPLEALL1		0x0000ffff
1059 #define	SFBSTIPPLEBITS		16
1060 #define	SFBSTIPPLEBITMASK	0xf
1061 #define	SFBSTIPPLEBYTESDONE	32
1062 #define	SFBCOPYALL1		0x000000ff
1063 #define	SFBCOPYBITS		8
1064 #define	SFBCOPYBITMASK		0x3
1065 #define	SFBCOPYBYTESDONE	32
1066 #endif
1067 
1068 #ifdef pmax
1069 #define	WRITE_MB()
1070 #define	BUMP(p) (p)
1071 #endif
1072 
1073 #ifdef alpha
1074 #define	WRITE_MB() tc_wmb()
1075 /* registers is replicated in 1KB stride; rap round 4th iteration */
1076 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x400) & ~0x1000))
1077 #endif
1078 
1079 #define	SFBMODE(p, v) \
1080 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
1081 #define	SFBROP(p, v) \
1082 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
1083 #define	SFBPLANEMASK(p, v) \
1084 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
1085 #define	SFBPIXELMASK(p, v) \
1086 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
1087 #define	SFBADDRESS(p, v) \
1088 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
1089 #define	SFBSTART(p, v) \
1090 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
1091 #define	SFBPIXELSHIFT(p, v) \
1092 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
1093 #define	SFBFG(p, v) \
1094 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
1095 #define	SFBBG(p, v) \
1096 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
1097 #define	SFBBCONT(p, v) \
1098 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BCONT) = (v))
1099 
1100 #define	SFBDATA(p, v) \
1101 		(*((u_int32_t *)BUMP(p) + TGA_REG_GDAR) = (v))
1102 
1103 #define	SFBCOPY64BYTESDONE	8
1104 #define	SFBCOPY64BITS		64
1105 #define	SFBCOPY64SRC(p, v) \
1106 		(*((u_int32_t *)BUMP(p) + TGA_REG_GCSR) = (long)(v))
1107 #define	SFBCOPY64DST(p, v) \
1108 		(*((u_int32_t *)BUMP(p) + TGA_REG_GCDR) = (long)(v))
1109 
1110 /*
1111  * Actually write a string to the frame buffer.
1112  */
1113 static void
1114 sfbp_putchar(id, row, col, uc, attr)
1115 	void *id;
1116 	int row, col;
1117 	u_int uc;
1118 	long attr;
1119 {
1120 	struct rasops_info *ri = id;
1121 	caddr_t sfb, p;
1122 	int scanspan, height, width, align, x, y;
1123 	u_int32_t lmask, rmask, glyph;
1124 	u_int8_t *g;
1125 
1126 	x = col * ri->ri_font->fontwidth;
1127 	y = row * ri->ri_font->fontheight;
1128 	scanspan = ri->ri_stride;
1129 	height = ri->ri_font->fontheight;
1130 	uc -= ri->ri_font->firstchar;
1131 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
1132 
1133 	p = ri->ri_bits + y * scanspan + x * SFBPIXELBYTES;
1134 	align = (long)p & SFBALIGNMASK;
1135 	p -= align;
1136 	align /= SFBPIXELBYTES;
1137 	width = ri->ri_font->fontwidth + align;
1138 	lmask = SFBSTIPPLEALL1 << align;
1139 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1140 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1141 
1142 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
1143 	SFBPLANEMASK(sfb, ~0);
1144 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
1145 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1146 	SFBROP(sfb, (3 << 8) | 3); /* ROP_COPY24 */
1147 	*((u_int32_t *)sfb + TGA_REG_GPXR_P) = lmask & rmask;
1148 
1149 	/* XXX 2B stride fonts only XXX */
1150 	while (height > 0) {
1151 		glyph = *(u_int16_t *)g;		/* XXX */
1152 		*(u_int32_t *)p = glyph << align;
1153 		p += scanspan;
1154 		g += 2;					/* XXX */
1155 		height--;
1156 	}
1157 	SFBMODE(sfb, MODE_SIMPLE);
1158 	*((u_int32_t *)sfb + TGA_REG_GPXR_P) = ~0;
1159 }
1160 
1161 #undef	SFBSTIPPLEALL1
1162 #undef	SFBSTIPPLEBITS
1163 #undef	SFBSTIPPLEBITMASK
1164 #define	SFBSTIPPLEALL1		SFBCOPYALL1
1165 #define	SFBSTIPPLEBITS		SFBCOPYBITS
1166 #define	SFBSTIPPLEBITMASK	SFBCOPYBITMASK
1167 
1168 /*
1169  * Clear characters in a line.
1170  */
1171 static void
1172 sfbp_erasecols(id, row, startcol, ncols, attr)
1173 	void *id;
1174 	int row, startcol, ncols;
1175 	long attr;
1176 {
1177 	struct rasops_info *ri = id;
1178 	caddr_t sfb, p;
1179 	int scanspan, startx, height, width, align, w, y;
1180 	u_int32_t lmask, rmask;
1181 
1182 	scanspan = ri->ri_stride;
1183 	y = row * ri->ri_font->fontheight;
1184 	startx = startcol * ri->ri_font->fontwidth;
1185 	height = ri->ri_font->fontheight;
1186 	w = ri->ri_font->fontwidth * ncols;
1187 
1188 	p = ri->ri_bits + y * scanspan + startx * SFBPIXELBYTES;
1189 	align = (long)p & SFBALIGNMASK;
1190 	align /= SFBPIXELBYTES;
1191 	p -= align;
1192 	width = w + align;
1193 	lmask = SFBSTIPPLEALL1 << align;
1194 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1195 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1196 
1197 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1198 	SFBPLANEMASK(sfb, ~0);
1199 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1200 	if (width <= SFBSTIPPLEBITS) {
1201 		lmask = lmask & rmask;
1202 		while (height > 0) {
1203 			*(u_int32_t *)p = lmask;
1204 			p += scanspan;
1205 			height--;
1206 		}
1207 	}
1208 	else {
1209 		caddr_t q = p;
1210 		while (height > 0) {
1211 			*(u_int32_t *)p = lmask;
1212 			WRITE_MB();
1213 			width -= 2 * SFBSTIPPLEBITS;
1214 			while (width > 0) {
1215 				p += SFBSTIPPLEBYTESDONE;
1216 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1217 				WRITE_MB();
1218 				width -= SFBSTIPPLEBITS;
1219 			}
1220 			p += SFBSTIPPLEBYTESDONE;
1221 			*(u_int32_t *)p = rmask;
1222 			WRITE_MB();
1223 
1224 			p = (q += scanspan);
1225 			width = w + align;
1226 			height--;
1227 		}
1228 	}
1229 	SFBMODE(sfb, MODE_SIMPLE);
1230 }
1231 
1232 #if 1
1233 /*
1234  * Copy lines.
1235  */
1236 static void
1237 sfbp_copyrows(id, srcrow, dstrow, nrows)
1238 	void *id;
1239 	int srcrow, dstrow, nrows;
1240 {
1241 	struct rasops_info *ri = id;
1242 	caddr_t sfb, p;
1243 	int scanspan, offset, srcy, height, width, align, w;
1244 	u_int32_t lmask, rmask;
1245 
1246 	scanspan = ri->ri_stride;
1247 	height = ri->ri_font->fontheight * nrows;
1248 	offset = (dstrow - srcrow) * ri->ri_yscale;
1249 	srcy = ri->ri_font->fontheight * srcrow;
1250 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1251 		scanspan = -scanspan;
1252 		srcy += height;
1253 	}
1254 
1255 	p = ri->ri_bits + srcy * ri->ri_stride;
1256 	align = (long)p & SFBALIGNMASK;
1257 	p -= align;
1258 	align /= SFBPIXELBYTES;
1259 	w = ri->ri_emuwidth;
1260 	width = w + align;
1261 	lmask = SFBCOPYALL1 << align;
1262 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1263 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1264 
1265 	SFBMODE(sfb, MODE_COPY);
1266 	SFBPLANEMASK(sfb, ~0);
1267 	SFBPIXELSHIFT(sfb, 0);
1268 	if (width <= SFBCOPYBITS) {
1269 		/* never happens */;
1270 	}
1271 	else {
1272 		caddr_t q = p;
1273 		while (height > 0) {
1274 			*(u_int32_t *)p = lmask;
1275 			*(u_int32_t *)(p + offset) = lmask;
1276 			width -= 2 * SFBCOPYBITS;
1277 			while (width > 0) {
1278 				p += SFBCOPYBYTESDONE;
1279 				*(u_int32_t *)p = SFBCOPYALL1;
1280 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1281 				width -= SFBCOPYBITS;
1282 			}
1283 			p += SFBCOPYBYTESDONE;
1284 			*(u_int32_t *)p = rmask;
1285 			*(u_int32_t *)(p + offset) = rmask;
1286 
1287 			p = (q += scanspan);
1288 			width = w + align;
1289 			height--;
1290 		}
1291 	}
1292 	SFBMODE(sfb, MODE_SIMPLE);
1293 }
1294 
1295 #else
1296 
1297 
1298 static void
1299 sfbp_copyrows(id, srcrow, dstrow, nrows)
1300 	void *id;
1301 	int srcrow, dstrow, nrows;
1302 {
1303 	struct rasops_info *ri = id;
1304 	caddr_t sfb, p, q;
1305 	int scanspan, offset, srcy, height, width, w, align;
1306 	u_int32_t rmask, lmask;
1307 
1308 	scanspan = ri->ri_stride;
1309 	height = ri->ri_font->fontheight * nrows;
1310 	offset = (dstrow - srcrow) * ri->ri_yscale;
1311 	srcy = ri->ri_font->fontheight * srcrow;
1312 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1313 		scanspan = -scanspan;
1314 		srcy += height;
1315 	}
1316 
1317 	p = ri->ri_bits + srcy * ri->ri_stride;
1318 	align = (long)p & SFBALIGNMASK;
1319 	w = ri->ri_emuwidth;
1320 	width = w + align;
1321 	lmask = SFBCOPYALL1 << align;
1322 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1323 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1324 	q = p;
1325 
1326 	SFBMODE(sfb, MODE_COPY);
1327 	SFBPLANEMASK(sfb, ~0);
1328 	SFBPIXELSHIFT(sfb, 0);
1329 
1330 	if (width <= SFBCOPYBITS)
1331 		; /* never happens */
1332 	else if (width < SFBCOPY64BITS) {
1333 		; /* unlikely happens */
1334 
1335 	}
1336 	else {
1337 		while (height > 0) {
1338 			while (width >= SFBCOPY64BITS) {
1339 				SFBCOPY64SRC(sfb, p);
1340 				SFBCOPY64DST(sfb, p + offset);
1341 				p += SFBCOPY64BYTESDONE;
1342 				width -= SFBCOPY64BITS;
1343 			}
1344 			if (width >= SFBCOPYBITS) {
1345 				*(u_int32_t *)p = SFBCOPYALL1;
1346 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1347 				p += SFBCOPYBYTESDONE;
1348 				width -= SFBCOPYBITS;
1349 			}
1350 			if (width > 0) {
1351 				*(u_int32_t *)p = rmask;
1352 				*(u_int32_t *)(p + offset) = rmask;
1353 			}
1354 
1355 			p = (q += scanspan);
1356 			width = w;
1357 			height--;
1358 		}
1359 	}
1360 	SFBMODE(sfb, MODE_SIMPLE);
1361 }
1362 #endif
1363 
1364 /*
1365  * Erase lines.
1366  */
1367 static void
1368 sfbp_eraserows(id, startrow, nrows, attr)
1369 	void *id;
1370 	int startrow, nrows;
1371 	long attr;
1372 {
1373 	struct rasops_info *ri = id;
1374 	caddr_t sfb, p;
1375 	int scanspan, starty, height, width, align, w;
1376 	u_int32_t lmask, rmask;
1377 
1378 	scanspan = ri->ri_stride;
1379 	starty = ri->ri_font->fontheight * startrow;
1380 	height = ri->ri_font->fontheight * nrows;
1381 
1382 	p = ri->ri_bits + starty * scanspan;
1383 	align = (long)p & SFBALIGNMASK;
1384 	p -= align;
1385 	align /= SFBPIXELBYTES;
1386 	w = ri->ri_emuwidth * SFBPIXELBYTES;
1387 	width = w + align;
1388 	lmask = SFBSTIPPLEALL1 << align;
1389 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1390 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1391 
1392 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1393 	SFBPLANEMASK(sfb, ~0);
1394 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1395 	if (width <= SFBSTIPPLEBITS) {
1396 		/* never happens */;
1397 	}
1398 	else {
1399 		caddr_t q = p;
1400 		while (height > 0) {
1401 			*(u_int32_t *)p = lmask;
1402 			WRITE_MB();
1403 			width -= 2 * SFBSTIPPLEBITS;
1404 			while (width > 0) {
1405 				p += SFBSTIPPLEBYTESDONE;
1406 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1407 				WRITE_MB();
1408 				width -= SFBSTIPPLEBITS;
1409 			}
1410 			p += SFBSTIPPLEBYTESDONE;
1411 			*(u_int32_t *)p = rmask;
1412 			WRITE_MB();
1413 
1414 			p = (q += scanspan);
1415 			width = w + align;
1416 			height--;
1417 		}
1418 	}
1419 	SFBMODE(sfb, MODE_SIMPLE);
1420 }
1421