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