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