xref: /netbsd/sys/dev/tc/sfb.c (revision bf9ec67e)
1 /* $NetBSD: sfb.c,v 1.51 2002/03/17 19:41:02 atatat 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.51 2002/03/17 19:41:02 atatat 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 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
349 	    WSDISPLAY_FONTORDER_L2R);
350 	if (cookie <= 0)
351 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
352 		    WSDISPLAY_FONTORDER_L2R);
353 	if (cookie <= 0) {
354 		printf("sfb: font table is empty\n");
355 		return;
356 	}
357 
358 	/* the accelerated sfb_putchar() needs LSbit left */
359 	if (wsfont_lock(cookie, &ri->ri_font)) {
360 		printf("sfb: couldn't lock font\n");
361 		return;
362 	}
363 	ri->ri_wsfcookie = cookie;
364 
365 	rasops_init(ri, 34, 80);
366 
367 	/* add our accelerated functions */
368 	ri->ri_ops.putchar = sfb_putchar;
369 	ri->ri_ops.erasecols = sfb_erasecols;
370 	ri->ri_ops.copyrows = sfb_copyrows;
371 	ri->ri_ops.eraserows = sfb_eraserows;
372 	ri->ri_do_cursor = sfb_do_cursor;
373 
374 	/* XXX shouldn't be global */
375 	sfb_stdscreen.nrows = ri->ri_rows;
376 	sfb_stdscreen.ncols = ri->ri_cols;
377 	sfb_stdscreen.textops = &ri->ri_ops;
378 	sfb_stdscreen.capabilities = ri->ri_caps;
379 }
380 
381 static int
382 sfbioctl(v, cmd, data, flag, p)
383 	void *v;
384 	u_long cmd;
385 	caddr_t data;
386 	int flag;
387 	struct proc *p;
388 {
389 	struct sfb_softc *sc = v;
390 	struct rasops_info *ri = sc->sc_ri;
391 	int turnoff;
392 
393 	switch (cmd) {
394 	case WSDISPLAYIO_GTYPE:
395 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
396 		return (0);
397 
398 	case WSDISPLAYIO_GINFO:
399 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
400 		wsd_fbip->height = ri->ri_height;
401 		wsd_fbip->width = ri->ri_width;
402 		wsd_fbip->depth = ri->ri_depth;
403 		wsd_fbip->cmsize = CMAP_SIZE;
404 #undef fbt
405 		return (0);
406 
407 	case WSDISPLAYIO_GETCMAP:
408 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
409 
410 	case WSDISPLAYIO_PUTCMAP:
411 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
412 
413 	case WSDISPLAYIO_SVIDEO:
414 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
415 		if (sc->sc_blanked ^ turnoff) {
416 			caddr_t asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
417 			*(u_int32_t *)(asic + SFB_ASIC_VIDEO_VALID)
418 				= !turnoff;
419 			tc_wmb();
420 			sc->sc_blanked = turnoff;
421 		}
422 		return (0);
423 
424 	case WSDISPLAYIO_GVIDEO:
425 		*(u_int *)data = sc->sc_blanked ?
426 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
427 		return (0);
428 
429 	case WSDISPLAYIO_GCURPOS:
430 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
431 		return (0);
432 
433 	case WSDISPLAYIO_SCURPOS:
434 		set_curpos(sc, (struct wsdisplay_curpos *)data);
435 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
436 		return (0);
437 
438 	case WSDISPLAYIO_GCURMAX:
439 		((struct wsdisplay_curpos *)data)->x =
440 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
441 		return (0);
442 
443 	case WSDISPLAYIO_GCURSOR:
444 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
445 
446 	case WSDISPLAYIO_SCURSOR:
447 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
448 	}
449 	return (EPASSTHROUGH);
450 }
451 
452 static paddr_t
453 sfbmmap(v, offset, prot)
454 	void *v;
455 	off_t offset;
456 	int prot;
457 {
458 	struct sfb_softc *sc = v;
459 
460 	if (offset >= SFB_SIZE || offset < 0)
461 		return (-1);
462 	return machine_btop(sc->sc_vaddr + offset);
463 }
464 
465 static int
466 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
467 	void *v;
468 	const struct wsscreen_descr *type;
469 	void **cookiep;
470 	int *curxp, *curyp;
471 	long *attrp;
472 {
473 	struct sfb_softc *sc = v;
474 	struct rasops_info *ri = sc->sc_ri;
475 	long defattr;
476 
477 	if (sc->nscreens > 0)
478 		return (ENOMEM);
479 
480 	*cookiep = ri;	 /* one and only for now */
481 	*curxp = 0;
482 	*curyp = 0;
483 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
484 	*attrp = defattr;
485 	sc->nscreens++;
486 	return (0);
487 }
488 
489 static void
490 sfb_free_screen(v, cookie)
491 	void *v;
492 	void *cookie;
493 {
494 	struct sfb_softc *sc = v;
495 
496 	if (sc->sc_ri == &sfb_console_ri)
497 		panic("sfb_free_screen: console");
498 
499 	sc->nscreens--;
500 }
501 
502 static int
503 sfb_show_screen(v, cookie, waitok, cb, cbarg)
504 	void *v;
505 	void *cookie;
506 	int waitok;
507 	void (*cb) __P((void *, int, int));
508 	void *cbarg;
509 {
510 
511 	return (0);
512 }
513 
514 /* EXPORT */ int
515 sfb_cnattach(addr)
516 	tc_addr_t addr;
517 {
518 	struct rasops_info *ri;
519 	long defattr;
520 
521 	ri = &sfb_console_ri;
522 	ri->ri_hw = (void *)addr;
523 	sfb_common_init(ri);
524 	(*ri->ri_ops.alloc_attr)(&ri, 0, 0, 0, &defattr);
525 	wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
526 	sfb_consaddr = addr;
527 	return (0);
528 }
529 
530 static int
531 sfbintr(arg)
532 	void *arg;
533 {
534 	struct sfb_softc *sc = arg;
535 	caddr_t base, asic, vdac;
536 	int v;
537 
538 	base = (caddr_t)sc->sc_ri->ri_hw;
539 	asic = base + SFB_ASIC_OFFSET;
540 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
541 	/* *(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1; */
542 
543 	if (sc->sc_changed == 0)
544 		goto done;
545 
546 	vdac = base + SFB_RAMDAC_OFFSET;
547 	v = sc->sc_changed;
548 	if (v & WSDISPLAY_CURSOR_DOCUR) {
549 		SELECT(vdac, BT459_IREG_CCR);
550 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
551 	}
552 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
553 		int x, y;
554 
555 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
556 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
557 		x += sc->sc_cursor.cc_magic.x;
558 		y += sc->sc_cursor.cc_magic.y;
559 
560 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
561 		REG(vdac, bt_reg) = x;		tc_wmb();
562 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
563 		REG(vdac, bt_reg) = y;		tc_wmb();
564 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
565 	}
566 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
567 		u_int8_t *cp = sc->sc_cursor.cc_color;
568 
569 		SELECT(vdac, BT459_IREG_CCOLOR_2);
570 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
571 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
572 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
573 
574 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
575 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
576 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
577 	}
578 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
579 		u_int8_t *ip, *mp, img, msk;
580 		u_int8_t u;
581 		int bcnt;
582 
583 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
584 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
585 
586 		bcnt = 0;
587 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
588 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
589 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
590 			/* pad right half 32 pixel when smaller than 33 */
591 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
592 				REG(vdac, bt_reg) = 0; tc_wmb();
593 				REG(vdac, bt_reg) = 0; tc_wmb();
594 			}
595 			else {
596 				img = *ip++;
597 				msk = *mp++;
598 				img &= msk;	/* cookie off image */
599 				u = (msk & 0x0f) << 4 | (img & 0x0f);
600 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
601 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
602 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
603 			}
604 			bcnt += 2;
605 		}
606 		/* pad unoccupied scan lines */
607 		while (bcnt < CURSOR_MAX_SIZE * 16) {
608 			REG(vdac, bt_reg) = 0; tc_wmb();
609 			REG(vdac, bt_reg) = 0; tc_wmb();
610 			bcnt += 2;
611 		}
612 	}
613 	if (v & WSDISPLAY_CMAP_DOLUT) {
614 		struct hwcmap256 *cm = &sc->sc_cmap;
615 		int index;
616 
617 		SELECT(vdac, 0);
618 		for (index = 0; index < CMAP_SIZE; index++) {
619 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
620 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
621 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
622 		}
623 	}
624 	sc->sc_changed = 0;
625 done:
626 	return (1);
627 }
628 
629 static void
630 sfbhwinit(base)
631 	caddr_t base;
632 {
633 	caddr_t vdac = base + SFB_RAMDAC_OFFSET;
634 	const u_int8_t *p;
635 	int i;
636 
637 	SELECT(vdac, BT459_IREG_COMMAND_0);
638 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
639 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
640 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
641 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
642 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
643 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
644 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
645 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
646 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
647 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
648 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
649 
650 	SELECT(vdac, BT459_IREG_CCR);
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 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
664 
665 	/* build sane colormap */
666 	SELECT(vdac, 0);
667 	p = rasops_cmap;
668 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
669 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
670 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
671 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
672 	}
673 
674 	/* clear out cursor image */
675 	SELECT(vdac, BT459_IREG_CRAM_BASE);
676 	for (i = 0; i < 1024; i++)
677 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
678 
679 	/*
680 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
681 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
682 	 * image color.  CCOLOR_1 will be never used.
683 	 */
684 	SELECT(vdac, BT459_IREG_CCOLOR_1);
685 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
686 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
687 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
688 
689 	REG(vdac, bt_reg) = 0;		tc_wmb();
690 	REG(vdac, bt_reg) = 0;		tc_wmb();
691 	REG(vdac, bt_reg) = 0;		tc_wmb();
692 
693 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
694 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
695 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
696 }
697 
698 static int
699 get_cmap(sc, p)
700 	struct sfb_softc *sc;
701 	struct wsdisplay_cmap *p;
702 {
703 	u_int index = p->index, count = p->count;
704 
705 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
706 		return (EINVAL);
707 
708 	if (!uvm_useracc(p->red, count, B_WRITE) ||
709 	    !uvm_useracc(p->green, count, B_WRITE) ||
710 	    !uvm_useracc(p->blue, count, B_WRITE))
711 		return (EFAULT);
712 
713 	copyout(&sc->sc_cmap.r[index], p->red, count);
714 	copyout(&sc->sc_cmap.g[index], p->green, count);
715 	copyout(&sc->sc_cmap.b[index], p->blue, count);
716 
717 	return (0);
718 }
719 
720 static int
721 set_cmap(sc, p)
722 	struct sfb_softc *sc;
723 	struct wsdisplay_cmap *p;
724 {
725 	u_int index = p->index, count = p->count;
726 
727 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
728 		return (EINVAL);
729 
730 	if (!uvm_useracc(p->red, count, B_READ) ||
731 	    !uvm_useracc(p->green, count, B_READ) ||
732 	    !uvm_useracc(p->blue, count, B_READ))
733 		return (EFAULT);
734 
735 	copyin(p->red, &sc->sc_cmap.r[index], count);
736 	copyin(p->green, &sc->sc_cmap.g[index], count);
737 	copyin(p->blue, &sc->sc_cmap.b[index], count);
738 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
739 	return (0);
740 }
741 
742 static int
743 set_cursor(sc, p)
744 	struct sfb_softc *sc;
745 	struct wsdisplay_cursor *p;
746 {
747 #define	cc (&sc->sc_cursor)
748 	u_int v, index, count, icount;
749 
750 	v = p->which;
751 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
752 		index = p->cmap.index;
753 		count = p->cmap.count;
754 		if (index >= 2 || (index + count) > 2)
755 			return (EINVAL);
756 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
757 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
758 		    !uvm_useracc(p->cmap.blue, count, B_READ))
759 			return (EFAULT);
760 	}
761 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
762 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
763 			return (EINVAL);
764 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
765 		if (!uvm_useracc(p->image, icount, B_READ) ||
766 		    !uvm_useracc(p->mask, icount, B_READ))
767 			return (EFAULT);
768 	}
769 
770 	if (v & WSDISPLAY_CURSOR_DOCUR)
771 		sc->sc_curenb = p->enable;
772 	if (v & WSDISPLAY_CURSOR_DOPOS)
773 		set_curpos(sc, &p->pos);
774 	if (v & WSDISPLAY_CURSOR_DOHOT)
775 		cc->cc_hot = p->hot;
776 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
777 		copyin(p->cmap.red, &cc->cc_color[index], count);
778 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
779 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
780 	}
781 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
782 		cc->cc_size = p->size;
783 		memset(cc->cc_image, 0, sizeof cc->cc_image);
784 		copyin(p->image, cc->cc_image, icount);
785 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
786 	}
787 	sc->sc_changed |= v;
788 
789 	return (0);
790 #undef cc
791 }
792 
793 static int
794 get_cursor(sc, p)
795 	struct sfb_softc *sc;
796 	struct wsdisplay_cursor *p;
797 {
798 
799 	return (EPASSTHROUGH); /* XXX */
800 }
801 
802 static void
803 set_curpos(sc, curpos)
804 	struct sfb_softc *sc;
805 	struct wsdisplay_curpos *curpos;
806 {
807 	struct rasops_info *ri = sc->sc_ri;
808 	int x = curpos->x, y = curpos->y;
809 
810 	if (y < 0)
811 		y = 0;
812 	else if (y > ri->ri_height);
813 		y = ri->ri_height;
814 	if (x < 0)
815 		x = 0;
816 	else if (x > ri->ri_width);
817 		x = ri->ri_width;
818 	sc->sc_cursor.cc_pos.x = x;
819 	sc->sc_cursor.cc_pos.y = y;
820 }
821 
822 #define	MODE_SIMPLE		0
823 #define	MODE_OPAQUESTIPPLE	1
824 #define	MODE_OPAQUELINE		2
825 #define	MODE_TRANSPARENTSTIPPLE	5
826 #define	MODE_TRANSPARENTLINE	6
827 #define	MODE_COPY		7
828 
829 /* parameters for 8bpp configuration */
830 #define	SFBALIGNMASK		0x7
831 #define	SFBSTIPPLEALL1		0xffffffff
832 #define	SFBSTIPPLEBITS		32
833 #define	SFBSTIPPLEBITMASK	0x1f
834 #define	SFBSTIPPLEBYTESDONE	32
835 #define	SFBCOPYALL1		0xffffffff
836 #define	SFBCOPYBITS		32
837 #define	SFBCOPYBITMASK		0x1f
838 #define	SFBCOPYBYTESDONE	32
839 
840 #if defined(pmax)
841 #define	WRITE_MB()
842 #define	BUMP(p) (p)
843 #endif
844 
845 #if defined(alpha)
846 #define	WRITE_MB() tc_wmb()
847 /* SFB registers replicated in 128B stride; cycle after eight iterations */
848 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
849 #endif
850 
851 #define	SFBMODE(p, v) \
852 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
853 #define	SFBROP(p, v) \
854 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
855 #define	SFBPLANEMASK(p, v) \
856 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
857 #define	SFBPIXELMASK(p, v) \
858 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
859 #define	SFBADDRESS(p, v) \
860 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
861 #define	SFBSTART(p, v) \
862 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
863 #define	SFBPIXELSHIFT(p, v) \
864 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
865 #define	SFBFG(p, v) \
866 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
867 #define	SFBBG(p, v) \
868 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
869 
870 /*
871  * Paint the cursor.
872  */
873 static void
874 sfb_do_cursor(ri)
875 	struct rasops_info *ri;
876 {
877 	caddr_t sfb, p;
878 	int scanspan, height, width, align, x, y;
879 	u_int32_t lmask, rmask;
880 
881 	x = ri->ri_ccol * ri->ri_font->fontwidth;
882 	y = ri->ri_crow * ri->ri_font->fontheight;
883 	scanspan = ri->ri_stride;
884 	height = ri->ri_font->fontheight;
885 
886 	p = ri->ri_bits + y * scanspan + x;
887 	align = (long)p & SFBALIGNMASK;
888 	p -= align;
889 	width = ri->ri_font->fontwidth + align;
890 	lmask = SFBSTIPPLEALL1 << align;
891 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
892 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
893 
894 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
895 	SFBPLANEMASK(sfb, ~0);
896 	SFBROP(sfb, 6);  /* ROP_XOR */
897 	SFBFG(sfb, ~0);
898 
899 	lmask = lmask & rmask;
900 	while (height > 0) {
901 		SFBADDRESS(sfb, (long)p);
902 		SFBSTART(sfb, lmask);
903 		p += scanspan;
904 		height--;
905 	}
906 	SFBMODE(sfb, MODE_SIMPLE);
907 	SFBROP(sfb, 3); /* ROP_COPY */
908 }
909 
910 /*
911  * Paint a character.
912  */
913 static void
914 sfb_putchar(id, row, col, uc, attr)
915 	void *id;
916 	int row, col;
917 	u_int uc;
918 	long attr;
919 {
920 	struct rasops_info *ri = id;
921 	caddr_t sfb, p;
922 	int scanspan, height, width, align, x, y;
923 	u_int32_t lmask, rmask, glyph;
924 	u_int8_t *g;
925 
926 	x = col * ri->ri_font->fontwidth;
927 	y = row * ri->ri_font->fontheight;
928 	scanspan = ri->ri_stride;
929 	height = ri->ri_font->fontheight;
930 	uc -= ri->ri_font->firstchar;
931 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
932 
933 	p = ri->ri_bits + y * scanspan + x;
934 	align = (long)p & SFBALIGNMASK;
935 	p -= align;
936 	width = ri->ri_font->fontwidth + align;
937 	lmask = SFBSTIPPLEALL1 << align;
938 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
939 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
940 
941 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
942 	SFBPLANEMASK(sfb, ~0);
943 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
944 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
945 
946 	/* XXX 2B stride fonts only XXX */
947 	lmask = lmask & rmask;
948 	while (height > 0) {
949 		glyph = *(u_int16_t *)g;		/* XXX */
950 		SFBPIXELMASK(sfb, lmask);
951 		SFBADDRESS(sfb, (long)p);
952 		SFBSTART(sfb, glyph << align);
953 		p += scanspan;
954 		g += 2;					/* XXX */
955 		height--;
956 	}
957 	if (attr & 1 /* UNDERLINE */) {
958 		p -= scanspan * 2;
959 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
960 		SFBADDRESS(sfb, (long)p);
961 		SFBSTART(sfb, lmask);
962 	}
963 
964 	SFBMODE(sfb, MODE_SIMPLE);
965 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
966 }
967 
968 #if 0
969 /*
970  * Copy characters in a line.
971  */
972 static void
973 sfb_copycols(id, row, srccol, dstcol, ncols)
974 	void *id;
975 	int row, srccol, dstcol, ncols;
976 {
977 	struct rasops_info *ri = id;
978 	caddr_t sp, dp, basex, sfb;
979 	int scanspan, height, width, aligns, alignd, shift, w, y;
980 	u_int32_t lmaskd, rmaskd;
981 
982 	scanspan = ri->ri_stride;
983 	y = row * ri->ri_font->fontheight;
984 	basex = ri->ri_bits + y * scanspan;
985 	height = ri->ri_font->fontheight;
986 	w = ri->ri_font->fontwidth * ncols;
987 
988 	sp = basex + ri->ri_font->fontwidth * srccol;
989 	aligns = (long)sp & SFBALIGNMASK;
990 	dp = basex + ri->ri_font->fontwidth * dstcol;
991 	alignd = (long)dp & SFBALIGNMASK;
992 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
993 
994 	SFBMODE(sfb, MODE_COPY);
995 	SFBPLANEMASK(sfb, ~0);
996 	/* small enough to fit in a single 32bit */
997 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
998 		SFBPIXELSHIFT(sfb, alignd - aligns);
999 		lmaskd = SFBCOPYALL1 << alignd;
1000 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
1001 		lmaskd = lmaskd & rmaskd;
1002 		sp -= aligns;
1003 		dp -= alignd;
1004 		while (height > 0) {
1005 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1006 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1007 			sp += scanspan;
1008 			dp += scanspan;
1009 			height--;
1010 		}
1011 	}
1012 	/* copy forward (left-to-right) */
1013 	else if (dstcol < srccol || srccol + ncols < dstcol) {
1014 		caddr_t sq, dq;
1015 
1016 		shift = alignd - aligns;
1017 		if (shift < 0) {
1018 			shift = 8 + shift;	/* enforce right rotate */
1019 			alignd += 8;		/* bearing on left edge */
1020 		}
1021 		width = alignd + w;
1022 		lmaskd = SFBCOPYALL1 << alignd;
1023 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1024 		sp -= aligns;
1025 		dp -= alignd;
1026 
1027 		SFBPIXELSHIFT(sfb, shift);
1028 		w = width;
1029 		sq = sp;
1030 		dq = dp;
1031 		while (height > 0) {
1032 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1033 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1034 			width -= 2 * SFBCOPYBITS;
1035 			while (width > 0) {
1036 				sp += SFBCOPYBYTESDONE;
1037 				dp += SFBCOPYBYTESDONE;
1038 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1039 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1040 				width -= SFBCOPYBITS;
1041 			}
1042 			sp += SFBCOPYBYTESDONE;
1043 			dp += SFBCOPYBYTESDONE;
1044 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1045 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1046 			sp = (sq += scanspan);
1047 			dp = (dq += scanspan);
1048 			width = w;
1049 			height--;
1050 		}
1051 	}
1052 	/* copy backward (right-to-left) */
1053 	else {
1054 		caddr_t sq, dq;
1055 
1056 		shift = alignd - aligns;
1057 		if (shift > 0) {
1058 			shift = shift - 8;	/* force left rotate */
1059 			alignd += 24;
1060 		}
1061 		width = alignd + w;
1062 		lmaskd = SFBCOPYALL1 << alignd;
1063 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1064 		sp -= aligns;
1065 		dp -= alignd;
1066 
1067 		SFBPIXELSHIFT(sfb, shift);
1068 		w = width;
1069 		sq = sp += (((aligns + w) - 1) & ~31);
1070 		dq = dp += (((alignd + w) - 1) & ~31);
1071 		while (height > 0) {
1072 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1073 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
1074 			width -= 2 * SFBCOPYBITS;
1075 			while (width > 0) {
1076 				sp -= SFBCOPYBYTESDONE;
1077 				dp -= SFBCOPYBYTESDONE;
1078 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
1079 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
1080 				width -= SFBCOPYBITS;
1081 			}
1082 			sp -= SFBCOPYBYTESDONE;
1083 			dp -= SFBCOPYBYTESDONE;
1084 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
1085 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
1086 
1087 			sp = (sq += scanspan);
1088 			dp = (dq += scanspan);
1089 			width = w;
1090 			height--;
1091 		}
1092 	}
1093 	SFBMODE(sfb, MODE_SIMPLE);
1094 	SFBPIXELSHIFT(sfb, 0);
1095 }
1096 #endif
1097 
1098 /*
1099  * Clear characters in a line.
1100  */
1101 static void
1102 sfb_erasecols(id, row, startcol, ncols, attr)
1103 	void *id;
1104 	int row, startcol, ncols;
1105 	long attr;
1106 {
1107 	struct rasops_info *ri = id;
1108 	caddr_t sfb, p;
1109 	int scanspan, startx, height, width, align, w, y;
1110 	u_int32_t lmask, rmask;
1111 
1112 	scanspan = ri->ri_stride;
1113 	y = row * ri->ri_font->fontheight;
1114 	startx = startcol * ri->ri_font->fontwidth;
1115 	height = ri->ri_font->fontheight;
1116 	w = ri->ri_font->fontwidth * ncols;
1117 
1118 	p = ri->ri_bits + y * scanspan + startx;
1119 	align = (long)p & SFBALIGNMASK;
1120 	p -= align;
1121 	width = w + align;
1122 	lmask = SFBSTIPPLEALL1 << align;
1123 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1124 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1125 
1126 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1127 	SFBPLANEMASK(sfb, ~0);
1128 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1129 	if (width <= SFBSTIPPLEBITS) {
1130 		lmask = lmask & rmask;
1131 		while (height > 0) {
1132 			SFBADDRESS(sfb, (long)p);
1133 			SFBSTART(sfb, lmask);
1134 			p += scanspan;
1135 			height--;
1136 		}
1137 	}
1138 	else {
1139 		caddr_t q = p;
1140 		while (height > 0) {
1141 			*(u_int32_t *)p = lmask;
1142 			WRITE_MB();
1143 			width -= 2 * SFBSTIPPLEBITS;
1144 			while (width > 0) {
1145 				p += SFBSTIPPLEBYTESDONE;
1146 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1147 				WRITE_MB();
1148 				width -= SFBSTIPPLEBITS;
1149 			}
1150 			p += SFBSTIPPLEBYTESDONE;
1151 			*(u_int32_t *)p = rmask;
1152 			WRITE_MB();
1153 
1154 			p = (q += scanspan);
1155 			width = w + align;
1156 			height--;
1157 		}
1158 	}
1159 	SFBMODE(sfb, MODE_SIMPLE);
1160 }
1161 
1162 /*
1163  * Copy lines.
1164  */
1165 static void
1166 sfb_copyrows(id, srcrow, dstrow, nrows)
1167 	void *id;
1168 	int srcrow, dstrow, nrows;
1169 {
1170 	struct rasops_info *ri = id;
1171 	caddr_t sfb, p;
1172 	int scanspan, offset, srcy, height, width, align, w;
1173 	u_int32_t lmask, rmask;
1174 
1175 	scanspan = ri->ri_stride;
1176 	height = ri->ri_font->fontheight * nrows;
1177 	offset = (dstrow - srcrow) * ri->ri_yscale;
1178 	srcy = ri->ri_font->fontheight * srcrow;
1179 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1180 		scanspan = -scanspan;
1181 		srcy += height;
1182 	}
1183 
1184 	p = ri->ri_bits + srcy * ri->ri_stride;
1185 	align = (long)p & SFBALIGNMASK;
1186 	p -= align;
1187 	w = ri->ri_emuwidth;
1188 	width = w + align;
1189 	lmask = SFBCOPYALL1 << align;
1190 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1191 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1192 
1193 	SFBMODE(sfb, MODE_COPY);
1194 	SFBPLANEMASK(sfb, ~0);
1195 	SFBPIXELSHIFT(sfb, 0);
1196 	if (width <= SFBCOPYBITS) {
1197 		/* never happens */;
1198 	}
1199 	else {
1200 		caddr_t q = p;
1201 		while (height > 0) {
1202 			*(u_int32_t *)p = lmask;
1203 			*(u_int32_t *)(p + offset) = lmask;
1204 			width -= 2 * SFBCOPYBITS;
1205 			while (width > 0) {
1206 				p += SFBCOPYBYTESDONE;
1207 				*(u_int32_t *)p = SFBCOPYALL1;
1208 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1209 				width -= SFBCOPYBITS;
1210 			}
1211 			p += SFBCOPYBYTESDONE;
1212 			*(u_int32_t *)p = rmask;
1213 			*(u_int32_t *)(p + offset) = rmask;
1214 
1215 			p = (q += scanspan);
1216 			width = w + align;
1217 			height--;
1218 		}
1219 	}
1220 	SFBMODE(sfb, MODE_SIMPLE);
1221 }
1222 
1223 /*
1224  * Erase lines.
1225  */
1226 void
1227 sfb_eraserows(id, startrow, nrows, attr)
1228 	void *id;
1229 	int startrow, nrows;
1230 	long attr;
1231 {
1232 	struct rasops_info *ri = id;
1233 	caddr_t sfb, p;
1234 	int scanspan, starty, height, width, align, w;
1235 	u_int32_t lmask, rmask;
1236 
1237 	scanspan = ri->ri_stride;
1238 	starty = ri->ri_font->fontheight * startrow;
1239 	height = ri->ri_font->fontheight * nrows;
1240 
1241 	p = ri->ri_bits + starty * scanspan;
1242 	align = (long)p & SFBALIGNMASK;
1243 	p -= align;
1244 	w = ri->ri_emuwidth;
1245 	width = w + align;
1246 	lmask = SFBSTIPPLEALL1 << align;
1247 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1248 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
1249 
1250 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1251 	SFBPLANEMASK(sfb, ~0);
1252 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1253 	if (width <= SFBSTIPPLEBITS) {
1254 		/* never happens */;
1255 	}
1256 	else {
1257 		caddr_t q = p;
1258 		while (height > 0) {
1259 			*(u_int32_t *)p = lmask;
1260 			WRITE_MB();
1261 			width -= 2 * SFBSTIPPLEBITS;
1262 			while (width > 0) {
1263 				p += SFBSTIPPLEBYTESDONE;
1264 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1265 				WRITE_MB();
1266 				width -= SFBSTIPPLEBITS;
1267 			}
1268 			p += SFBSTIPPLEBYTESDONE;
1269 			*(u_int32_t *)p = rmask;
1270 			WRITE_MB();
1271 
1272 			p = (q += scanspan);
1273 			width = w + align;
1274 			height--;
1275 		}
1276 	}
1277 	SFBMODE(sfb, MODE_SIMPLE);
1278 }
1279