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