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