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