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