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