xref: /netbsd-src/sys/dev/tc/sfb.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /* $NetBSD: sfb.c,v 1.49 2001/11/13 06:26:10 lukem 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.49 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/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 const struct cfattach sfb_ca = {
139 	sizeof(struct sfb_softc), sfbmatch, sfbattach,
140 };
141 
142 static void sfb_common_init __P((struct rasops_info *));
143 static struct rasops_info sfb_console_ri;
144 static tc_addr_t sfb_consaddr;
145 
146 static void sfb_putchar __P((void *, int, int, u_int, long));
147 static void sfb_erasecols __P((void *, int, int, int, long));
148 static void sfb_eraserows __P((void *, int, int, long));
149 static void sfb_copyrows __P((void *, int, int, int));
150 static void sfb_do_cursor __P((struct rasops_info *));
151 #if 0
152 static void sfb_copycols __P((void *, int, int, int, int));
153 #endif
154 
155 static struct wsscreen_descr sfb_stdscreen = {
156 	"std", 0, 0,
157 	0, /* textops */
158 	0, 0,
159 	WSSCREEN_REVERSE
160 };
161 
162 static const struct wsscreen_descr *_sfb_scrlist[] = {
163 	&sfb_stdscreen,
164 };
165 
166 static const struct wsscreen_list sfb_screenlist = {
167 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
168 };
169 
170 static int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
171 static paddr_t	sfbmmap __P((void *, off_t, int));
172 
173 static int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
174 				      void **, int *, int *, long *));
175 static void	sfb_free_screen __P((void *, void *));
176 static int	sfb_show_screen __P((void *, void *, int,
177 				     void (*) (void *, int, int), void *));
178 
179 static const struct wsdisplay_accessops sfb_accessops = {
180 	sfbioctl,
181 	sfbmmap,
182 	sfb_alloc_screen,
183 	sfb_free_screen,
184 	sfb_show_screen,
185 	0 /* load_font */
186 };
187 
188 int  sfb_cnattach __P((tc_addr_t));
189 static int  sfbintr __P((void *));
190 static void sfbhwinit __P((caddr_t));
191 
192 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
193 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
194 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
195 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
196 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
197 
198 /*
199  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
200  *   M M M M I I I I		M I M I M I M I
201  *	[ before ]		   [ after ]
202  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
203  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
204  */
205 static const u_int8_t shuffle[256] = {
206 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
207 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
208 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
209 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
210 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
211 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
212 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
213 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
214 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
215 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
216 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
217 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
218 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
219 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
220 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
221 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
222 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
223 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
224 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
225 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
226 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
227 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
228 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
229 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
230 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
231 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
232 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
233 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
234 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
235 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
236 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
237 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
238 };
239 
240 static int
241 sfbmatch(parent, match, aux)
242 	struct device *parent;
243 	struct cfdata *match;
244 	void *aux;
245 {
246 	struct tc_attach_args *ta = aux;
247 
248 	if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
249 		return (0);
250 	return (1);
251 }
252 
253 static void
254 sfbattach(parent, self, aux)
255 	struct device *parent, *self;
256 	void *aux;
257 {
258 	struct sfb_softc *sc = (struct sfb_softc *)self;
259 	struct tc_attach_args *ta = aux;
260 	struct rasops_info *ri;
261 	struct wsemuldisplaydev_attach_args waa;
262 	struct hwcmap256 *cm;
263 	const u_int8_t *p;
264 	caddr_t asic;
265 	int console, index;
266 
267 	console = (ta->ta_addr == sfb_consaddr);
268 	if (console) {
269 		sc->sc_ri = ri = &sfb_console_ri;
270 		sc->nscreens = 1;
271 	}
272 	else {
273 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
274 			M_DEVBUF, M_NOWAIT);
275 		if (ri == NULL) {
276 			printf(": can't alloc memory\n");
277 			return;
278 		}
279 		memset(ri, 0, sizeof(struct rasops_info));
280 
281 		ri->ri_hw = (void *)ta->ta_addr;
282 		sfb_common_init(ri);
283 		sc->sc_ri = ri;
284 	}
285 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
286 
287 	cm = &sc->sc_cmap;
288 	p = rasops_cmap;
289 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
290 		cm->r[index] = p[0];
291 		cm->g[index] = p[1];
292 		cm->b[index] = p[2];
293 	}
294 
295 	sc->sc_vaddr = ta->ta_addr;
296 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
297 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
298 	sc->sc_blanked = sc->sc_curenb = 0;
299 
300 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
301 
302 	asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
303 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
304 	*(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
305 
306 	waa.console = console;
307 	waa.scrdata = &sfb_screenlist;
308 	waa.accessops = &sfb_accessops;
309 	waa.accesscookie = sc;
310 
311 	config_found(self, &waa, wsemuldisplaydevprint);
312 }
313 
314 static void
315 sfb_common_init(ri)
316 	struct rasops_info *ri;
317 {
318 	caddr_t base, asic;
319 	int hsetup, vsetup, vbase, cookie;
320 
321 	base = (caddr_t)ri->ri_hw;
322 	asic = base + SFB_ASIC_OFFSET;
323 	hsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
324 	vsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
325 
326 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
327 	*(u_int32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
328 	*(u_int32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
329 	*(u_int32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
330 	*(u_int32_t *)(asic + SFB_ASIC_ROP) = 3; 	/* ROP_COPY */
331 	*(u_int32_t *)(asic + 0x180000) = 0; 		/* Bt459 reset */
332 
333 	/* initialize colormap and cursor hardware */
334 	sfbhwinit(base);
335 
336 	ri->ri_flg = RI_CENTER;
337 	ri->ri_depth = 8;
338 	ri->ri_width = (hsetup & 0x1ff) << 2;
339 	ri->ri_height = (vsetup & 0x7ff);
340 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
341 	ri->ri_bits = base + SFB_FB_OFFSET + vbase * 4096;
342 
343 	/* clear the screen */
344 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
345 
346 	wsfont_init();
347 	/* prefer 12 pixel wide font */
348 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
349 		cookie = wsfont_find(NULL, 0, 0, 0);
350 	if (cookie <= 0) {
351 		printf("sfb: font table is empty\n");
352 		return;
353 	}
354 
355 	/* the accelerated sfb_putchar() needs LSbit left */
356 	if (wsfont_lock(cookie, &ri->ri_font,
357 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
358 		printf("sfb: couldn't lock font\n");
359 		return;
360 	}
361 	ri->ri_wsfcookie = cookie;
362 
363 	rasops_init(ri, 34, 80);
364 
365 	/* add our accelerated functions */
366 	ri->ri_ops.putchar = sfb_putchar;
367 	ri->ri_ops.erasecols = sfb_erasecols;
368 	ri->ri_ops.copyrows = sfb_copyrows;
369 	ri->ri_ops.eraserows = sfb_eraserows;
370 	ri->ri_do_cursor = sfb_do_cursor;
371 
372 	/* XXX shouldn't be global */
373 	sfb_stdscreen.nrows = ri->ri_rows;
374 	sfb_stdscreen.ncols = ri->ri_cols;
375 	sfb_stdscreen.textops = &ri->ri_ops;
376 	sfb_stdscreen.capabilities = ri->ri_caps;
377 }
378 
379 static int
380 sfbioctl(v, cmd, data, flag, p)
381 	void *v;
382 	u_long cmd;
383 	caddr_t data;
384 	int flag;
385 	struct proc *p;
386 {
387 	struct sfb_softc *sc = v;
388 	struct rasops_info *ri = sc->sc_ri;
389 	int turnoff;
390 
391 	switch (cmd) {
392 	case WSDISPLAYIO_GTYPE:
393 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
394 		return (0);
395 
396 	case WSDISPLAYIO_GINFO:
397 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
398 		wsd_fbip->height = ri->ri_height;
399 		wsd_fbip->width = ri->ri_width;
400 		wsd_fbip->depth = ri->ri_depth;
401 		wsd_fbip->cmsize = CMAP_SIZE;
402 #undef fbt
403 		return (0);
404 
405 	case WSDISPLAYIO_GETCMAP:
406 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
407 
408 	case WSDISPLAYIO_PUTCMAP:
409 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
410 
411 	case WSDISPLAYIO_SVIDEO:
412 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
413 		if (sc->sc_blanked ^ turnoff) {
414 			caddr_t asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
415 			*(u_int32_t *)(asic + SFB_ASIC_VIDEO_VALID)
416 				= !turnoff;
417 			tc_wmb();
418 			sc->sc_blanked = turnoff;
419 		}
420 		return (0);
421 
422 	case WSDISPLAYIO_GVIDEO:
423 		*(u_int *)data = sc->sc_blanked ?
424 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
425 		return (0);
426 
427 	case WSDISPLAYIO_GCURPOS:
428 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
429 		return (0);
430 
431 	case WSDISPLAYIO_SCURPOS:
432 		set_curpos(sc, (struct wsdisplay_curpos *)data);
433 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
434 		return (0);
435 
436 	case WSDISPLAYIO_GCURMAX:
437 		((struct wsdisplay_curpos *)data)->x =
438 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
439 		return (0);
440 
441 	case WSDISPLAYIO_GCURSOR:
442 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
443 
444 	case WSDISPLAYIO_SCURSOR:
445 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
446 	}
447 	return (ENOTTY);
448 }
449 
450 static paddr_t
451 sfbmmap(v, offset, prot)
452 	void *v;
453 	off_t offset;
454 	int prot;
455 {
456 	struct sfb_softc *sc = v;
457 
458 	if (offset >= SFB_SIZE || offset < 0)
459 		return (-1);
460 	return machine_btop(sc->sc_vaddr + offset);
461 }
462 
463 static int
464 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
465 	void *v;
466 	const struct wsscreen_descr *type;
467 	void **cookiep;
468 	int *curxp, *curyp;
469 	long *attrp;
470 {
471 	struct sfb_softc *sc = v;
472 	struct rasops_info *ri = sc->sc_ri;
473 	long defattr;
474 
475 	if (sc->nscreens > 0)
476 		return (ENOMEM);
477 
478 	*cookiep = ri;	 /* one and only for now */
479 	*curxp = 0;
480 	*curyp = 0;
481 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
482 	*attrp = defattr;
483 	sc->nscreens++;
484 	return (0);
485 }
486 
487 static void
488 sfb_free_screen(v, cookie)
489 	void *v;
490 	void *cookie;
491 {
492 	struct sfb_softc *sc = v;
493 
494 	if (sc->sc_ri == &sfb_console_ri)
495 		panic("sfb_free_screen: console");
496 
497 	sc->nscreens--;
498 }
499 
500 static int
501 sfb_show_screen(v, cookie, waitok, cb, cbarg)
502 	void *v;
503 	void *cookie;
504 	int waitok;
505 	void (*cb) __P((void *, int, int));
506 	void *cbarg;
507 {
508 
509 	return (0);
510 }
511 
512 /* EXPORT */ int
513 sfb_cnattach(addr)
514 	tc_addr_t addr;
515 {
516 	struct rasops_info *ri;
517 	long defattr;
518 
519 	ri = &sfb_console_ri;
520 	ri->ri_hw = (void *)addr;
521 	sfb_common_init(ri);
522 	(*ri->ri_ops.alloc_attr)(&ri, 0, 0, 0, &defattr);
523 	wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
524 	sfb_consaddr = addr;
525 	return (0);
526 }
527 
528 static int
529 sfbintr(arg)
530 	void *arg;
531 {
532 	struct sfb_softc *sc = arg;
533 	caddr_t base, asic, vdac;
534 	int v;
535 
536 	base = (caddr_t)sc->sc_ri->ri_hw;
537 	asic = base + SFB_ASIC_OFFSET;
538 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
539 	/* *(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1; */
540 
541 	if (sc->sc_changed == 0)
542 		goto done;
543 
544 	vdac = base + SFB_RAMDAC_OFFSET;
545 	v = sc->sc_changed;
546 	if (v & WSDISPLAY_CURSOR_DOCUR) {
547 		SELECT(vdac, BT459_IREG_CCR);
548 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
549 	}
550 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
551 		int x, y;
552 
553 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
554 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
555 		x += sc->sc_cursor.cc_magic.x;
556 		y += sc->sc_cursor.cc_magic.y;
557 
558 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
559 		REG(vdac, bt_reg) = x;		tc_wmb();
560 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
561 		REG(vdac, bt_reg) = y;		tc_wmb();
562 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
563 	}
564 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
565 		u_int8_t *cp = sc->sc_cursor.cc_color;
566 
567 		SELECT(vdac, BT459_IREG_CCOLOR_2);
568 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
569 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
570 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
571 
572 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
573 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
574 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
575 	}
576 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
577 		u_int8_t *ip, *mp, img, msk;
578 		u_int8_t u;
579 		int bcnt;
580 
581 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
582 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
583 
584 		bcnt = 0;
585 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
586 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
587 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
588 			/* pad right half 32 pixel when smaller than 33 */
589 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
590 				REG(vdac, bt_reg) = 0; tc_wmb();
591 				REG(vdac, bt_reg) = 0; tc_wmb();
592 			}
593 			else {
594 				img = *ip++;
595 				msk = *mp++;
596 				img &= msk;	/* cookie off image */
597 				u = (msk & 0x0f) << 4 | (img & 0x0f);
598 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
599 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
600 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
601 			}
602 			bcnt += 2;
603 		}
604 		/* pad unoccupied scan lines */
605 		while (bcnt < CURSOR_MAX_SIZE * 16) {
606 			REG(vdac, bt_reg) = 0; tc_wmb();
607 			REG(vdac, bt_reg) = 0; tc_wmb();
608 			bcnt += 2;
609 		}
610 	}
611 	if (v & WSDISPLAY_CMAP_DOLUT) {
612 		struct hwcmap256 *cm = &sc->sc_cmap;
613 		int index;
614 
615 		SELECT(vdac, 0);
616 		for (index = 0; index < CMAP_SIZE; index++) {
617 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
618 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
619 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
620 		}
621 	}
622 	sc->sc_changed = 0;
623 done:
624 	return (1);
625 }
626 
627 static void
628 sfbhwinit(base)
629 	caddr_t base;
630 {
631 	caddr_t vdac = base + SFB_RAMDAC_OFFSET;
632 	const u_int8_t *p;
633 	int i;
634 
635 	SELECT(vdac, BT459_IREG_COMMAND_0);
636 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
637 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
638 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
639 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
640 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
641 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
642 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
643 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
644 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
645 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
646 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
647 
648 	SELECT(vdac, BT459_IREG_CCR);
649 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
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 
663 	/* build sane colormap */
664 	SELECT(vdac, 0);
665 	p = rasops_cmap;
666 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
667 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
668 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
669 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
670 	}
671 
672 	/* clear out cursor image */
673 	SELECT(vdac, BT459_IREG_CRAM_BASE);
674 	for (i = 0; i < 1024; i++)
675 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
676 
677 	/*
678 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
679 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
680 	 * image color.  CCOLOR_1 will be never used.
681 	 */
682 	SELECT(vdac, BT459_IREG_CCOLOR_1);
683 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
684 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
685 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
686 
687 	REG(vdac, bt_reg) = 0;		tc_wmb();
688 	REG(vdac, bt_reg) = 0;		tc_wmb();
689 	REG(vdac, bt_reg) = 0;		tc_wmb();
690 
691 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
692 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
693 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
694 }
695 
696 static int
697 get_cmap(sc, p)
698 	struct sfb_softc *sc;
699 	struct wsdisplay_cmap *p;
700 {
701 	u_int index = p->index, count = p->count;
702 
703 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
704 		return (EINVAL);
705 
706 	if (!uvm_useracc(p->red, count, B_WRITE) ||
707 	    !uvm_useracc(p->green, count, B_WRITE) ||
708 	    !uvm_useracc(p->blue, count, B_WRITE))
709 		return (EFAULT);
710 
711 	copyout(&sc->sc_cmap.r[index], p->red, count);
712 	copyout(&sc->sc_cmap.g[index], p->green, count);
713 	copyout(&sc->sc_cmap.b[index], p->blue, count);
714 
715 	return (0);
716 }
717 
718 static int
719 set_cmap(sc, p)
720 	struct sfb_softc *sc;
721 	struct wsdisplay_cmap *p;
722 {
723 	u_int index = p->index, count = p->count;
724 
725 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
726 		return (EINVAL);
727 
728 	if (!uvm_useracc(p->red, count, B_READ) ||
729 	    !uvm_useracc(p->green, count, B_READ) ||
730 	    !uvm_useracc(p->blue, count, B_READ))
731 		return (EFAULT);
732 
733 	copyin(p->red, &sc->sc_cmap.r[index], count);
734 	copyin(p->green, &sc->sc_cmap.g[index], count);
735 	copyin(p->blue, &sc->sc_cmap.b[index], count);
736 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
737 	return (0);
738 }
739 
740 static int
741 set_cursor(sc, p)
742 	struct sfb_softc *sc;
743 	struct wsdisplay_cursor *p;
744 {
745 #define	cc (&sc->sc_cursor)
746 	u_int v, index, count, icount;
747 
748 	v = p->which;
749 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
750 		index = p->cmap.index;
751 		count = p->cmap.count;
752 		if (index >= 2 || (index + count) > 2)
753 			return (EINVAL);
754 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
755 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
756 		    !uvm_useracc(p->cmap.blue, count, B_READ))
757 			return (EFAULT);
758 	}
759 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
760 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
761 			return (EINVAL);
762 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
763 		if (!uvm_useracc(p->image, icount, B_READ) ||
764 		    !uvm_useracc(p->mask, icount, B_READ))
765 			return (EFAULT);
766 	}
767 
768 	if (v & WSDISPLAY_CURSOR_DOCUR)
769 		sc->sc_curenb = p->enable;
770 	if (v & WSDISPLAY_CURSOR_DOPOS)
771 		set_curpos(sc, &p->pos);
772 	if (v & WSDISPLAY_CURSOR_DOHOT)
773 		cc->cc_hot = p->hot;
774 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
775 		copyin(p->cmap.red, &cc->cc_color[index], count);
776 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
777 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
778 	}
779 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
780 		cc->cc_size = p->size;
781 		memset(cc->cc_image, 0, sizeof cc->cc_image);
782 		copyin(p->image, cc->cc_image, icount);
783 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
784 	}
785 	sc->sc_changed |= v;
786 
787 	return (0);
788 #undef cc
789 }
790 
791 static int
792 get_cursor(sc, p)
793 	struct sfb_softc *sc;
794 	struct wsdisplay_cursor *p;
795 {
796 
797 	return (ENOTTY); /* XXX */
798 }
799 
800 static void
801 set_curpos(sc, curpos)
802 	struct sfb_softc *sc;
803 	struct wsdisplay_curpos *curpos;
804 {
805 	struct rasops_info *ri = sc->sc_ri;
806 	int x = curpos->x, y = curpos->y;
807 
808 	if (y < 0)
809 		y = 0;
810 	else if (y > ri->ri_height);
811 		y = ri->ri_height;
812 	if (x < 0)
813 		x = 0;
814 	else if (x > ri->ri_width);
815 		x = ri->ri_width;
816 	sc->sc_cursor.cc_pos.x = x;
817 	sc->sc_cursor.cc_pos.y = y;
818 }
819 
820 #define	MODE_SIMPLE		0
821 #define	MODE_OPAQUESTIPPLE	1
822 #define	MODE_OPAQUELINE		2
823 #define	MODE_TRANSPARENTSTIPPLE	5
824 #define	MODE_TRANSPARENTLINE	6
825 #define	MODE_COPY		7
826 
827 /* parameters for 8bpp configuration */
828 #define	SFBALIGNMASK		0x7
829 #define	SFBSTIPPLEALL1		0xffffffff
830 #define	SFBSTIPPLEBITS		32
831 #define	SFBSTIPPLEBITMASK	0x1f
832 #define	SFBSTIPPLEBYTESDONE	32
833 #define	SFBCOPYALL1		0xffffffff
834 #define	SFBCOPYBITS		32
835 #define	SFBCOPYBITMASK		0x1f
836 #define	SFBCOPYBYTESDONE	32
837 
838 #if defined(pmax)
839 #define	WRITE_MB()
840 #define	BUMP(p) (p)
841 #endif
842 
843 #if defined(alpha)
844 #define	WRITE_MB() tc_wmb()
845 /* SFB registers replicated in 128B stride; cycle after eight iterations */
846 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
847 #endif
848 
849 #define	SFBMODE(p, v) \
850 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
851 #define	SFBROP(p, v) \
852 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
853 #define	SFBPLANEMASK(p, v) \
854 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
855 #define	SFBPIXELMASK(p, v) \
856 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
857 #define	SFBADDRESS(p, v) \
858 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
859 #define	SFBSTART(p, v) \
860 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
861 #define	SFBPIXELSHIFT(p, v) \
862 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
863 #define	SFBFG(p, v) \
864 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
865 #define	SFBBG(p, v) \
866 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
867 
868 /*
869  * Paint the cursor.
870  */
871 static void
872 sfb_do_cursor(ri)
873 	struct rasops_info *ri;
874 {
875 	caddr_t sfb, p;
876 	int scanspan, height, width, align, x, y;
877 	u_int32_t lmask, rmask;
878 
879 	x = ri->ri_ccol * ri->ri_font->fontwidth;
880 	y = ri->ri_crow * ri->ri_font->fontheight;
881 	scanspan = ri->ri_stride;
882 	height = ri->ri_font->fontheight;
883 
884 	p = ri->ri_bits + y * scanspan + x;
885 	align = (long)p & SFBALIGNMASK;
886 	p -= align;
887 	width = ri->ri_font->fontwidth + align;
888 	lmask = SFBSTIPPLEALL1 << align;
889 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
890 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
891 
892 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
893 	SFBPLANEMASK(sfb, ~0);
894 	SFBROP(sfb, 6);  /* ROP_XOR */
895 	SFBFG(sfb, ~0);
896 
897 	lmask = lmask & rmask;
898 	while (height > 0) {
899 		SFBADDRESS(sfb, (long)p);
900 		SFBSTART(sfb, lmask);
901 		p += scanspan;
902 		height--;
903 	}
904 	SFBMODE(sfb, MODE_SIMPLE);
905 	SFBROP(sfb, 3); /* ROP_COPY */
906 }
907 
908 /*
909  * Paint a character.
910  */
911 static void
912 sfb_putchar(id, row, col, uc, attr)
913 	void *id;
914 	int row, col;
915 	u_int uc;
916 	long attr;
917 {
918 	struct rasops_info *ri = id;
919 	caddr_t sfb, p;
920 	int scanspan, height, width, align, x, y;
921 	u_int32_t lmask, rmask, glyph;
922 	u_int8_t *g;
923 
924 	x = col * ri->ri_font->fontwidth;
925 	y = row * ri->ri_font->fontheight;
926 	scanspan = ri->ri_stride;
927 	height = ri->ri_font->fontheight;
928 	uc -= ri->ri_font->firstchar;
929 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
930 
931 	p = ri->ri_bits + y * scanspan + x;
932 	align = (long)p & SFBALIGNMASK;
933 	p -= align;
934 	width = ri->ri_font->fontwidth + align;
935 	lmask = SFBSTIPPLEALL1 << align;
936 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
937 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
938 
939 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
940 	SFBPLANEMASK(sfb, ~0);
941 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
942 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
943 
944 	/* XXX 2B stride fonts only XXX */
945 	lmask = lmask & rmask;
946 	while (height > 0) {
947 		glyph = *(u_int16_t *)g;		/* XXX */
948 		SFBPIXELMASK(sfb, lmask);
949 		SFBADDRESS(sfb, (long)p);
950 		SFBSTART(sfb, glyph << align);
951 		p += scanspan;
952 		g += 2;					/* XXX */
953 		height--;
954 	}
955 	if (attr & 1 /* UNDERLINE */) {
956 		p -= scanspan * 2;
957 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
958 		SFBADDRESS(sfb, (long)p);
959 		SFBSTART(sfb, lmask);
960 	}
961 
962 	SFBMODE(sfb, MODE_SIMPLE);
963 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
964 }
965 
966 #if 0
967 /*
968  * Copy characters in a line.
969  */
970 static void
971 sfb_copycols(id, row, srccol, dstcol, ncols)
972 	void *id;
973 	int row, srccol, dstcol, ncols;
974 {
975 	struct rasops_info *ri = id;
976 	caddr_t sp, dp, basex, sfb;
977 	int scanspan, height, width, aligns, alignd, shift, w, y;
978 	u_int32_t lmaskd, rmaskd;
979 
980 	scanspan = ri->ri_stride;
981 	y = row * ri->ri_font->fontheight;
982 	basex = ri->ri_bits + y * scanspan;
983 	height = ri->ri_font->fontheight;
984 	w = ri->ri_font->fontwidth * ncols;
985 
986 	sp = basex + ri->ri_font->fontwidth * srccol;
987 	aligns = (long)sp & SFBALIGNMASK;
988 	dp = basex + ri->ri_font->fontwidth * dstcol;
989 	alignd = (long)dp & SFBALIGNMASK;
990 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
991 
992 	SFBMODE(sfb, MODE_COPY);
993 	SFBPLANEMASK(sfb, ~0);
994 	/* small enough to fit in a single 32bit */
995 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
996 		SFBPIXELSHIFT(sfb, alignd - aligns);
997 		lmaskd = SFBCOPYALL1 << alignd;
998 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
999 		lmaskd = lmaskd & rmaskd;
1000 		sp -= aligns;
1001 		dp -= alignd;
1002 		while (height > 0) {
1003 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1004 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1005 			sp += scanspan;
1006 			dp += scanspan;
1007 			height--;
1008 		}
1009 	}
1010 	/* copy forward (left-to-right) */
1011 	else if (dstcol < srccol || srccol + ncols < dstcol) {
1012 		caddr_t sq, dq;
1013 
1014 		shift = alignd - aligns;
1015 		if (shift < 0) {
1016 			shift = 8 + shift;	/* enforce right rotate */
1017 			alignd += 8;		/* bearing on left edge */
1018 		}
1019 		width = alignd + w;
1020 		lmaskd = SFBCOPYALL1 << alignd;
1021 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1022 		sp -= aligns;
1023 		dp -= alignd;
1024 
1025 		SFBPIXELSHIFT(sfb, shift);
1026 		w = width;
1027 		sq = sp;
1028 		dq = dp;
1029 		while (height > 0) {
1030 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1031 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1032 			width -= 2 * SFBCOPYBITS;
1033 			while (width > 0) {
1034 				sp += SFBCOPYBYTESDONE;
1035 				dp += SFBCOPYBYTESDONE;
1036 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1037 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1038 				width -= SFBCOPYBITS;
1039 			}
1040 			sp += SFBCOPYBYTESDONE;
1041 			dp += SFBCOPYBYTESDONE;
1042 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1043 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1044 			sp = (sq += scanspan);
1045 			dp = (dq += scanspan);
1046 			width = w;
1047 			height--;
1048 		}
1049 	}
1050 	/* copy backward (right-to-left) */
1051 	else {
1052 		caddr_t sq, dq;
1053 
1054 		shift = alignd - aligns;
1055 		if (shift > 0) {
1056 			shift = shift - 8;	/* force left rotate */
1057 			alignd += 24;
1058 		}
1059 		width = alignd + w;
1060 		lmaskd = SFBCOPYALL1 << alignd;
1061 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1062 		sp -= aligns;
1063 		dp -= alignd;
1064 
1065 		SFBPIXELSHIFT(sfb, shift);
1066 		w = width;
1067 		sq = sp += (((aligns + w) - 1) & ~31);
1068 		dq = dp += (((alignd + w) - 1) & ~31);
1069 		while (height > 0) {
1070 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1071 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1072 			width -= 2 * SFBCOPYBITS;
1073 			while (width > 0) {
1074 				sp -= SFBCOPYBYTESDONE;
1075 				dp -= SFBCOPYBYTESDONE;
1076 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1077 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1078 				width -= SFBCOPYBITS;
1079 			}
1080 			sp -= SFBCOPYBYTESDONE;
1081 			dp -= SFBCOPYBYTESDONE;
1082 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1083 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1084 
1085 			sp = (sq += scanspan);
1086 			dp = (dq += scanspan);
1087 			width = w;
1088 			height--;
1089 		}
1090 	}
1091 	SFBMODE(sfb, MODE_SIMPLE);
1092 	SFBPIXELSHIFT(sfb, 0);
1093 }
1094 #endif
1095 
1096 /*
1097  * Clear characters in a line.
1098  */
1099 static void
1100 sfb_erasecols(id, row, startcol, ncols, attr)
1101 	void *id;
1102 	int row, startcol, ncols;
1103 	long attr;
1104 {
1105 	struct rasops_info *ri = id;
1106 	caddr_t sfb, p;
1107 	int scanspan, startx, height, width, align, w, y;
1108 	u_int32_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;
1117 	align = (long)p & SFBALIGNMASK;
1118 	p -= align;
1119 	width = w + align;
1120 	lmask = SFBSTIPPLEALL1 << align;
1121 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1122 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1123 
1124 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1125 	SFBPLANEMASK(sfb, ~0);
1126 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1127 	if (width <= SFBSTIPPLEBITS) {
1128 		lmask = lmask & rmask;
1129 		while (height > 0) {
1130 			SFBADDRESS(sfb, (long)p);
1131 			SFBSTART(sfb, lmask);
1132 			p += scanspan;
1133 			height--;
1134 		}
1135 	}
1136 	else {
1137 		caddr_t q = p;
1138 		while (height > 0) {
1139 			*(u_int32_t *)p = lmask;
1140 			WRITE_MB();
1141 			width -= 2 * SFBSTIPPLEBITS;
1142 			while (width > 0) {
1143 				p += SFBSTIPPLEBYTESDONE;
1144 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1145 				WRITE_MB();
1146 				width -= SFBSTIPPLEBITS;
1147 			}
1148 			p += SFBSTIPPLEBYTESDONE;
1149 			*(u_int32_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 /*
1161  * Copy lines.
1162  */
1163 static void
1164 sfb_copyrows(id, srcrow, dstrow, nrows)
1165 	void *id;
1166 	int srcrow, dstrow, nrows;
1167 {
1168 	struct rasops_info *ri = id;
1169 	caddr_t sfb, p;
1170 	int scanspan, offset, srcy, height, width, align, w;
1171 	u_int32_t lmask, rmask;
1172 
1173 	scanspan = ri->ri_stride;
1174 	height = ri->ri_font->fontheight * nrows;
1175 	offset = (dstrow - srcrow) * ri->ri_yscale;
1176 	srcy = ri->ri_font->fontheight * srcrow;
1177 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1178 		scanspan = -scanspan;
1179 		srcy += height;
1180 	}
1181 
1182 	p = ri->ri_bits + srcy * ri->ri_stride;
1183 	align = (long)p & SFBALIGNMASK;
1184 	p -= align;
1185 	w = ri->ri_emuwidth;
1186 	width = w + align;
1187 	lmask = SFBCOPYALL1 << align;
1188 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1189 	sfb = (caddr_t)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 		caddr_t q = p;
1199 		while (height > 0) {
1200 			*(u_int32_t *)p = lmask;
1201 			*(u_int32_t *)(p + offset) = lmask;
1202 			width -= 2 * SFBCOPYBITS;
1203 			while (width > 0) {
1204 				p += SFBCOPYBYTESDONE;
1205 				*(u_int32_t *)p = SFBCOPYALL1;
1206 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1207 				width -= SFBCOPYBITS;
1208 			}
1209 			p += SFBCOPYBYTESDONE;
1210 			*(u_int32_t *)p = rmask;
1211 			*(u_int32_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 /*
1222  * Erase lines.
1223  */
1224 void
1225 sfb_eraserows(id, startrow, nrows, attr)
1226 	void *id;
1227 	int startrow, nrows;
1228 	long attr;
1229 {
1230 	struct rasops_info *ri = id;
1231 	caddr_t sfb, p;
1232 	int scanspan, starty, height, width, align, w;
1233 	u_int32_t lmask, rmask;
1234 
1235 	scanspan = ri->ri_stride;
1236 	starty = ri->ri_font->fontheight * startrow;
1237 	height = ri->ri_font->fontheight * nrows;
1238 
1239 	p = ri->ri_bits + starty * scanspan;
1240 	align = (long)p & SFBALIGNMASK;
1241 	p -= align;
1242 	w = ri->ri_emuwidth;
1243 	width = w + align;
1244 	lmask = SFBSTIPPLEALL1 << align;
1245 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1246 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1247 
1248 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1249 	SFBPLANEMASK(sfb, ~0);
1250 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1251 	if (width <= SFBSTIPPLEBITS) {
1252 		/* never happens */;
1253 	}
1254 	else {
1255 		caddr_t q = p;
1256 		while (height > 0) {
1257 			*(u_int32_t *)p = lmask;
1258 			WRITE_MB();
1259 			width -= 2 * SFBSTIPPLEBITS;
1260 			while (width > 0) {
1261 				p += SFBSTIPPLEBYTESDONE;
1262 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1263 				WRITE_MB();
1264 				width -= SFBSTIPPLEBITS;
1265 			}
1266 			p += SFBSTIPPLEBYTESDONE;
1267 			*(u_int32_t *)p = rmask;
1268 			WRITE_MB();
1269 
1270 			p = (q += scanspan);
1271 			width = w + align;
1272 			height--;
1273 		}
1274 	}
1275 	SFBMODE(sfb, MODE_SIMPLE);
1276 }
1277