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