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