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