Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.82
      1 /* $NetBSD: sfb.c,v 1.82 2010/05/15 08:53:27 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.82 2010/05/15 08:53:27 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 		ri->ri_flg &= ~RI_NO_AUTO;
    272 		sc->nscreens = 1;
    273 	}
    274 	else {
    275 		ri = malloc(sizeof(struct rasops_info),
    276 			M_DEVBUF, M_NOWAIT|M_ZERO);
    277 		if (ri == NULL) {
    278 			printf(": can't alloc memory\n");
    279 			return;
    280 		}
    281 
    282 		ri->ri_hw = (void *)ta->ta_addr;
    283 		sfb_common_init(ri);
    284 		sc->sc_ri = ri;
    285 	}
    286 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    287 
    288 	sfb_cmap_init(sc);
    289 
    290 	sc->sc_vaddr = ta->ta_addr;
    291 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
    292 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
    293 	sc->sc_blanked = sc->sc_curenb = 0;
    294 
    295 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
    296 
    297 	asic = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
    298 
    299 	SFBWRITE32(asic, SFB_ASIC_CLEAR_INTR, 0);
    300 	SFBWRITE32(asic, SFB_ASIC_ENABLE_INTR, 1);
    301 
    302 	waa.console = console;
    303 	waa.scrdata = &sfb_screenlist;
    304 	waa.accessops = &sfb_accessops;
    305 	waa.accesscookie = sc;
    306 
    307 	config_found(self, &waa, wsemuldisplaydevprint);
    308 }
    309 
    310 static void
    311 sfb_cmap_init(struct sfb_softc *sc)
    312 {
    313 	struct hwcmap256 *cm;
    314 	const uint8_t *p;
    315 	int index;
    316 
    317 	cm = &sc->sc_cmap;
    318 	p = rasops_cmap;
    319 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    320 		cm->r[index] = p[0];
    321 		cm->g[index] = p[1];
    322 		cm->b[index] = p[2];
    323 	}
    324 }
    325 
    326 static void
    327 sfb_common_init(struct rasops_info *ri)
    328 {
    329 	char *base, *asic;
    330 	int hsetup, vsetup, vbase, cookie;
    331 
    332 	base = (void *)ri->ri_hw;
    333 	asic = base + SFB_ASIC_OFFSET;
    334 	hsetup = *(volatile uint32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
    335 	vsetup = *(volatile uint32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
    336 
    337 	vbase = 1;
    338 	SFBWRITE32(asic, SFB_ASIC_VIDEO_BASE, vbase);
    339 	SFBWRITE32(asic, SFB_ASIC_PLANEMASK, ~0);
    340 	SFBWRITE32(asic, SFB_ASIC_PIXELMASK, ~0);
    341 	SFBWRITE32(asic, SFB_ASIC_MODE, 0);	/* MODE_SIMPLE */
    342 	SFBWRITE32(asic, SFB_ASIC_ROP, 3); 	/* ROP_COPY */
    343 	SFBWRITE32(asic, 0x180000, 0); 		/* Bt459 reset */
    344 
    345 	/* initialize colormap and cursor hardware */
    346 	sfbhwinit(base);
    347 
    348 	ri->ri_flg = RI_CENTER;
    349 	if (ri == &sfb_console_ri)
    350 		ri->ri_flg |= RI_NO_AUTO;
    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, void *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 	char *asic;
    478 
    479 	ri = sc->sc_ri;
    480 	asic = (char *)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 	char *base, *asic, *vdac;
    554 	int v;
    555 
    556 	base = (void *)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 		uint8_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 		uint8_t *ip, *mp, img, msk;
    601 		uint8_t u;
    602 		int bcnt;
    603 
    604 		ip = (uint8_t *)sc->sc_cursor.cc_image;
    605 		mp = (uint8_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(void *base)
    652 {
    653 	char *vdac = (char *)base + SFB_RAMDAC_OFFSET;
    654 	const uint8_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) = (void *)(((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 	char *sfb, *p;
    908 	int scanspan, height, width, align, x, y;
    909 	uint32_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 = (char *)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 	char *sfb, *p;
    948 	int scanspan, height, width, align, x, y;
    949 	uint32_t lmask, rmask, glyph;
    950 	uint8_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 = (char *)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 = *(uint16_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 	void *sp, *dp, *basex, *sfb;
   1003 	int scanspan, height, width, aligns, alignd, shift, w, y;
   1004 	uint32_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 = (void *)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 		void *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 		void *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 	char *sfb, *p;
   1130 	int scanspan, startx, height, width, align, w, y;
   1131 	uint32_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 = (char *)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 		char *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 	char *sfb, *p;
   1189 	int scanspan, offset, srcy, height, width, align, w;
   1190 	uint32_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 = (char *)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 		char *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 	char *sfb, *p;
   1248 	int scanspan, starty, height, width, align, w;
   1249 	uint32_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 = (char *)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 		char *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