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