xref: /netbsd-src/sys/dev/tc/sfbplus.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /* $NetBSD: sfbplus.c,v 1.33 2009/08/22 17:38:06 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.33 2009/08/22 17:38:06 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 		sc->nscreens = 1;
264 	}
265 	else {
266 		ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT);
267 		if (ri == NULL) {
268 			printf(": can't alloc memory\n");
269 			return;
270 		}
271 		memset(ri, 0, sizeof(struct rasops_info));
272 
273 		ri->ri_hw = (void *)ta->ta_addr;
274 		sfbp_common_init(ri);
275 		sc->sc_ri = ri;
276 	}
277 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height,
278 	    (ri->ri_depth != 32) ? 8 : 24);
279 
280 	sc->sc_vaddr = ta->ta_addr;
281 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
282 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
283 	sc->sc_blanked = sc->sc_curenb = 0;
284 
285 	if (ri->ri_depth == 8) {
286 		sc->sc_hwops.visible = bt459visible;
287 		sc->sc_hwops.locate = bt459locate;
288 		sc->sc_hwops.shape = bt459shape;
289 		sc->sc_hwops.color = bt459color;
290 		sc->sc_hwops.setlut = bt459setlut;
291 		sc->sc_hwops.getlut = noplut;
292 	} else {
293 		sc->sc_hwops.visible = sfbpvisible;
294 		sc->sc_hwops.locate = sfbplocate;
295 		sc->sc_hwops.shape = sfbpshape;
296 		sc->sc_hwops.color = bt463color;
297 		sc->sc_hwops.setlut = noplut;
298 		sc->sc_hwops.getlut = noplut;
299 	}
300 	sfbp_cmap_init(sc);
301 
302         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
303 
304 	asic = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
305 	*(uint32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
306 	*(uint32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
307 
308 	waa.console = console;
309 	waa.scrdata = &sfb_screenlist;
310 	waa.accessops = &sfb_accessops;
311 	waa.accesscookie = sc;
312 
313 	config_found(self, &waa, wsemuldisplaydevprint);
314 }
315 
316 static void
317 sfbp_cmap_init(struct sfbp_softc *sc)
318 {
319 	struct hwcmap256 *cm;
320 	const uint8_t *p;
321 	int index;
322 
323 	if (sc->sc_ri->ri_depth != 8)
324 		return;
325 
326 	cm = &sc->sc_cmap;
327 	p = rasops_cmap;
328 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
329 		cm->r[index] = p[0];
330 		cm->g[index] = p[1];
331 		cm->b[index] = p[2];
332 	}
333 }
334 
335 static void
336 sfbp_common_init(struct rasops_info *ri)
337 {
338 	char *base, *asic;
339 	int i, depth, hsetup, vsetup, vbase, cookie;
340 
341 	base = ri->ri_hw;
342 	asic = base + SFB_ASIC_OFFSET;
343 	hsetup = *(uint32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
344 	vsetup = *(uint32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
345 	i = *(uint32_t *)(asic + SFB_ASIC_DEEP);
346 	depth = (i & 01) ? 32 : 8;
347 
348 	/*
349 	 * - neglect 0,1 cases of hsetup register.
350 	 * - observed 804x600?, 644x480? values.
351 	 */
352 
353 	*(uint32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
354 	vbase *= (i & 0x20) ? 2048 : 4096;	/* VRAM chip size */
355 	if (i & 1) vbase *= 4;			/* bytes per pixel */
356 
357 	*(uint32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
358 	*(uint32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
359 	*(uint32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
360 	*(uint32_t *)(asic + SFB_ASIC_ROP) = 3;		/* ROP_COPY */
361 
362 	/* initialize colormap and cursor hardware */
363 	if (depth != 32) {
364 		*(uint32_t *)(asic + 0x180000) = 0;	/* Bt459 reset */
365 		bt459init(base + SFB_RAMDAC_OFFSET);
366 	}
367 	else {
368 		bt463init(base + SFB_RAMDAC_OFFSET);
369 	}
370 
371 	ri->ri_flg = RI_CENTER;
372 	ri->ri_flg = 0;			/* XXX 32bpp RI_CENTER fails XXX */
373 	ri->ri_depth = depth;
374 	ri->ri_width = (hsetup & 0x1ff) << 2;
375 	ri->ri_height = (vsetup & 0x7ff);
376 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
377 	ri->ri_bits = base + 0x800000 + vbase;
378 
379 	if (depth == 32) {
380 		ri->ri_rnum = 8;
381 		ri->ri_gnum = 8;
382 		ri->ri_bnum = 8;
383 		ri->ri_rpos = 16;
384 		ri->ri_gpos = 8;
385 		ri->ri_bpos = 0;
386 	}
387 
388 	/* clear the screen */
389 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
390 
391 	wsfont_init();
392 	/* prefer 12 pixel wide font */
393 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
394 	    WSDISPLAY_FONTORDER_L2R);
395 	if (cookie <= 0)
396 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
397 		    WSDISPLAY_FONTORDER_L2R);
398 	if (cookie <= 0) {
399 		printf("sfbp: font table is empty\n");
400 		return;
401 	}
402 
403 	/* the accelerated sfbp_putchar() needs LSbit left */
404 	if (wsfont_lock(cookie, &ri->ri_font)) {
405 		printf("sfb: couldn't lock font\n");
406 		return;
407 	}
408 	ri->ri_wsfcookie = cookie;
409 
410 	rasops_init(ri, 34, 80);
411 
412 	/* add our accelerated functions */
413 	ri->ri_ops.putchar = sfbp_putchar;
414 	ri->ri_ops.erasecols = sfbp_erasecols;
415 	ri->ri_ops.copyrows = sfbp_copyrows;
416 	ri->ri_ops.eraserows = sfbp_eraserows;
417 
418 	/* XXX shouldn't be global */
419 	sfbp_stdscreen.nrows = ri->ri_rows;
420 	sfbp_stdscreen.ncols = ri->ri_cols;
421 	sfbp_stdscreen.textops = &ri->ri_ops;
422 	sfbp_stdscreen.capabilities = ri->ri_caps;
423 	/* our accelerated putchar can't underline */
424 	sfbp_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE;
425 }
426 
427 static int
428 sfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
429 {
430 	struct sfbp_softc *sc = v;
431 	struct rasops_info *ri = sc->sc_ri;
432 	int turnoff, s;
433 
434 	switch (cmd) {
435 	case WSDISPLAYIO_GTYPE:
436 		*(u_int *)data = WSDISPLAY_TYPE_SFBP;
437 		return (0);
438 
439 	case WSDISPLAYIO_GINFO:
440 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
441 		wsd_fbip->height = ri->ri_height;
442 		wsd_fbip->width = ri->ri_width;
443 		wsd_fbip->depth = ri->ri_depth;
444 		wsd_fbip->cmsize = CMAP_SIZE;	/* XXX */
445 #undef fbt
446 		return (0);
447 
448 	case WSDISPLAYIO_GETCMAP:
449 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
450 
451 	case WSDISPLAYIO_PUTCMAP:
452 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
453 
454 	case WSDISPLAYIO_SVIDEO:
455 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
456 		if ((sc->sc_blanked == 0) ^ turnoff) {
457 			sc->sc_blanked = turnoff;
458 #if 0 /* XXX later XXX */
459 	Low order 3bit control visibilities of screen and builtin cursor.
460 #endif	/* XXX XXX XXX */
461 		}
462 		return (0);
463 
464 	case WSDISPLAYIO_GVIDEO:
465 		*(u_int *)data = sc->sc_blanked ?
466 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
467 		return (0);
468 
469 	case WSDISPLAYIO_GCURPOS:
470 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
471 		return (0);
472 
473 	case WSDISPLAYIO_SCURPOS:
474 		s = spltty();
475 		set_curpos(sc, (struct wsdisplay_curpos *)data);
476 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
477 		splx(s);
478 		return (0);
479 
480 	case WSDISPLAYIO_GCURMAX:
481 		((struct wsdisplay_curpos *)data)->x =
482 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
483 		return (0);
484 
485 	case WSDISPLAYIO_GCURSOR:
486 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
487 
488 	case WSDISPLAYIO_SCURSOR:
489 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
490 
491 	case WSDISPLAYIO_SMODE:
492 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
493 			s = spltty();
494 			sfbp_cmap_init(sc);
495 			sc->sc_curenb = 0;
496 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
497 			    WSDISPLAY_CMAP_DOLUT);
498 			splx(s);
499 		}
500 		return (0);
501 	}
502 	return (EPASSTHROUGH);
503 }
504 
505 paddr_t
506 sfbmmap(void *v, void *vs, off_t offset, int prot)
507 {
508 	struct sfbp_softc *sc = v;
509 
510 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
511 		return (-1);
512 	return machine_btop(sc->sc_vaddr + offset);
513 }
514 
515 static int
516 sfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
517     int *curxp, int *curyp, long *attrp)
518 {
519 	struct sfbp_softc *sc = v;
520 	struct rasops_info *ri = sc->sc_ri;
521 	long defattr;
522 
523 	if (sc->nscreens > 0)
524 		return (ENOMEM);
525 
526 	*cookiep = ri;		 /* one and only for now */
527 	*curxp = 0;
528 	*curyp = 0;
529 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
530 	*attrp = defattr;
531 	sc->nscreens++;
532 	return (0);
533 }
534 
535 void
536 sfb_free_screen(void *v, void *cookie)
537 {
538 	struct sfbp_softc *sc = v;
539 
540 	if (sc->sc_ri == &sfbp_console_ri)
541 		panic("sfb_free_screen: console");
542 
543 	sc->nscreens--;
544 }
545 
546 static int
547 sfb_show_screen(void *v, void *cookie, int waitok,
548     void (*cb)(void *, int, int), void *cbarg)
549 {
550 
551 	return (0);
552 }
553 
554 int
555 sfbp_cnattach(tc_addr_t addr)
556 {
557 	struct rasops_info *ri;
558 	long defattr;
559 
560 	ri = &sfbp_console_ri;
561 	ri->ri_hw = (void *)addr;
562 	sfbp_common_init(ri);
563 	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
564 	wsdisplay_cnattach(&sfbp_stdscreen, ri, 0, 0, defattr);
565 	sfbp_consaddr = addr;
566 	return (0);
567 }
568 
569 static int
570 sfbpintr(void *arg)
571 {
572 #define	cc (&sc->sc_cursor)
573 	struct sfbp_softc *sc = arg;
574 	char *base, *asic;
575 	uint32_t sisr;
576 	int v;
577 
578 	base = sc->sc_ri->ri_hw;
579 	asic = base + SFB_ASIC_OFFSET;
580 	sisr = *((uint32_t *)asic + TGA_REG_SISR);
581 	*(uint32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
582 
583 	if (sc->sc_changed == 0)
584 		goto done;
585 
586 	v = sc->sc_changed;
587 	if (v & WSDISPLAY_CURSOR_DOCUR)
588 		(*sc->sc_hwops.visible)(base, sc->sc_curenb);
589 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT))
590 		(*sc->sc_hwops.locate)(base, cc);
591 	if (v & WSDISPLAY_CURSOR_DOCMAP)
592 		(*sc->sc_hwops.color)(base, cc->cc_color);
593 	if (v & WSDISPLAY_CURSOR_DOSHAPE)
594 		(*sc->sc_hwops.shape)(base, &cc->cc_size, cc->cc_image);
595 	if (v & WSDISPLAY_CMAP_DOLUT)
596 		(*sc->sc_hwops.setlut)(base, &sc->sc_cmap);
597 	sc->sc_changed = 0;
598 done:
599 	*((uint32_t *)asic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
600 	return (1);
601 #undef cc
602 }
603 
604 static void
605 bt459init(void *vdac)
606 {
607 	const uint8_t *p;
608 	int i;
609 
610 	SELECT(vdac, BT459_IREG_COMMAND_0);
611 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
612 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
613 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
614 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
615 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
616 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
617 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
618 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
619 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
620 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
621 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
622 
623 	SELECT(vdac, BT459_IREG_CCR);
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 	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 
638 	/* build sane colormap */
639 	SELECT(vdac, 0);
640 	p = rasops_cmap;
641 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
642 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
643 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
644 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
645 	}
646 
647 	/* clear out cursor image */
648 	SELECT(vdac, BT459_IREG_CRAM_BASE);
649 	for (i = 0; i < 1024; i++)
650 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
651 
652 	/*
653 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
654 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
655 	 * image color.  CCOLOR_1 will be never used.
656 	 */
657 	SELECT(vdac, BT459_IREG_CCOLOR_1);
658 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
659 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
660 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
661 
662 	REG(vdac, bt_reg) = 0;		tc_wmb();
663 	REG(vdac, bt_reg) = 0;		tc_wmb();
664 	REG(vdac, bt_reg) = 0;		tc_wmb();
665 
666 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
667 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
668 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
669 }
670 
671 static void
672 bt463init(void *vdac)
673 {
674 	int i;
675 
676 	SELECT(vdac, BT463_IREG_COMMAND_0);
677 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
678 	REG(vdac, bt_reg) = 0x48;	tc_wmb();	/* CMD 1 */
679 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
680 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
681 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
682 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
683 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
684 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
685 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
686 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
687 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
688 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
689 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
690 
691 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
692 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
693 		REG(vdac, bt_reg) = 0x00;	/*   0:7  */
694 		REG(vdac, bt_reg) = 0xe1;	/*   8:15 */
695 		REG(vdac, bt_reg) = 0x81; 	/*  16:23 */
696 	}
697 }
698 
699 static int
700 get_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
701 {
702 	u_int index = p->index, count = p->count;
703 	int error;
704 
705 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
706 		return (EINVAL);
707 
708 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
709 	if (error)
710 		return error;
711 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
712 	if (error)
713 		return error;
714 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
715 	return error;
716 }
717 
718 static int
719 set_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
720 {
721 	struct hwcmap256 cmap;
722 	u_int index = p->index, count = p->count;
723 	int error, s;
724 
725 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
726 		return (EINVAL);
727 
728 	error = copyin(p->red, &cmap.r[index], count);
729 	if (error)
730 		return error;
731 	error = copyin(p->green, &cmap.g[index], count);
732 	if (error)
733 		return error;
734 	error = copyin(p->blue, &cmap.b[index], count);
735 	if (error)
736 		return error;
737 
738 	s = spltty();
739 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
740 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
741 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
742 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
743 	splx(s);
744 	return (0);
745 }
746 
747 static int
748 set_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
749 {
750 #define	cc (&sc->sc_cursor)
751 	u_int v, index = 0, count = 0, icount = 0;
752 	uint8_t r[2], g[2], b[2], image[512], mask[512];
753 	int error, s;
754 
755 	v = p->which;
756 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
757 		index = p->cmap.index;
758 		count = p->cmap.count;
759 		if (index >= 2 || (index + count) > 2)
760 			return (EINVAL);
761 		error = copyin(p->cmap.red, &r[index], count);
762 		if (error)
763 			return error;
764 		error = copyin(p->cmap.green, &g[index], count);
765 		if (error)
766 			return error;
767 		error = copyin(p->cmap.blue, &b[index], count);
768 		if (error)
769 			return error;
770 	}
771 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
772 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
773 			return (EINVAL);
774 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
775 		error = copyin(p->image, image, icount);
776 		if (error)
777 			return error;
778 		error = copyin(p->mask, mask, icount);
779 		if (error)
780 			return error;
781 	}
782 
783 	s = spltty();
784 	if (v & WSDISPLAY_CURSOR_DOCUR)
785 		sc->sc_curenb = p->enable;
786 	if (v & WSDISPLAY_CURSOR_DOPOS)
787 		set_curpos(sc, &p->pos);
788 	if (v & WSDISPLAY_CURSOR_DOHOT)
789 		cc->cc_hot = p->hot;
790 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
791 		memcpy(&cc->cc_color[index], &r[index], count);
792 		memcpy(&cc->cc_color[index + 2], &g[index], count);
793 		memcpy(&cc->cc_color[index + 4], &b[index], count);
794 	}
795 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
796 		cc->cc_size = p->size;
797 		memset(cc->cc_image, 0, sizeof cc->cc_image);
798 		memcpy(cc->cc_image, image, icount);
799 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
800 		memcpy(cc->cc_mask, mask, icount);
801 	}
802 	sc->sc_changed |= v;
803 	splx(s);
804 
805 	return (0);
806 #undef cc
807 }
808 
809 static int
810 get_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
811 {
812 	return (EPASSTHROUGH); /* XXX */
813 }
814 
815 static void
816 set_curpos(struct sfbp_softc *sc, struct wsdisplay_curpos *curpos)
817 {
818 	struct rasops_info *ri = sc->sc_ri;
819 	int x = curpos->x, y = curpos->y;
820 
821 	if (y < 0)
822 		y = 0;
823 	else if (y > ri->ri_height)
824 		y = ri->ri_height;
825 	if (x < 0)
826 		x = 0;
827 	else if (x > ri->ri_width)
828 		x = ri->ri_width;
829 	sc->sc_cursor.cc_pos.x = x;
830 	sc->sc_cursor.cc_pos.y = y;
831 }
832 
833 static void
834 bt459visible(void *hw, int on)
835 {
836 	hw = (char *)hw + SFB_RAMDAC_OFFSET;
837 	SELECT(hw, BT459_IREG_CCR);
838 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
839 	tc_wmb();
840 }
841 
842 static void
843 sfbpvisible(void *hw, int on)
844 {
845 	/* XXX use SFBplus ASIC XX */
846 }
847 
848 static void
849 bt459locate(void *hw, struct hwcursor64 *cc)
850 {
851 	int x, y, s;
852 
853 	x = cc->cc_pos.x - cc->cc_hot.x;
854 	y = cc->cc_pos.y - cc->cc_hot.y;
855 	x += cc->cc_magic.x;
856 	y += cc->cc_magic.y;
857 
858 	hw = (char *)hw + SFB_RAMDAC_OFFSET;
859 
860 	s = spltty();
861 	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
862 	REG(hw, bt_reg) = x;		tc_wmb();
863 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
864 	REG(hw, bt_reg) = y;		tc_wmb();
865 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
866 	splx(s);
867 }
868 
869 static void
870 sfbplocate(void *hw, struct hwcursor64 *cc)
871 {
872 	int x, y;
873 
874 	x = cc->cc_pos.x - cc->cc_hot.x;
875 	y = cc->cc_pos.y - cc->cc_hot.y;
876 
877 	hw = (char *)hw + SFB_ASIC_OFFSET;
878 	*((uint32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
879 	tc_wmb();
880 }
881 
882 static void
883 bt459color(void *hw, uint8_t *cp)
884 {
885 
886 	hw = (char *)hw + SFB_RAMDAC_OFFSET;
887 
888 	SELECT(hw, BT459_IREG_CCOLOR_2);
889 	REG(hw, bt_reg) = cp[1]; tc_wmb();
890 	REG(hw, bt_reg) = cp[3]; tc_wmb();
891 	REG(hw, bt_reg) = cp[5]; tc_wmb();
892 
893 	REG(hw, bt_reg) = cp[0]; tc_wmb();
894 	REG(hw, bt_reg) = cp[2]; tc_wmb();
895 	REG(hw, bt_reg) = cp[4]; tc_wmb();
896 }
897 
898 static void
899 bt463color(void *hw, uint8_t *cp)
900 {
901 }
902 
903 static void
904 bt459shape(void *hw, struct wsdisplay_curpos *size, uint64_t *image)
905 {
906 	uint8_t *ip, *mp, img, msk;
907 	uint8_t u;
908 	int bcnt;
909 
910 	hw = (char *)hw + SFB_RAMDAC_OFFSET;
911 	ip = (uint8_t *)image;
912 	mp = (uint8_t *)(image + CURSOR_MAX_SIZE);
913 
914 	bcnt = 0;
915 	SELECT(hw, BT459_IREG_CRAM_BASE+0);
916 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
917 	while (bcnt < size->y * 16) {
918 		/* pad right half 32 pixel when smaller than 33 */
919 		if ((bcnt & 0x8) && size->x < 33) {
920 			REG(hw, bt_reg) = 0; tc_wmb();
921 			REG(hw, bt_reg) = 0; tc_wmb();
922 		}
923 		else {
924 			img = *ip++;
925 			msk = *mp++;
926 			img &= msk;	/* cookie off image */
927 			u = (msk & 0x0f) << 4 | (img & 0x0f);
928 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
929 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
930 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
931 		}
932 		bcnt += 2;
933 	}
934 	/* pad unoccupied scan lines */
935 	while (bcnt < CURSOR_MAX_SIZE * 16) {
936 		REG(hw, bt_reg) = 0; tc_wmb();
937 		REG(hw, bt_reg) = 0; tc_wmb();
938 		bcnt += 2;
939 	}
940 }
941 
942 static void
943 sfbpshape(void *hw, struct wsdisplay_curpos *size, uint64_t *image)
944 {
945 	/* XXX use SFBplus ASIC XXX */
946 }
947 
948 static void
949 bt459setlut(void *hw, struct hwcmap256 *cm)
950 {
951 	int index;
952 
953 	hw = (char *)hw + SFB_RAMDAC_OFFSET;
954 	SELECT(hw, 0);
955 	for (index = 0; index < CMAP_SIZE; index++) {
956 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
957 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
958 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
959 	}
960 }
961 
962 static void
963 noplut(void *hw, struct hwcmap256 *cm)
964 {
965 }
966 
967 #define SFBBPP 32
968 
969 #define	MODE_SIMPLE		0
970 #define	MODE_OPAQUESTIPPLE	1
971 #define	MODE_OPAQUELINE		2
972 #define	MODE_TRANSPARENTSTIPPLE	5
973 #define	MODE_TRANSPARENTLINE	6
974 #define	MODE_COPY		7
975 
976 #if SFBBPP == 8
977 /* parameters for 8bpp configuration */
978 #define	SFBALIGNMASK		0x7
979 #define	SFBPIXELBYTES		1
980 #define	SFBSTIPPLEALL1		0xffffffff
981 #define	SFBSTIPPLEBITS		32
982 #define	SFBSTIPPLEBITMASK	0x1f
983 #define	SFBSTIPPLEBYTESDONE	32
984 #define	SFBCOPYALL1		0xffffffff
985 #define	SFBCOPYBITS		32
986 #define	SFBCOPYBITMASK		0x1f
987 #define	SFBCOPYBYTESDONE	32
988 
989 #elif SFBBPP == 32
990 /* parameters for 32bpp configuration */
991 #define	SFBALIGNMASK		0x7
992 #define	SFBPIXELBYTES		4
993 #define	SFBSTIPPLEALL1		0x0000ffff
994 #define	SFBSTIPPLEBITS		16
995 #define	SFBSTIPPLEBITMASK	0xf
996 #define	SFBSTIPPLEBYTESDONE	32
997 #define	SFBCOPYALL1		0x000000ff
998 #define	SFBCOPYBITS		8
999 #define	SFBCOPYBITMASK		0x3
1000 #define	SFBCOPYBYTESDONE	32
1001 #endif
1002 
1003 #ifdef pmax
1004 #define	WRITE_MB()
1005 #define	BUMP(p) (p)
1006 #endif
1007 
1008 #ifdef alpha
1009 #define	WRITE_MB() tc_wmb()
1010 /* registers is replicated in 1KB stride; rap round 4th iteration */
1011 #define	BUMP(p) ((p) = (void *)(((long)(p) + 0x400) & ~0x1000))
1012 #endif
1013 
1014 #define	SFBMODE(p, v) \
1015 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
1016 #define	SFBROP(p, v) \
1017 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
1018 #define	SFBPLANEMASK(p, v) \
1019 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
1020 #define	SFBPIXELMASK(p, v) \
1021 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
1022 #define	SFBADDRESS(p, v) \
1023 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
1024 #define	SFBSTART(p, v) \
1025 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
1026 #define	SFBPIXELSHIFT(p, v) \
1027 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
1028 #define	SFBFG(p, v) \
1029 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
1030 #define	SFBBG(p, v) \
1031 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
1032 #define	SFBBCONT(p, v) \
1033 		(*(uint32_t *)(BUMP(p) + SFB_ASIC_BCONT) = (v))
1034 
1035 #define	SFBDATA(p, v) \
1036 		(*((uint32_t *)BUMP(p) + TGA_REG_GDAR) = (v))
1037 
1038 #define	SFBCOPY64BYTESDONE	8
1039 #define	SFBCOPY64BITS		64
1040 #define	SFBCOPY64SRC(p, v) \
1041 		(*((uint32_t *)BUMP(p) + TGA_REG_GCSR) = (long)(v))
1042 #define	SFBCOPY64DST(p, v) \
1043 		(*((uint32_t *)BUMP(p) + TGA_REG_GCDR) = (long)(v))
1044 
1045 /*
1046  * Actually write a string to the frame buffer.
1047  */
1048 static void
1049 sfbp_putchar(void *id, int row, int col, u_int uc, long attr)
1050 {
1051 	struct rasops_info *ri = id;
1052 	char *sfb, *p;
1053 	int scanspan, height, width, align, x, y;
1054 	uint32_t lmask, rmask, glyph;
1055 	uint8_t *g;
1056 
1057 	x = col * ri->ri_font->fontwidth;
1058 	y = row * ri->ri_font->fontheight;
1059 	scanspan = ri->ri_stride;
1060 	height = ri->ri_font->fontheight;
1061 	uc -= ri->ri_font->firstchar;
1062 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
1063 
1064 	p = ri->ri_bits + y * scanspan + x * SFBPIXELBYTES;
1065 	align = (long)p & SFBALIGNMASK;
1066 	p -= align;
1067 	align /= SFBPIXELBYTES;
1068 	width = ri->ri_font->fontwidth + align;
1069 	lmask = SFBSTIPPLEALL1 << align;
1070 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1071 	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1072 
1073 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
1074 	SFBPLANEMASK(sfb, ~0);
1075 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
1076 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1077 	SFBROP(sfb, (3 << 8) | 3); /* ROP_COPY24 */
1078 	*((uint32_t *)sfb + TGA_REG_GPXR_P) = lmask & rmask;
1079 
1080 	/* XXX 2B stride fonts only XXX */
1081 	while (height > 0) {
1082 		glyph = *(uint16_t *)g;			/* XXX */
1083 		*(uint32_t *)p = glyph << align;
1084 		p += scanspan;
1085 		g += 2;					/* XXX */
1086 		height--;
1087 	}
1088 	SFBMODE(sfb, MODE_SIMPLE);
1089 	*((uint32_t *)sfb + TGA_REG_GPXR_P) = ~0;
1090 }
1091 
1092 #undef	SFBSTIPPLEALL1
1093 #undef	SFBSTIPPLEBITS
1094 #undef	SFBSTIPPLEBITMASK
1095 #define	SFBSTIPPLEALL1		SFBCOPYALL1
1096 #define	SFBSTIPPLEBITS		SFBCOPYBITS
1097 #define	SFBSTIPPLEBITMASK	SFBCOPYBITMASK
1098 
1099 /*
1100  * Clear characters in a line.
1101  */
1102 static void
1103 sfbp_erasecols(void *id, int row, int startcol, int ncols, long attr)
1104 {
1105 	struct rasops_info *ri = id;
1106 	char *sfb, *p;
1107 	int scanspan, startx, height, width, align, w, y;
1108 	uint32_t lmask, rmask;
1109 
1110 	scanspan = ri->ri_stride;
1111 	y = row * ri->ri_font->fontheight;
1112 	startx = startcol * ri->ri_font->fontwidth;
1113 	height = ri->ri_font->fontheight;
1114 	w = ri->ri_font->fontwidth * ncols;
1115 
1116 	p = ri->ri_bits + y * scanspan + startx * SFBPIXELBYTES;
1117 	align = (long)p & SFBALIGNMASK;
1118 	align /= SFBPIXELBYTES;
1119 	p -= align;
1120 	width = w + align;
1121 	lmask = SFBSTIPPLEALL1 << align;
1122 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1123 	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1124 
1125 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1126 	SFBPLANEMASK(sfb, ~0);
1127 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1128 	if (width <= SFBSTIPPLEBITS) {
1129 		lmask = lmask & rmask;
1130 		while (height > 0) {
1131 			*(uint32_t *)p = lmask;
1132 			p += scanspan;
1133 			height--;
1134 		}
1135 	}
1136 	else {
1137 		char *q = p;
1138 		while (height > 0) {
1139 			*(uint32_t *)p = lmask;
1140 			WRITE_MB();
1141 			width -= 2 * SFBSTIPPLEBITS;
1142 			while (width > 0) {
1143 				p += SFBSTIPPLEBYTESDONE;
1144 				*(uint32_t *)p = SFBSTIPPLEALL1;
1145 				WRITE_MB();
1146 				width -= SFBSTIPPLEBITS;
1147 			}
1148 			p += SFBSTIPPLEBYTESDONE;
1149 			*(uint32_t *)p = rmask;
1150 			WRITE_MB();
1151 
1152 			p = (q += scanspan);
1153 			width = w + align;
1154 			height--;
1155 		}
1156 	}
1157 	SFBMODE(sfb, MODE_SIMPLE);
1158 }
1159 
1160 #if 1
1161 /*
1162  * Copy lines.
1163  */
1164 static void
1165 sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1166 {
1167 	struct rasops_info *ri = id;
1168 	char *sfb, *p;
1169 	int scanspan, offset, srcy, height, width, align, w;
1170 	uint32_t lmask, rmask;
1171 
1172 	scanspan = ri->ri_stride;
1173 	height = ri->ri_font->fontheight * nrows;
1174 	offset = (dstrow - srcrow) * ri->ri_yscale;
1175 	srcy = ri->ri_font->fontheight * srcrow;
1176 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1177 		scanspan = -scanspan;
1178 		srcy += height;
1179 	}
1180 
1181 	p = ri->ri_bits + srcy * ri->ri_stride;
1182 	align = (long)p & SFBALIGNMASK;
1183 	p -= align;
1184 	align /= SFBPIXELBYTES;
1185 	w = ri->ri_emuwidth;
1186 	width = w + align;
1187 	lmask = SFBCOPYALL1 << align;
1188 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1189 	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1190 
1191 	SFBMODE(sfb, MODE_COPY);
1192 	SFBPLANEMASK(sfb, ~0);
1193 	SFBPIXELSHIFT(sfb, 0);
1194 	if (width <= SFBCOPYBITS) {
1195 		/* never happens */;
1196 	}
1197 	else {
1198 		char *q = p;
1199 		while (height > 0) {
1200 			*(uint32_t *)p = lmask;
1201 			*(uint32_t *)(p + offset) = lmask;
1202 			width -= 2 * SFBCOPYBITS;
1203 			while (width > 0) {
1204 				p += SFBCOPYBYTESDONE;
1205 				*(uint32_t *)p = SFBCOPYALL1;
1206 				*(uint32_t *)(p + offset) = SFBCOPYALL1;
1207 				width -= SFBCOPYBITS;
1208 			}
1209 			p += SFBCOPYBYTESDONE;
1210 			*(uint32_t *)p = rmask;
1211 			*(uint32_t *)(p + offset) = rmask;
1212 
1213 			p = (q += scanspan);
1214 			width = w + align;
1215 			height--;
1216 		}
1217 	}
1218 	SFBMODE(sfb, MODE_SIMPLE);
1219 }
1220 
1221 #else
1222 
1223 
1224 static void
1225 sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1226 {
1227 	struct rasops_info *ri = id;
1228 	void *sfb, *p, *q;
1229 	int scanspan, offset, srcy, height, width, w, align;
1230 	uint32_t rmask, lmask;
1231 
1232 	scanspan = ri->ri_stride;
1233 	height = ri->ri_font->fontheight * nrows;
1234 	offset = (dstrow - srcrow) * ri->ri_yscale;
1235 	srcy = ri->ri_font->fontheight * srcrow;
1236 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1237 		scanspan = -scanspan;
1238 		srcy += height;
1239 	}
1240 
1241 	p = ri->ri_bits + srcy * ri->ri_stride;
1242 	align = (long)p & SFBALIGNMASK;
1243 	w = ri->ri_emuwidth;
1244 	width = w + align;
1245 	lmask = SFBCOPYALL1 << align;
1246 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1247 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1248 	q = p;
1249 
1250 	SFBMODE(sfb, MODE_COPY);
1251 	SFBPLANEMASK(sfb, ~0);
1252 	SFBPIXELSHIFT(sfb, 0);
1253 
1254 	if (width <= SFBCOPYBITS)
1255 		; /* never happens */
1256 	else if (width < SFBCOPY64BITS) {
1257 		; /* unlikely happens */
1258 
1259 	}
1260 	else {
1261 		while (height > 0) {
1262 			while (width >= SFBCOPY64BITS) {
1263 				SFBCOPY64SRC(sfb, *p);
1264 				SFBCOPY64DST(sfb, *p + offset);
1265 				p += SFBCOPY64BYTESDONE;
1266 				width -= SFBCOPY64BITS;
1267 			}
1268 			if (width >= SFBCOPYBITS) {
1269 				*(uint32_t *)p = SFBCOPYALL1;
1270 				*(uint32_t *)(p + offset) = SFBCOPYALL1;
1271 				p += SFBCOPYBYTESDONE;
1272 				width -= SFBCOPYBITS;
1273 			}
1274 			if (width > 0) {
1275 				*(uint32_t *)p = rmask;
1276 				*(uint32_t *)(p + offset) = rmask;
1277 			}
1278 
1279 			p = (q += scanspan);
1280 			width = w;
1281 			height--;
1282 		}
1283 	}
1284 	SFBMODE(sfb, MODE_SIMPLE);
1285 }
1286 #endif
1287 
1288 /*
1289  * Erase lines.
1290  */
1291 static void
1292 sfbp_eraserows(void *id, int startrow, int nrows, long attr)
1293 {
1294 	struct rasops_info *ri = id;
1295 	char *sfb, *p;
1296 	int scanspan, starty, height, width, align, w;
1297 	uint32_t lmask, rmask;
1298 
1299 	scanspan = ri->ri_stride;
1300 	starty = ri->ri_font->fontheight * startrow;
1301 	height = ri->ri_font->fontheight * nrows;
1302 
1303 	p = ri->ri_bits + starty * scanspan;
1304 	align = (long)p & SFBALIGNMASK;
1305 	p -= align;
1306 	align /= SFBPIXELBYTES;
1307 	w = ri->ri_emuwidth * SFBPIXELBYTES;
1308 	width = w + align;
1309 	lmask = SFBSTIPPLEALL1 << align;
1310 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1311 	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1312 
1313 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1314 	SFBPLANEMASK(sfb, ~0);
1315 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1316 	if (width <= SFBSTIPPLEBITS) {
1317 		/* never happens */;
1318 	}
1319 	else {
1320 		char *q = p;
1321 		while (height > 0) {
1322 			*(uint32_t *)p = lmask;
1323 			WRITE_MB();
1324 			width -= 2 * SFBSTIPPLEBITS;
1325 			while (width > 0) {
1326 				p += SFBSTIPPLEBYTESDONE;
1327 				*(uint32_t *)p = SFBSTIPPLEALL1;
1328 				WRITE_MB();
1329 				width -= SFBSTIPPLEBITS;
1330 			}
1331 			p += SFBSTIPPLEBYTESDONE;
1332 			*(uint32_t *)p = rmask;
1333 			WRITE_MB();
1334 
1335 			p = (q += scanspan);
1336 			width = w + align;
1337 			height--;
1338 		}
1339 	}
1340 	SFBMODE(sfb, MODE_SIMPLE);
1341 }
1342