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