xref: /netbsd/sys/dev/tc/sfb.c (revision c4a72b64)
1 /* $NetBSD: sfb.c,v 1.57 2002/10/02 16:53:05 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1998, 1999 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: sfb.c,v 1.57 2002/10/02 16:53:05 thorpej 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/tc/sfbreg.h>
56 
57 #include <uvm/uvm_extern.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 /*
68  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
69  * obscure register layout such as 2nd and 3rd Bt459 registers are
70  * adjacent each other in a word, i.e.,
71  *	struct bt459triplet {
72  * 		struct {
73  *			u_int8_t u0;
74  *			u_int8_t u1;
75  *			u_int8_t u2;
76  *			unsigned :8;
77  *		} bt_lo;
78  *
79  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
80  *	struct bt459reg {
81  *		   u_int32_t	   bt_lo;
82  *		   u_int32_t	   bt_hi;
83  *		   u_int32_t	   bt_reg;
84  *		   u_int32_t	   bt_cmap;
85  *	};
86  */
87 
88 /* Bt459 hardware registers */
89 #define	bt_lo	0
90 #define	bt_hi	1
91 #define	bt_reg	2
92 #define	bt_cmap 3
93 
94 #define	REG(base, index)	*((u_int32_t *)(base) + (index))
95 #define	SELECT(vdac, regno) do {			\
96 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
97 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
98 	tc_wmb();					\
99    } while (0)
100 
101 struct hwcmap256 {
102 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
103 	u_int8_t r[CMAP_SIZE];
104 	u_int8_t g[CMAP_SIZE];
105 	u_int8_t b[CMAP_SIZE];
106 };
107 
108 struct hwcursor64 {
109 	struct wsdisplay_curpos cc_pos;
110 	struct wsdisplay_curpos cc_hot;
111 	struct wsdisplay_curpos cc_size;
112 	struct wsdisplay_curpos cc_magic;
113 #define	CURSOR_MAX_SIZE	64
114 	u_int8_t cc_color[6];
115 	u_int64_t cc_image[64 + 64];
116 };
117 
118 struct sfb_softc {
119 	struct device sc_dev;
120 	vaddr_t sc_vaddr;
121 	size_t sc_size;
122 	struct rasops_info *sc_ri;
123 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
124 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
125 	int sc_blanked;			/* video visibility disabled */
126 	int sc_curenb;			/* cursor sprite enabled */
127 	int sc_changed;			/* need update of hardware */
128 #define	WSDISPLAY_CMAP_DOLUT	0x20
129 	int nscreens;
130 };
131 
132 #define	HX_MAGIC_X	368
133 #define	HX_MAGIC_Y	38
134 
135 static int  sfbmatch __P((struct device *, struct cfdata *, void *));
136 static void sfbattach __P((struct device *, struct device *, void *));
137 
138 CFATTACH_DECL(sfb, sizeof(struct sfb_softc),
139     sfbmatch, sfbattach, NULL, NULL);
140 
141 static void sfb_common_init __P((struct rasops_info *));
142 static struct rasops_info sfb_console_ri;
143 static tc_addr_t sfb_consaddr;
144 
145 static void sfb_putchar __P((void *, int, int, u_int, long));
146 static void sfb_erasecols __P((void *, int, int, int, long));
147 static void sfb_eraserows __P((void *, int, int, long));
148 static void sfb_copyrows __P((void *, int, int, int));
149 static void sfb_do_cursor __P((struct rasops_info *));
150 #if 0
151 static void sfb_copycols __P((void *, int, int, int, int));
152 #endif
153 
154 static struct wsscreen_descr sfb_stdscreen = {
155 	"std", 0, 0,
156 	0, /* textops */
157 	0, 0,
158 	WSSCREEN_REVERSE
159 };
160 
161 static const struct wsscreen_descr *_sfb_scrlist[] = {
162 	&sfb_stdscreen,
163 };
164 
165 static const struct wsscreen_list sfb_screenlist = {
166 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
167 };
168 
169 static int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
170 static paddr_t	sfbmmap __P((void *, off_t, int));
171 
172 static int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
173 				      void **, int *, int *, long *));
174 static void	sfb_free_screen __P((void *, void *));
175 static int	sfb_show_screen __P((void *, void *, int,
176 				     void (*) (void *, int, int), void *));
177 
178 static const struct wsdisplay_accessops sfb_accessops = {
179 	sfbioctl,
180 	sfbmmap,
181 	sfb_alloc_screen,
182 	sfb_free_screen,
183 	sfb_show_screen,
184 	0 /* load_font */
185 };
186 
187 int  sfb_cnattach __P((tc_addr_t));
188 static int  sfbintr __P((void *));
189 static void sfbhwinit __P((caddr_t));
190 
191 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
192 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
193 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
194 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
195 static void set_curpos __P((struct sfb_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 sfbmatch(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("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
248 		return (0);
249 	return (1);
250 }
251 
252 static void
253 sfbattach(parent, self, aux)
254 	struct device *parent, *self;
255 	void *aux;
256 {
257 	struct sfb_softc *sc = (struct sfb_softc *)self;
258 	struct tc_attach_args *ta = aux;
259 	struct rasops_info *ri;
260 	struct wsemuldisplaydev_attach_args waa;
261 	struct hwcmap256 *cm;
262 	const u_int8_t *p;
263 	caddr_t asic;
264 	int console, index;
265 
266 	console = (ta->ta_addr == sfb_consaddr);
267 	if (console) {
268 		sc->sc_ri = ri = &sfb_console_ri;
269 		sc->nscreens = 1;
270 	}
271 	else {
272 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
273 			M_DEVBUF, M_NOWAIT);
274 		if (ri == NULL) {
275 			printf(": can't alloc memory\n");
276 			return;
277 		}
278 		memset(ri, 0, sizeof(struct rasops_info));
279 
280 		ri->ri_hw = (void *)ta->ta_addr;
281 		sfb_common_init(ri);
282 		sc->sc_ri = ri;
283 	}
284 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
285 
286 	cm = &sc->sc_cmap;
287 	p = rasops_cmap;
288 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
289 		cm->r[index] = p[0];
290 		cm->g[index] = p[1];
291 		cm->b[index] = p[2];
292 	}
293 
294 	sc->sc_vaddr = ta->ta_addr;
295 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
296 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
297 	sc->sc_blanked = sc->sc_curenb = 0;
298 
299 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
300 
301 	asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
302 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
303 	*(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
304 
305 	waa.console = console;
306 	waa.scrdata = &sfb_screenlist;
307 	waa.accessops = &sfb_accessops;
308 	waa.accesscookie = sc;
309 
310 	config_found(self, &waa, wsemuldisplaydevprint);
311 }
312 
313 static void
314 sfb_common_init(ri)
315 	struct rasops_info *ri;
316 {
317 	caddr_t base, asic;
318 	int hsetup, vsetup, vbase, cookie;
319 
320 	base = (caddr_t)ri->ri_hw;
321 	asic = base + SFB_ASIC_OFFSET;
322 	hsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
323 	vsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
324 
325 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
326 	*(u_int32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
327 	*(u_int32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
328 	*(u_int32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
329 	*(u_int32_t *)(asic + SFB_ASIC_ROP) = 3; 	/* ROP_COPY */
330 	*(u_int32_t *)(asic + 0x180000) = 0; 		/* Bt459 reset */
331 
332 	/* initialize colormap and cursor hardware */
333 	sfbhwinit(base);
334 
335 	ri->ri_flg = RI_CENTER;
336 	ri->ri_depth = 8;
337 	ri->ri_width = (hsetup & 0x1ff) << 2;
338 	ri->ri_height = (vsetup & 0x7ff);
339 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
340 	ri->ri_bits = base + SFB_FB_OFFSET + vbase * 4096;
341 
342 	/* clear the screen */
343 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
344 
345 	wsfont_init();
346 	/* prefer 12 pixel wide font */
347 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
348 	    WSDISPLAY_FONTORDER_L2R);
349 	if (cookie <= 0)
350 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
351 		    WSDISPLAY_FONTORDER_L2R);
352 	if (cookie <= 0) {
353 		printf("sfb: font table is empty\n");
354 		return;
355 	}
356 
357 	/* the accelerated sfb_putchar() needs LSbit left */
358 	if (wsfont_lock(cookie, &ri->ri_font)) {
359 		printf("sfb: couldn't lock font\n");
360 		return;
361 	}
362 	ri->ri_wsfcookie = cookie;
363 
364 	rasops_init(ri, 34, 80);
365 
366 	/* add our accelerated functions */
367 	ri->ri_ops.putchar = sfb_putchar;
368 	ri->ri_ops.erasecols = sfb_erasecols;
369 	ri->ri_ops.copyrows = sfb_copyrows;
370 	ri->ri_ops.eraserows = sfb_eraserows;
371 	ri->ri_do_cursor = sfb_do_cursor;
372 
373 	/* XXX shouldn't be global */
374 	sfb_stdscreen.nrows = ri->ri_rows;
375 	sfb_stdscreen.ncols = ri->ri_cols;
376 	sfb_stdscreen.textops = &ri->ri_ops;
377 	sfb_stdscreen.capabilities = ri->ri_caps;
378 }
379 
380 static int
381 sfbioctl(v, cmd, data, flag, p)
382 	void *v;
383 	u_long cmd;
384 	caddr_t data;
385 	int flag;
386 	struct proc *p;
387 {
388 	struct sfb_softc *sc = v;
389 	struct rasops_info *ri = sc->sc_ri;
390 	int turnoff;
391 
392 	switch (cmd) {
393 	case WSDISPLAYIO_GTYPE:
394 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
395 		return (0);
396 
397 	case WSDISPLAYIO_GINFO:
398 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
399 		wsd_fbip->height = ri->ri_height;
400 		wsd_fbip->width = ri->ri_width;
401 		wsd_fbip->depth = ri->ri_depth;
402 		wsd_fbip->cmsize = CMAP_SIZE;
403 #undef fbt
404 		return (0);
405 
406 	case WSDISPLAYIO_GETCMAP:
407 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
408 
409 	case WSDISPLAYIO_PUTCMAP:
410 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
411 
412 	case WSDISPLAYIO_SVIDEO:
413 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
414 		if (sc->sc_blanked ^ turnoff) {
415 			caddr_t asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
416 			*(u_int32_t *)(asic + SFB_ASIC_VIDEO_VALID)
417 				= !turnoff;
418 			tc_wmb();
419 			sc->sc_blanked = turnoff;
420 		}
421 		return (0);
422 
423 	case WSDISPLAYIO_GVIDEO:
424 		*(u_int *)data = sc->sc_blanked ?
425 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
426 		return (0);
427 
428 	case WSDISPLAYIO_GCURPOS:
429 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
430 		return (0);
431 
432 	case WSDISPLAYIO_SCURPOS:
433 		set_curpos(sc, (struct wsdisplay_curpos *)data);
434 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
435 		return (0);
436 
437 	case WSDISPLAYIO_GCURMAX:
438 		((struct wsdisplay_curpos *)data)->x =
439 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
440 		return (0);
441 
442 	case WSDISPLAYIO_GCURSOR:
443 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
444 
445 	case WSDISPLAYIO_SCURSOR:
446 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
447 	}
448 	return (EPASSTHROUGH);
449 }
450 
451 static paddr_t
452 sfbmmap(v, offset, prot)
453 	void *v;
454 	off_t offset;
455 	int prot;
456 {
457 	struct sfb_softc *sc = v;
458 
459 	if (offset >= SFB_SIZE || offset < 0)
460 		return (-1);
461 	return machine_btop(sc->sc_vaddr + offset);
462 }
463 
464 static int
465 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
466 	void *v;
467 	const struct wsscreen_descr *type;
468 	void **cookiep;
469 	int *curxp, *curyp;
470 	long *attrp;
471 {
472 	struct sfb_softc *sc = v;
473 	struct rasops_info *ri = sc->sc_ri;
474 	long defattr;
475 
476 	if (sc->nscreens > 0)
477 		return (ENOMEM);
478 
479 	*cookiep = ri;	 /* one and only for now */
480 	*curxp = 0;
481 	*curyp = 0;
482 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
483 	*attrp = defattr;
484 	sc->nscreens++;
485 	return (0);
486 }
487 
488 static void
489 sfb_free_screen(v, cookie)
490 	void *v;
491 	void *cookie;
492 {
493 	struct sfb_softc *sc = v;
494 
495 	if (sc->sc_ri == &sfb_console_ri)
496 		panic("sfb_free_screen: console");
497 
498 	sc->nscreens--;
499 }
500 
501 static int
502 sfb_show_screen(v, cookie, waitok, cb, cbarg)
503 	void *v;
504 	void *cookie;
505 	int waitok;
506 	void (*cb) __P((void *, int, int));
507 	void *cbarg;
508 {
509 
510 	return (0);
511 }
512 
513 /* EXPORT */ int
514 sfb_cnattach(addr)
515 	tc_addr_t addr;
516 {
517 	struct rasops_info *ri;
518 	long defattr;
519 
520 	ri = &sfb_console_ri;
521 	ri->ri_hw = (void *)addr;
522 	sfb_common_init(ri);
523 	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
524 	wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
525 	sfb_consaddr = addr;
526 	return (0);
527 }
528 
529 static int
530 sfbintr(arg)
531 	void *arg;
532 {
533 	struct sfb_softc *sc = arg;
534 	caddr_t base, asic, vdac;
535 	int v;
536 
537 	base = (caddr_t)sc->sc_ri->ri_hw;
538 	asic = base + SFB_ASIC_OFFSET;
539 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
540 	/* *(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1; */
541 
542 	if (sc->sc_changed == 0)
543 		goto done;
544 
545 	vdac = base + SFB_RAMDAC_OFFSET;
546 	v = sc->sc_changed;
547 	if (v & WSDISPLAY_CURSOR_DOCUR) {
548 		SELECT(vdac, BT459_IREG_CCR);
549 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
550 	}
551 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
552 		int x, y;
553 
554 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
555 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
556 		x += sc->sc_cursor.cc_magic.x;
557 		y += sc->sc_cursor.cc_magic.y;
558 
559 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
560 		REG(vdac, bt_reg) = x;		tc_wmb();
561 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
562 		REG(vdac, bt_reg) = y;		tc_wmb();
563 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
564 	}
565 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
566 		u_int8_t *cp = sc->sc_cursor.cc_color;
567 
568 		SELECT(vdac, BT459_IREG_CCOLOR_2);
569 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
570 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
571 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
572 
573 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
574 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
575 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
576 	}
577 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
578 		u_int8_t *ip, *mp, img, msk;
579 		u_int8_t u;
580 		int bcnt;
581 
582 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
583 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
584 
585 		bcnt = 0;
586 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
587 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
588 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
589 			/* pad right half 32 pixel when smaller than 33 */
590 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
591 				REG(vdac, bt_reg) = 0; tc_wmb();
592 				REG(vdac, bt_reg) = 0; tc_wmb();
593 			}
594 			else {
595 				img = *ip++;
596 				msk = *mp++;
597 				img &= msk;	/* cookie off image */
598 				u = (msk & 0x0f) << 4 | (img & 0x0f);
599 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
600 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
601 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
602 			}
603 			bcnt += 2;
604 		}
605 		/* pad unoccupied scan lines */
606 		while (bcnt < CURSOR_MAX_SIZE * 16) {
607 			REG(vdac, bt_reg) = 0; tc_wmb();
608 			REG(vdac, bt_reg) = 0; tc_wmb();
609 			bcnt += 2;
610 		}
611 	}
612 	if (v & WSDISPLAY_CMAP_DOLUT) {
613 		struct hwcmap256 *cm = &sc->sc_cmap;
614 		int index;
615 
616 		SELECT(vdac, 0);
617 		for (index = 0; index < CMAP_SIZE; index++) {
618 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
619 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
620 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
621 		}
622 	}
623 	sc->sc_changed = 0;
624 done:
625 	return (1);
626 }
627 
628 static void
629 sfbhwinit(base)
630 	caddr_t base;
631 {
632 	caddr_t vdac = base + SFB_RAMDAC_OFFSET;
633 	const u_int8_t *p;
634 	int i;
635 
636 	SELECT(vdac, BT459_IREG_COMMAND_0);
637 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
638 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
639 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
640 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
641 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
642 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
643 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
644 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
645 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
646 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
647 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
648 
649 	SELECT(vdac, BT459_IREG_CCR);
650 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
651 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
652 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
653 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
654 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
655 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
656 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
657 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
658 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
659 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
660 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
661 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
662 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
663 
664 	/* build sane colormap */
665 	SELECT(vdac, 0);
666 	p = rasops_cmap;
667 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
668 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
669 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
670 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
671 	}
672 
673 	/* clear out cursor image */
674 	SELECT(vdac, BT459_IREG_CRAM_BASE);
675 	for (i = 0; i < 1024; i++)
676 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
677 
678 	/*
679 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
680 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
681 	 * image color.  CCOLOR_1 will be never used.
682 	 */
683 	SELECT(vdac, BT459_IREG_CCOLOR_1);
684 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
685 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
686 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
687 
688 	REG(vdac, bt_reg) = 0;		tc_wmb();
689 	REG(vdac, bt_reg) = 0;		tc_wmb();
690 	REG(vdac, bt_reg) = 0;		tc_wmb();
691 
692 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
693 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
694 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
695 }
696 
697 static int
698 get_cmap(sc, p)
699 	struct sfb_softc *sc;
700 	struct wsdisplay_cmap *p;
701 {
702 	u_int index = p->index, count = p->count;
703 
704 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
705 		return (EINVAL);
706 
707 	if (!uvm_useracc(p->red, count, B_WRITE) ||
708 	    !uvm_useracc(p->green, count, B_WRITE) ||
709 	    !uvm_useracc(p->blue, count, B_WRITE))
710 		return (EFAULT);
711 
712 	copyout(&sc->sc_cmap.r[index], p->red, count);
713 	copyout(&sc->sc_cmap.g[index], p->green, count);
714 	copyout(&sc->sc_cmap.b[index], p->blue, count);
715 
716 	return (0);
717 }
718 
719 static int
720 set_cmap(sc, p)
721 	struct sfb_softc *sc;
722 	struct wsdisplay_cmap *p;
723 {
724 	u_int index = p->index, count = p->count;
725 
726 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
727 		return (EINVAL);
728 
729 	if (!uvm_useracc(p->red, count, B_READ) ||
730 	    !uvm_useracc(p->green, count, B_READ) ||
731 	    !uvm_useracc(p->blue, count, B_READ))
732 		return (EFAULT);
733 
734 	copyin(p->red, &sc->sc_cmap.r[index], count);
735 	copyin(p->green, &sc->sc_cmap.g[index], count);
736 	copyin(p->blue, &sc->sc_cmap.b[index], count);
737 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
738 	return (0);
739 }
740 
741 static int
742 set_cursor(sc, p)
743 	struct sfb_softc *sc;
744 	struct wsdisplay_cursor *p;
745 {
746 #define	cc (&sc->sc_cursor)
747 	u_int v, index, count, icount;
748 
749 	v = p->which;
750 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
751 		index = p->cmap.index;
752 		count = p->cmap.count;
753 		if (index >= 2 || (index + count) > 2)
754 			return (EINVAL);
755 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
756 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
757 		    !uvm_useracc(p->cmap.blue, count, B_READ))
758 			return (EFAULT);
759 	}
760 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
761 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
762 			return (EINVAL);
763 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
764 		if (!uvm_useracc(p->image, icount, B_READ) ||
765 		    !uvm_useracc(p->mask, icount, B_READ))
766 			return (EFAULT);
767 	}
768 
769 	if (v & WSDISPLAY_CURSOR_DOCUR)
770 		sc->sc_curenb = p->enable;
771 	if (v & WSDISPLAY_CURSOR_DOPOS)
772 		set_curpos(sc, &p->pos);
773 	if (v & WSDISPLAY_CURSOR_DOHOT)
774 		cc->cc_hot = p->hot;
775 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
776 		copyin(p->cmap.red, &cc->cc_color[index], count);
777 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
778 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
779 	}
780 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
781 		cc->cc_size = p->size;
782 		memset(cc->cc_image, 0, sizeof cc->cc_image);
783 		copyin(p->image, cc->cc_image, icount);
784 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
785 	}
786 	sc->sc_changed |= v;
787 
788 	return (0);
789 #undef cc
790 }
791 
792 static int
793 get_cursor(sc, p)
794 	struct sfb_softc *sc;
795 	struct wsdisplay_cursor *p;
796 {
797 
798 	return (EPASSTHROUGH); /* XXX */
799 }
800 
801 static void
802 set_curpos(sc, curpos)
803 	struct sfb_softc *sc;
804 	struct wsdisplay_curpos *curpos;
805 {
806 	struct rasops_info *ri = sc->sc_ri;
807 	int x = curpos->x, y = curpos->y;
808 
809 	if (y < 0)
810 		y = 0;
811 	else if (y > ri->ri_height);
812 		y = ri->ri_height;
813 	if (x < 0)
814 		x = 0;
815 	else if (x > ri->ri_width);
816 		x = ri->ri_width;
817 	sc->sc_cursor.cc_pos.x = x;
818 	sc->sc_cursor.cc_pos.y = y;
819 }
820 
821 #define	MODE_SIMPLE		0
822 #define	MODE_OPAQUESTIPPLE	1
823 #define	MODE_OPAQUELINE		2
824 #define	MODE_TRANSPARENTSTIPPLE	5
825 #define	MODE_TRANSPARENTLINE	6
826 #define	MODE_COPY		7
827 
828 /* parameters for 8bpp configuration */
829 #define	SFBALIGNMASK		0x7
830 #define	SFBSTIPPLEALL1		0xffffffff
831 #define	SFBSTIPPLEBITS		32
832 #define	SFBSTIPPLEBITMASK	0x1f
833 #define	SFBSTIPPLEBYTESDONE	32
834 #define	SFBCOPYALL1		0xffffffff
835 #define	SFBCOPYBITS		32
836 #define	SFBCOPYBITMASK		0x1f
837 #define	SFBCOPYBYTESDONE	32
838 
839 #if defined(pmax)
840 #define	WRITE_MB()
841 #define	BUMP(p) (p)
842 #endif
843 
844 #if defined(alpha)
845 #define	WRITE_MB() tc_wmb()
846 /* SFB registers replicated in 128B stride; cycle after eight iterations */
847 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
848 #endif
849 
850 #define	SFBMODE(p, v) \
851 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
852 #define	SFBROP(p, v) \
853 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
854 #define	SFBPLANEMASK(p, v) \
855 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
856 #define	SFBPIXELMASK(p, v) \
857 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
858 #define	SFBADDRESS(p, v) \
859 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
860 #define	SFBSTART(p, v) \
861 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
862 #define	SFBPIXELSHIFT(p, v) \
863 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
864 #define	SFBFG(p, v) \
865 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
866 #define	SFBBG(p, v) \
867 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
868 
869 /*
870  * Paint the cursor.
871  */
872 static void
873 sfb_do_cursor(ri)
874 	struct rasops_info *ri;
875 {
876 	caddr_t sfb, p;
877 	int scanspan, height, width, align, x, y;
878 	u_int32_t lmask, rmask;
879 
880 	x = ri->ri_ccol * ri->ri_font->fontwidth;
881 	y = ri->ri_crow * ri->ri_font->fontheight;
882 	scanspan = ri->ri_stride;
883 	height = ri->ri_font->fontheight;
884 
885 	p = ri->ri_bits + y * scanspan + x;
886 	align = (long)p & SFBALIGNMASK;
887 	p -= align;
888 	width = ri->ri_font->fontwidth + align;
889 	lmask = SFBSTIPPLEALL1 << align;
890 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
891 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
892 
893 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
894 	SFBPLANEMASK(sfb, ~0);
895 	SFBROP(sfb, 6);  /* ROP_XOR */
896 	SFBFG(sfb, ~0);
897 
898 	lmask = lmask & rmask;
899 	while (height > 0) {
900 		SFBADDRESS(sfb, (long)p);
901 		SFBSTART(sfb, lmask);
902 		p += scanspan;
903 		height--;
904 	}
905 	SFBMODE(sfb, MODE_SIMPLE);
906 	SFBROP(sfb, 3); /* ROP_COPY */
907 }
908 
909 /*
910  * Paint a character.
911  */
912 static void
913 sfb_putchar(id, row, col, uc, attr)
914 	void *id;
915 	int row, col;
916 	u_int uc;
917 	long attr;
918 {
919 	struct rasops_info *ri = id;
920 	caddr_t sfb, p;
921 	int scanspan, height, width, align, x, y;
922 	u_int32_t lmask, rmask, glyph;
923 	u_int8_t *g;
924 
925 	x = col * ri->ri_font->fontwidth;
926 	y = row * ri->ri_font->fontheight;
927 	scanspan = ri->ri_stride;
928 	height = ri->ri_font->fontheight;
929 	uc -= ri->ri_font->firstchar;
930 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
931 
932 	p = ri->ri_bits + y * scanspan + x;
933 	align = (long)p & SFBALIGNMASK;
934 	p -= align;
935 	width = ri->ri_font->fontwidth + align;
936 	lmask = SFBSTIPPLEALL1 << align;
937 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
938 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
939 
940 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
941 	SFBPLANEMASK(sfb, ~0);
942 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
943 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
944 
945 	/* XXX 2B stride fonts only XXX */
946 	lmask = lmask & rmask;
947 	while (height > 0) {
948 		glyph = *(u_int16_t *)g;		/* XXX */
949 		SFBPIXELMASK(sfb, lmask);
950 		SFBADDRESS(sfb, (long)p);
951 		SFBSTART(sfb, glyph << align);
952 		p += scanspan;
953 		g += 2;					/* XXX */
954 		height--;
955 	}
956 	if (attr & 1 /* UNDERLINE */) {
957 		p -= scanspan * 2;
958 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
959 		SFBADDRESS(sfb, (long)p);
960 		SFBSTART(sfb, lmask);
961 	}
962 
963 	SFBMODE(sfb, MODE_SIMPLE);
964 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
965 }
966 
967 #if 0
968 /*
969  * Copy characters in a line.
970  */
971 static void
972 sfb_copycols(id, row, srccol, dstcol, ncols)
973 	void *id;
974 	int row, srccol, dstcol, ncols;
975 {
976 	struct rasops_info *ri = id;
977 	caddr_t sp, dp, basex, sfb;
978 	int scanspan, height, width, aligns, alignd, shift, w, y;
979 	u_int32_t lmaskd, rmaskd;
980 
981 	scanspan = ri->ri_stride;
982 	y = row * ri->ri_font->fontheight;
983 	basex = ri->ri_bits + y * scanspan;
984 	height = ri->ri_font->fontheight;
985 	w = ri->ri_font->fontwidth * ncols;
986 
987 	sp = basex + ri->ri_font->fontwidth * srccol;
988 	aligns = (long)sp & SFBALIGNMASK;
989 	dp = basex + ri->ri_font->fontwidth * dstcol;
990 	alignd = (long)dp & SFBALIGNMASK;
991 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
992 
993 	SFBMODE(sfb, MODE_COPY);
994 	SFBPLANEMASK(sfb, ~0);
995 	/* small enough to fit in a single 32bit */
996 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
997 		SFBPIXELSHIFT(sfb, alignd - aligns);
998 		lmaskd = SFBCOPYALL1 << alignd;
999 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
1000 		lmaskd = lmaskd & rmaskd;
1001 		sp -= aligns;
1002 		dp -= alignd;
1003 		while (height > 0) {
1004 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1005 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1006 			sp += scanspan;
1007 			dp += scanspan;
1008 			height--;
1009 		}
1010 	}
1011 	/* copy forward (left-to-right) */
1012 	else if (dstcol < srccol || srccol + ncols < dstcol) {
1013 		caddr_t sq, dq;
1014 
1015 		shift = alignd - aligns;
1016 		if (shift < 0) {
1017 			shift = 8 + shift;	/* enforce right rotate */
1018 			alignd += 8;		/* bearing on left edge */
1019 		}
1020 		width = alignd + w;
1021 		lmaskd = SFBCOPYALL1 << alignd;
1022 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1023 		sp -= aligns;
1024 		dp -= alignd;
1025 
1026 		SFBPIXELSHIFT(sfb, shift);
1027 		w = width;
1028 		sq = sp;
1029 		dq = dp;
1030 		while (height > 0) {
1031 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1032 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1033 			width -= 2 * SFBCOPYBITS;
1034 			while (width > 0) {
1035 				sp += SFBCOPYBYTESDONE;
1036 				dp += SFBCOPYBYTESDONE;
1037 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1038 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1039 				width -= SFBCOPYBITS;
1040 			}
1041 			sp += SFBCOPYBYTESDONE;
1042 			dp += SFBCOPYBYTESDONE;
1043 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1044 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1045 			sp = (sq += scanspan);
1046 			dp = (dq += scanspan);
1047 			width = w;
1048 			height--;
1049 		}
1050 	}
1051 	/* copy backward (right-to-left) */
1052 	else {
1053 		caddr_t sq, dq;
1054 
1055 		shift = alignd - aligns;
1056 		if (shift > 0) {
1057 			shift = shift - 8;	/* force left rotate */
1058 			alignd += 24;
1059 		}
1060 		width = alignd + w;
1061 		lmaskd = SFBCOPYALL1 << alignd;
1062 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1063 		sp -= aligns;
1064 		dp -= alignd;
1065 
1066 		SFBPIXELSHIFT(sfb, shift);
1067 		w = width;
1068 		sq = sp += (((aligns + w) - 1) & ~31);
1069 		dq = dp += (((alignd + w) - 1) & ~31);
1070 		while (height > 0) {
1071 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1072 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1073 			width -= 2 * SFBCOPYBITS;
1074 			while (width > 0) {
1075 				sp -= SFBCOPYBYTESDONE;
1076 				dp -= SFBCOPYBYTESDONE;
1077 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1078 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1079 				width -= SFBCOPYBITS;
1080 			}
1081 			sp -= SFBCOPYBYTESDONE;
1082 			dp -= SFBCOPYBYTESDONE;
1083 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1084 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1085 
1086 			sp = (sq += scanspan);
1087 			dp = (dq += scanspan);
1088 			width = w;
1089 			height--;
1090 		}
1091 	}
1092 	SFBMODE(sfb, MODE_SIMPLE);
1093 	SFBPIXELSHIFT(sfb, 0);
1094 }
1095 #endif
1096 
1097 /*
1098  * Clear characters in a line.
1099  */
1100 static void
1101 sfb_erasecols(id, row, startcol, ncols, attr)
1102 	void *id;
1103 	int row, startcol, ncols;
1104 	long attr;
1105 {
1106 	struct rasops_info *ri = id;
1107 	caddr_t sfb, p;
1108 	int scanspan, startx, height, width, align, w, y;
1109 	u_int32_t lmask, rmask;
1110 
1111 	scanspan = ri->ri_stride;
1112 	y = row * ri->ri_font->fontheight;
1113 	startx = startcol * ri->ri_font->fontwidth;
1114 	height = ri->ri_font->fontheight;
1115 	w = ri->ri_font->fontwidth * ncols;
1116 
1117 	p = ri->ri_bits + y * scanspan + startx;
1118 	align = (long)p & SFBALIGNMASK;
1119 	p -= align;
1120 	width = w + align;
1121 	lmask = SFBSTIPPLEALL1 << align;
1122 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1123 	sfb = (caddr_t)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 			SFBADDRESS(sfb, (long)p);
1132 			SFBSTART(sfb, lmask);
1133 			p += scanspan;
1134 			height--;
1135 		}
1136 	}
1137 	else {
1138 		caddr_t q = p;
1139 		while (height > 0) {
1140 			*(u_int32_t *)p = lmask;
1141 			WRITE_MB();
1142 			width -= 2 * SFBSTIPPLEBITS;
1143 			while (width > 0) {
1144 				p += SFBSTIPPLEBYTESDONE;
1145 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1146 				WRITE_MB();
1147 				width -= SFBSTIPPLEBITS;
1148 			}
1149 			p += SFBSTIPPLEBYTESDONE;
1150 			*(u_int32_t *)p = rmask;
1151 			WRITE_MB();
1152 
1153 			p = (q += scanspan);
1154 			width = w + align;
1155 			height--;
1156 		}
1157 	}
1158 	SFBMODE(sfb, MODE_SIMPLE);
1159 }
1160 
1161 /*
1162  * Copy lines.
1163  */
1164 static void
1165 sfb_copyrows(id, srcrow, dstrow, nrows)
1166 	void *id;
1167 	int srcrow, dstrow, nrows;
1168 {
1169 	struct rasops_info *ri = id;
1170 	caddr_t sfb, p;
1171 	int scanspan, offset, srcy, height, width, align, w;
1172 	u_int32_t lmask, rmask;
1173 
1174 	scanspan = ri->ri_stride;
1175 	height = ri->ri_font->fontheight * nrows;
1176 	offset = (dstrow - srcrow) * ri->ri_yscale;
1177 	srcy = ri->ri_font->fontheight * srcrow;
1178 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1179 		scanspan = -scanspan;
1180 		srcy += height;
1181 	}
1182 
1183 	p = ri->ri_bits + srcy * ri->ri_stride;
1184 	align = (long)p & SFBALIGNMASK;
1185 	p -= align;
1186 	w = ri->ri_emuwidth;
1187 	width = w + align;
1188 	lmask = SFBCOPYALL1 << align;
1189 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1190 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1191 
1192 	SFBMODE(sfb, MODE_COPY);
1193 	SFBPLANEMASK(sfb, ~0);
1194 	SFBPIXELSHIFT(sfb, 0);
1195 	if (width <= SFBCOPYBITS) {
1196 		/* never happens */;
1197 	}
1198 	else {
1199 		caddr_t q = p;
1200 		while (height > 0) {
1201 			*(u_int32_t *)p = lmask;
1202 			*(u_int32_t *)(p + offset) = lmask;
1203 			width -= 2 * SFBCOPYBITS;
1204 			while (width > 0) {
1205 				p += SFBCOPYBYTESDONE;
1206 				*(u_int32_t *)p = SFBCOPYALL1;
1207 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1208 				width -= SFBCOPYBITS;
1209 			}
1210 			p += SFBCOPYBYTESDONE;
1211 			*(u_int32_t *)p = rmask;
1212 			*(u_int32_t *)(p + offset) = rmask;
1213 
1214 			p = (q += scanspan);
1215 			width = w + align;
1216 			height--;
1217 		}
1218 	}
1219 	SFBMODE(sfb, MODE_SIMPLE);
1220 }
1221 
1222 /*
1223  * Erase lines.
1224  */
1225 void
1226 sfb_eraserows(id, startrow, nrows, attr)
1227 	void *id;
1228 	int startrow, nrows;
1229 	long attr;
1230 {
1231 	struct rasops_info *ri = id;
1232 	caddr_t sfb, p;
1233 	int scanspan, starty, height, width, align, w;
1234 	u_int32_t lmask, rmask;
1235 
1236 	scanspan = ri->ri_stride;
1237 	starty = ri->ri_font->fontheight * startrow;
1238 	height = ri->ri_font->fontheight * nrows;
1239 
1240 	p = ri->ri_bits + starty * scanspan;
1241 	align = (long)p & SFBALIGNMASK;
1242 	p -= align;
1243 	w = ri->ri_emuwidth;
1244 	width = w + align;
1245 	lmask = SFBSTIPPLEALL1 << align;
1246 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1247 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1248 
1249 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1250 	SFBPLANEMASK(sfb, ~0);
1251 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1252 	if (width <= SFBSTIPPLEBITS) {
1253 		/* never happens */;
1254 	}
1255 	else {
1256 		caddr_t q = p;
1257 		while (height > 0) {
1258 			*(u_int32_t *)p = lmask;
1259 			WRITE_MB();
1260 			width -= 2 * SFBSTIPPLEBITS;
1261 			while (width > 0) {
1262 				p += SFBSTIPPLEBYTESDONE;
1263 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1264 				WRITE_MB();
1265 				width -= SFBSTIPPLEBITS;
1266 			}
1267 			p += SFBSTIPPLEBYTESDONE;
1268 			*(u_int32_t *)p = rmask;
1269 			WRITE_MB();
1270 
1271 			p = (q += scanspan);
1272 			width = w + align;
1273 			height--;
1274 		}
1275 	}
1276 	SFBMODE(sfb, MODE_SIMPLE);
1277 }
1278