Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.81
      1 /* $NetBSD: sfb.c,v 1.81 2010/05/15 07:01:37 tsutsui 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.81 2010/05/15 07:01:37 tsutsui 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  *			uint8_t u0;
     73  *			uint8_t u1;
     74  *			uint8_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  *		   uint32_t	   bt_lo;
     81  *		   uint32_t	   bt_hi;
     82  *		   uint32_t	   bt_reg;
     83  *		   uint32_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 uint32_t *)((p) + (i)) = (v); tc_wmb();	\
     95     } while (/* CONSTCOND */ 0)
     96 #define	SFBWRITE32(p,i,v) do {					\
     97 	*(volatile uint32_t *)((p) + (i)) = (v);		\
     98     } while (/* CONSTCOND */ 0)
     99 #define	MEMWRITE32(p,v) do {					\
    100 	*(volatile uint32_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 	uint8_t r[CMAP_SIZE];
    111 	uint8_t g[CMAP_SIZE];
    112 	uint8_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 	uint8_t cc_color[6];
    122 	uint64_t cc_image[CURSOR_MAX_SIZE];
    123 	uint64_t cc_mask[CURSOR_MAX_SIZE];
    124 };
    125 
    126 struct sfb_softc {
    127 	vaddr_t sc_vaddr;
    128 	size_t sc_size;
    129 	struct rasops_info *sc_ri;
    130 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    131 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    132 	int sc_blanked;			/* video visibility disabled */
    133 	int sc_curenb;			/* cursor sprite enabled */
    134 	int sc_changed;			/* need update of hardware */
    135 #define	WSDISPLAY_CMAP_DOLUT	0x20
    136 	int nscreens;
    137 };
    138 
    139 #define	HX_MAGIC_X	368
    140 #define	HX_MAGIC_Y	38
    141 
    142 static int  sfbmatch(device_t, cfdata_t, void *);
    143 static void sfbattach(device_t, device_t, void *);
    144 
    145 CFATTACH_DECL_NEW(sfb, sizeof(struct sfb_softc),
    146     sfbmatch, sfbattach, NULL, NULL);
    147 
    148 static void sfb_common_init(struct rasops_info *);
    149 static struct rasops_info sfb_console_ri;
    150 static tc_addr_t sfb_consaddr;
    151 
    152 static void sfb_putchar(void *, int, int, u_int, long);
    153 static void sfb_erasecols(void *, int, int, int, long);
    154 static void sfb_eraserows(void *, int, int, long);
    155 static void sfb_copyrows(void *, int, int, int);
    156 static void sfb_do_cursor(struct rasops_info *);
    157 #if 0
    158 static void sfb_copycols(void *, int, int, int, int);
    159 #endif
    160 
    161 static struct wsscreen_descr sfb_stdscreen = {
    162 	"std", 0, 0,
    163 	0, /* textops */
    164 	0, 0,
    165 	WSSCREEN_REVERSE
    166 };
    167 
    168 static const struct wsscreen_descr *_sfb_scrlist[] = {
    169 	&sfb_stdscreen,
    170 };
    171 
    172 static const struct wsscreen_list sfb_screenlist = {
    173 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
    174 };
    175 
    176 static int	sfbioctl(void *, void *, u_long, void *, int, struct lwp *);
    177 static paddr_t	sfbmmap(void *, void *, off_t, int);
    178 
    179 static int	sfb_alloc_screen(void *, const struct wsscreen_descr *,
    180 				      void **, int *, int *, long *);
    181 static void	sfb_free_screen(void *, void *);
    182 static int	sfb_show_screen(void *, void *, int,
    183 				     void (*) (void *, int, int), void *);
    184 
    185 static const struct wsdisplay_accessops sfb_accessops = {
    186 	sfbioctl,
    187 	sfbmmap,
    188 	sfb_alloc_screen,
    189 	sfb_free_screen,
    190 	sfb_show_screen,
    191 	0 /* load_font */
    192 };
    193 
    194 int  sfb_cnattach(tc_addr_t);
    195 static int  sfbintr(void *);
    196 static void sfbhwinit(void *);
    197 static void sfb_cmap_init(struct sfb_softc *);
    198 static void sfb_screenblank(struct sfb_softc *);
    199 
    200 static int  get_cmap(struct sfb_softc *, struct wsdisplay_cmap *);
    201 static int  set_cmap(struct sfb_softc *, struct wsdisplay_cmap *);
    202 static int  set_cursor(struct sfb_softc *, struct wsdisplay_cursor *);
    203 static int  get_cursor(struct sfb_softc *, struct wsdisplay_cursor *);
    204 static void set_curpos(struct sfb_softc *, struct wsdisplay_curpos *);
    205 
    206 /*
    207  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    208  *   M M M M I I I I		M I M I M I M I
    209  *	[ before ]		   [ after ]
    210  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    211  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    212  */
    213 static const uint8_t shuffle[256] = {
    214 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    215 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    216 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    217 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    218 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    219 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    220 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    221 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    222 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    223 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    224 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    225 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    226 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    227 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    228 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    229 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    230 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    231 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    232 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    233 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    234 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    235 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    236 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    237 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    238 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    239 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    240 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    241 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    242 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    243 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    244 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    245 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    246 };
    247 
    248 static int
    249 sfbmatch(device_t parent, cfdata_t match, void *aux)
    250 {
    251 	struct tc_attach_args *ta = aux;
    252 
    253 	if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
    254 		return (0);
    255 	return (1);
    256 }
    257 
    258 static void
    259 sfbattach(device_t parent, device_t self, void *aux)
    260 {
    261 	struct sfb_softc *sc = device_private(self);
    262 	struct tc_attach_args *ta = aux;
    263 	struct rasops_info *ri;
    264 	struct wsemuldisplaydev_attach_args waa;
    265 	char *asic;
    266 	int console;
    267 
    268 	console = (ta->ta_addr == sfb_consaddr);
    269 	if (console) {
    270 		sc->sc_ri = ri = &sfb_console_ri;
    271 		sc->nscreens = 1;
    272 	}
    273 	else {
    274 		ri = malloc(sizeof(struct rasops_info),
    275 			M_DEVBUF, M_NOWAIT|M_ZERO);
    276 		if (ri == NULL) {
    277 			printf(": can't alloc memory\n");
    278 			return;
    279 		}
    280 
    281 		ri->ri_hw = (void *)ta->ta_addr;
    282 		sfb_common_init(ri);
    283 		sc->sc_ri = ri;
    284 	}
    285 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    286 
    287 	sfb_cmap_init(sc);
    288 
    289 	sc->sc_vaddr = ta->ta_addr;
    290 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
    291 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
    292 	sc->sc_blanked = sc->sc_curenb = 0;
    293 
    294 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
    295 
    296 	asic = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
    297 
    298 	SFBWRITE32(asic, SFB_ASIC_CLEAR_INTR, 0);
    299 	SFBWRITE32(asic, SFB_ASIC_ENABLE_INTR, 1);
    300 
    301 	waa.console = console;
    302 	waa.scrdata = &sfb_screenlist;
    303 	waa.accessops = &sfb_accessops;
    304 	waa.accesscookie = sc;
    305 
    306 	config_found(self, &waa, wsemuldisplaydevprint);
    307 }
    308 
    309 static void
    310 sfb_cmap_init(struct sfb_softc *sc)
    311 {
    312 	struct hwcmap256 *cm;
    313 	const uint8_t *p;
    314 	int index;
    315 
    316 	cm = &sc->sc_cmap;
    317 	p = rasops_cmap;
    318 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    319 		cm->r[index] = p[0];
    320 		cm->g[index] = p[1];
    321 		cm->b[index] = p[2];
    322 	}
    323 }
    324 
    325 static void
    326 sfb_common_init(struct rasops_info *ri)
    327 {
    328 	char *base, *asic;
    329 	int hsetup, vsetup, vbase, cookie;
    330 
    331 	base = (void *)ri->ri_hw;
    332 	asic = base + SFB_ASIC_OFFSET;
    333 	hsetup = *(volatile uint32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
    334 	vsetup = *(volatile uint32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
    335 
    336 	vbase = 1;
    337 	SFBWRITE32(asic, SFB_ASIC_VIDEO_BASE, vbase);
    338 	SFBWRITE32(asic, SFB_ASIC_PLANEMASK, ~0);
    339 	SFBWRITE32(asic, SFB_ASIC_PIXELMASK, ~0);
    340 	SFBWRITE32(asic, SFB_ASIC_MODE, 0);	/* MODE_SIMPLE */
    341 	SFBWRITE32(asic, SFB_ASIC_ROP, 3); 	/* ROP_COPY */
    342 	SFBWRITE32(asic, 0x180000, 0); 		/* Bt459 reset */
    343 
    344 	/* initialize colormap and cursor hardware */
    345 	sfbhwinit(base);
    346 
    347 	ri->ri_flg = RI_CENTER;
    348 	if (ri == &sfb_console_ri)
    349 		ri->ri_flg |= RI_NO_AUTO;
    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 		uint8_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 		uint8_t *ip, *mp, img, msk;
    600 		uint8_t u;
    601 		int bcnt;
    602 
    603 		ip = (uint8_t *)sc->sc_cursor.cc_image;
    604 		mp = (uint8_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 uint8_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 	uint32_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 	uint32_t lmask, rmask, glyph;
    949 	uint8_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 = *(uint16_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 	uint32_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 	uint32_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 	uint32_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 	uint32_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