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