Home | History | Annotate | Line # | Download | only in tc
      1 /* $NetBSD: mfb.c,v 1.64 2021/12/06 16:00:07 abs 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: mfb.c,v 1.64 2021/12/06 16:00:07 abs 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/bt431reg.h>
     54 
     55 #if defined(pmax)
     56 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
     57 #endif
     58 
     59 #if defined(alpha)
     60 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
     61 #endif
     62 
     63 /* Bt455 hardware registers, memory-mapped in 32bit stride */
     64 #define	bt_reg	0x0
     65 #define	bt_cmap	0x4
     66 #define	bt_clr	0x8
     67 #define	bt_ovly	0xc
     68 
     69 /* Bt431 hardware registers, memory-mapped in 32bit stride */
     70 #define	bt_lo	0x0
     71 #define	bt_hi	0x4
     72 #define	bt_ram	0x8
     73 #define	bt_ctl	0xc
     74 
     75 #define	REGWRITE32(p,i,v) do {					\
     76 	*(volatile uint32_t *)((p) + (i)) = (v); tc_wmb();	\
     77     } while (0)
     78 
     79 #define	SELECT455(p,r) do {					\
     80 	REGWRITE32((p), bt_reg, (r));				\
     81 	REGWRITE32((p), bt_clr, 0);				\
     82    } while (0)
     83 
     84 #define	TWIN(x)    ((x)|((x) << 8))
     85 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
     86 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
     87 
     88 #define	SELECT431(p,r) do {					\
     89 	REGWRITE32((p), bt_lo, TWIN(r));			\
     90 	REGWRITE32((p), bt_hi, 0);				\
     91    } while (0)
     92 
     93 struct hwcursor64 {
     94 	struct wsdisplay_curpos cc_pos;
     95 	struct wsdisplay_curpos cc_hot;
     96 	struct wsdisplay_curpos cc_size;
     97 	struct wsdisplay_curpos cc_magic;
     98 #define	CURSOR_MAX_SIZE	64
     99 	uint8_t cc_color[6];
    100 	uint64_t cc_image[CURSOR_MAX_SIZE];
    101 	uint64_t cc_mask[CURSOR_MAX_SIZE];
    102 };
    103 
    104 struct mfb_softc {
    105 	vaddr_t sc_vaddr;
    106 	size_t sc_size;
    107 	struct rasops_info *sc_ri;
    108 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    109 	int sc_blanked;
    110 	int sc_curenb;			/* cursor sprite enabled */
    111 	int sc_changed;			/* need update of hardware */
    112 	int nscreens;
    113 };
    114 
    115 #define	MX_MAGIC_X	360
    116 #define	MX_MAGIC_Y	36
    117 
    118 #define	MX_FB_OFFSET	0x200000
    119 #define	MX_FB_SIZE	0x200000
    120 #define	MX_BT455_OFFSET	0x100000
    121 #define	MX_BT431_OFFSET	0x180000
    122 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
    123 
    124 static int  mfbmatch(device_t, cfdata_t, void *);
    125 static void mfbattach(device_t, device_t, void *);
    126 
    127 CFATTACH_DECL_NEW(mfb, sizeof(struct mfb_softc),
    128     mfbmatch, mfbattach, NULL, NULL);
    129 
    130 static void mfb_common_init(struct rasops_info *);
    131 static struct rasops_info mfb_console_ri;
    132 static tc_addr_t mfb_consaddr;
    133 
    134 static struct wsscreen_descr mfb_stdscreen = {
    135 	"std", 0, 0,
    136 	0, /* textops */
    137 	0, 0,
    138 	WSSCREEN_REVERSE
    139 };
    140 
    141 static const struct wsscreen_descr *_mfb_scrlist[] = {
    142 	&mfb_stdscreen,
    143 };
    144 
    145 static const struct wsscreen_list mfb_screenlist = {
    146 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
    147 };
    148 
    149 static int	mfbioctl(void *, void *, u_long, void *, int, struct lwp *);
    150 static paddr_t	mfbmmap(void *, void *, off_t, int);
    151 
    152 static int	mfb_alloc_screen(void *, const struct wsscreen_descr *,
    153 				      void **, int *, int *, long *);
    154 static void	mfb_free_screen(void *, void *);
    155 static int	mfb_show_screen(void *, void *, int,
    156 				     void (*) (void *, int, int), void *);
    157 
    158 static const struct wsdisplay_accessops mfb_accessops = {
    159 	mfbioctl,
    160 	mfbmmap,
    161 	mfb_alloc_screen,
    162 	mfb_free_screen,
    163 	mfb_show_screen,
    164 	0 /* load_font */
    165 };
    166 
    167 int  mfb_cnattach(tc_addr_t);
    168 static int  mfbintr(void *);
    169 static void mfbhwinit(void *);
    170 
    171 static int  set_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
    172 static int  get_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
    173 static void set_curpos(struct mfb_softc *, struct wsdisplay_curpos *);
    174 
    175 /* bit order reverse */
    176 static const uint8_t flip[256] = {
    177 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    178 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    179 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    180 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    181 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    182 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    183 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    184 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    185 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    186 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    187 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    188 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    189 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    190 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    191 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    192 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    193 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    194 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    195 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    196 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    197 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    198 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    199 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    200 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    201 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    202 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    203 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    204 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    205 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    206 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    207 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    208 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    209 };
    210 
    211 static int
    212 mfbmatch(device_t parent, cfdata_t match, void *aux)
    213 {
    214 	struct tc_attach_args *ta = aux;
    215 
    216 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    217 		return (0);
    218 
    219 	return (1);
    220 }
    221 
    222 static void
    223 mfbattach(device_t parent, device_t self, void *aux)
    224 {
    225 	struct mfb_softc *sc = device_private(self);
    226 	struct tc_attach_args *ta = aux;
    227 	struct rasops_info *ri;
    228 	struct wsemuldisplaydev_attach_args waa;
    229 	int console;
    230 	volatile register int junk;
    231 
    232 	console = (ta->ta_addr == mfb_consaddr);
    233 	if (console) {
    234 		sc->sc_ri = ri = &mfb_console_ri;
    235 		ri->ri_flg &= ~RI_NO_AUTO;
    236 		sc->nscreens = 1;
    237 	}
    238 	else {
    239 		ri = malloc(sizeof(struct rasops_info),
    240 			M_DEVBUF, M_WAITOK | M_ZERO);
    241 		ri->ri_hw = (void *)ta->ta_addr;
    242 		mfb_common_init(ri);
    243 		sc->sc_ri = ri;
    244 	}
    245 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
    246 
    247 	sc->sc_vaddr = ta->ta_addr;
    248 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
    249 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
    250 	sc->sc_blanked = sc->sc_curenb = 0;
    251 
    252 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
    253 
    254 	/* clear any pending interrupts */
    255 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
    256 	junk = *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
    257 	__USE(junk);
    258 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
    259 
    260 	waa.console = console;
    261 	waa.scrdata = &mfb_screenlist;
    262 	waa.accessops = &mfb_accessops;
    263 	waa.accesscookie = sc;
    264 
    265 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
    266 }
    267 
    268 static void
    269 mfb_common_init(struct rasops_info *ri)
    270 {
    271 	char *base;
    272 	int cookie;
    273 
    274 	base = (void *)ri->ri_hw;
    275 
    276 	/* initialize colormap and cursor hardware */
    277 	mfbhwinit(base);
    278 
    279 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
    280 	if (ri == &mfb_console_ri)
    281 		ri->ri_flg |= RI_NO_AUTO;
    282 	ri->ri_depth = 8;	/* !! watch out !! */
    283 	ri->ri_width = 1280;
    284 	ri->ri_height = 1024;
    285 	ri->ri_stride = 2048;
    286 	ri->ri_bits = base + MX_FB_OFFSET;
    287 
    288 	/* clear the screen */
    289 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    290 
    291 	wsfont_init();
    292 	/* prefer 12 pixel wide font */
    293 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    294 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    295 	if (cookie <= 0)
    296 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    297 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    298 	if (cookie <= 0) {
    299 		printf("mfb: font table is empty\n");
    300 		return;
    301 	}
    302 
    303 	if (wsfont_lock(cookie, &ri->ri_font)) {
    304 		printf("mfb: couldn't lock font\n");
    305 		return;
    306 	}
    307 	ri->ri_wsfcookie = cookie;
    308 
    309 	rasops_init(ri, 34, 80);
    310 
    311 	/* XXX shouldn't be global */
    312 	mfb_stdscreen.nrows = ri->ri_rows;
    313 	mfb_stdscreen.ncols = ri->ri_cols;
    314 	mfb_stdscreen.textops = &ri->ri_ops;
    315 	mfb_stdscreen.capabilities = ri->ri_caps;
    316 }
    317 
    318 static int
    319 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    320 {
    321 	struct mfb_softc *sc = v;
    322 	struct rasops_info *ri = sc->sc_ri;
    323 	int turnoff, s;
    324 
    325 	switch (cmd) {
    326 	case WSDISPLAYIO_GTYPE:
    327 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
    328 		return (0);
    329 
    330 	case WSDISPLAYIO_GET_FBINFO: {
    331 		struct wsdisplayio_fbinfo *fbi = data;
    332 		return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
    333 	}
    334 
    335 	case WSDISPLAYIO_GINFO:
    336 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    337 		wsd_fbip->height = ri->ri_height;
    338 		wsd_fbip->width = ri->ri_width;
    339 		wsd_fbip->depth = ri->ri_depth;
    340 		wsd_fbip->cmsize = 0;
    341 #undef fbt
    342 		return (0);
    343 
    344 	case WSDISPLAYIO_GETCMAP:
    345 	case WSDISPLAYIO_PUTCMAP:
    346 		return (EPASSTHROUGH);
    347 
    348 	case WSDISPLAYIO_SVIDEO:
    349 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    350 		if (sc->sc_blanked != turnoff) {
    351 			sc->sc_blanked = turnoff;
    352 #if 0	/* XXX later XXX */
    353 	To turn off,
    354 	- assign Bt455 cmap[1].green with value 0 (black),
    355 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
    356 #endif	/* XXX XXX XXX */
    357 		}
    358 		return (0);
    359 
    360 	case WSDISPLAYIO_GVIDEO:
    361 		*(u_int *)data = sc->sc_blanked ?
    362 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    363 		return (0);
    364 
    365 	case WSDISPLAYIO_GCURPOS:
    366 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    367 		return (0);
    368 
    369 	case WSDISPLAYIO_SCURPOS:
    370 		s = spltty();
    371 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    372 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    373 		splx(s);
    374 		return (0);
    375 
    376 	case WSDISPLAYIO_GCURMAX:
    377 		((struct wsdisplay_curpos *)data)->x =
    378 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    379 		return (0);
    380 
    381 	case WSDISPLAYIO_GCURSOR:
    382 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    383 
    384 	case WSDISPLAYIO_SCURSOR:
    385 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    386 
    387 	case WSDISPLAYIO_SMODE:
    388 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    389 			s = spltty();
    390 			sc->sc_curenb = 0;
    391 			sc->sc_blanked = 0;
    392 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
    393 			splx(s);
    394 		}
    395 		return (0);
    396 	}
    397 	return (EPASSTHROUGH);
    398 }
    399 
    400 static paddr_t
    401 mfbmmap(void *v, void *vs, off_t offset, int prot)
    402 {
    403 	struct mfb_softc *sc = v;
    404 
    405 	if (offset >= MX_FB_SIZE || offset < 0)
    406 		return (-1);
    407 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
    408 }
    409 
    410 static int
    411 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    412     int *curxp, int *curyp, long *attrp)
    413 {
    414 	struct mfb_softc *sc = v;
    415 	struct rasops_info *ri = sc->sc_ri;
    416 	long defattr;
    417 
    418 	if (sc->nscreens > 0)
    419 		return (ENOMEM);
    420 
    421 	*cookiep = ri;		 /* one and only for now */
    422 	*curxp = 0;
    423 	*curyp = 0;
    424 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    425 	*attrp = defattr;
    426 	sc->nscreens++;
    427 	return (0);
    428 }
    429 
    430 static void
    431 mfb_free_screen(void *v, void *cookie)
    432 {
    433 	struct mfb_softc *sc = v;
    434 
    435 	if (sc->sc_ri == &mfb_console_ri)
    436 		panic("mfb_free_screen: console");
    437 
    438 	sc->nscreens--;
    439 }
    440 
    441 static int
    442 mfb_show_screen(void *v, void *cookie, int waitok,
    443     void (*cb)(void *, int, int), void *cbarg)
    444 {
    445 
    446 	return (0);
    447 }
    448 
    449 /* EXPORT */ int
    450 mfb_cnattach(tc_addr_t addr)
    451 {
    452 	struct rasops_info *ri;
    453 	long defattr;
    454 
    455 	ri = &mfb_console_ri;
    456 	ri->ri_hw = (void *)addr;
    457 	mfb_common_init(ri);
    458 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    459 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
    460 	mfb_consaddr = addr;
    461 	return (0);
    462 }
    463 
    464 static int
    465 mfbintr(void *arg)
    466 {
    467 	struct mfb_softc *sc = arg;
    468 	char *base, *vdac, *curs;
    469 	int v;
    470 	volatile register int junk;
    471 
    472 	base = (void *)sc->sc_ri->ri_hw;
    473 	junk = *(uint8_t *)(base + MX_IREQ_OFFSET);
    474 	__USE(junk);
    475 #if 0
    476 	*(uint8_t *)(base + MX_IREQ_OFFSET) = 0;
    477 #endif
    478 	if (sc->sc_changed == 0)
    479 		return (1);
    480 
    481 	vdac = base + MX_BT455_OFFSET;
    482 	curs = base + MX_BT431_OFFSET;
    483 	v = sc->sc_changed;
    484 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    485 		int  onoff;
    486 
    487 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
    488 		SELECT431(curs, BT431_REG_COMMAND);
    489 		REGWRITE32(curs, bt_ctl, onoff);
    490 	}
    491 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    492 		int x, y;
    493 		uint32_t twin;
    494 
    495 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    496 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    497 
    498 		x += sc->sc_cursor.cc_magic.x;
    499 		y += sc->sc_cursor.cc_magic.y;
    500 
    501 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    502 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
    503 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
    504 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
    505 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
    506 	}
    507 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    508 		uint8_t *cp = sc->sc_cursor.cc_color;
    509 
    510 		SELECT455(vdac, 8);
    511 		REGWRITE32(vdac, bt_cmap, 0);
    512 		REGWRITE32(vdac, bt_cmap, cp[1]);
    513 		REGWRITE32(vdac, bt_cmap, 0);
    514 
    515 		REGWRITE32(vdac, bt_cmap, 0);
    516 		REGWRITE32(vdac, bt_cmap, cp[1]);
    517 		REGWRITE32(vdac, bt_cmap, 0);
    518 
    519 		REGWRITE32(vdac, bt_ovly, 0);
    520 		REGWRITE32(vdac, bt_ovly, cp[0]);
    521 		REGWRITE32(vdac, bt_ovly, 0);
    522 	}
    523 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    524 		uint8_t *ip, *mp, img, msk;
    525 		int bcnt;
    526 
    527 		ip = (uint8_t *)sc->sc_cursor.cc_image;
    528 		mp = (uint8_t *)sc->sc_cursor.cc_mask;
    529 		bcnt = 0;
    530 		SELECT431(curs, BT431_REG_CRAM_BASE);
    531 
    532 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    533 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    534 			/* pad right half 32 pixel when smaller than 33 */
    535 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    536 				REGWRITE32(curs, bt_ram, 0);
    537 			}
    538 			else {
    539 				int half;
    540 
    541 				img = *ip++;
    542 				msk = *mp++;
    543 				img &= msk;	/* cookie off image */
    544 				half = (flip[msk] << 8) | flip[img];
    545 				REGWRITE32(curs, bt_ram, half);
    546 			}
    547 			bcnt += 2;
    548 		}
    549 		/* pad unoccupied scan lines */
    550 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    551 			REGWRITE32(curs, bt_ram, 0);
    552 			bcnt += 2;
    553 		}
    554 	}
    555 	sc->sc_changed = 0;
    556 	return (1);
    557 }
    558 
    559 static void
    560 mfbhwinit(void *mfbbase)
    561 {
    562 	char *vdac, *curs;
    563 	int i;
    564 
    565 	vdac = (char *)mfbbase + MX_BT455_OFFSET;
    566 	curs = (char *)mfbbase + MX_BT431_OFFSET;
    567 	SELECT431(curs, BT431_REG_COMMAND);
    568 	REGWRITE32(curs, bt_ctl, 0x0404);
    569 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
    570 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
    571 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
    572 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
    573 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
    574 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
    575 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    576 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    577 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
    578 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
    579 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
    580 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
    581 
    582 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
    583 	SELECT455(vdac, 0);
    584 	REGWRITE32(vdac, bt_cmap, 0);
    585 	REGWRITE32(vdac, bt_cmap, 0);
    586 	REGWRITE32(vdac, bt_cmap, 0);
    587 	REGWRITE32(vdac, bt_cmap, 0);
    588 	REGWRITE32(vdac, bt_cmap, 0xff);
    589 	REGWRITE32(vdac, bt_cmap, 0);
    590 	for (i = 2; i < 16; i++) {
    591 		REGWRITE32(vdac, bt_cmap, 0);
    592 		REGWRITE32(vdac, bt_cmap, 0);
    593 		REGWRITE32(vdac, bt_cmap, 0);
    594 	}
    595 	REGWRITE32(vdac, bt_ovly, 0);
    596 	REGWRITE32(vdac, bt_ovly, 0xff);
    597 	REGWRITE32(vdac, bt_ovly, 0);
    598 
    599 	SELECT431(curs, BT431_REG_CRAM_BASE);
    600 	for (i = 0; i < 512; i++) {
    601 		REGWRITE32(curs, bt_ram, 0);
    602 	}
    603 }
    604 
    605 static int
    606 set_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
    607 {
    608 #define	cc (&sc->sc_cursor)
    609 	u_int v, count = 0, icount = 0, index = 0;
    610 	uint64_t image[CURSOR_MAX_SIZE];
    611 	uint64_t mask[CURSOR_MAX_SIZE];
    612 	uint8_t color[6];
    613 	int error, s;
    614 
    615 	v = p->which;
    616 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    617 		index = p->cmap.index;
    618 		count = p->cmap.count;
    619 		if (index >= 2 || count > 2 - index)
    620 			return (EINVAL);
    621 		error = copyin(p->cmap.red, &color[index], count);
    622 		if (error)
    623 			return error;
    624 	}
    625 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    626 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    627 			return (EINVAL);
    628 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    629 		error = copyin(p->image, image, icount);
    630 		if (error)
    631 			return error;
    632 		error = copyin(p->mask, mask, icount);
    633 		if (error)
    634 			return error;
    635 	}
    636 
    637 	s = spltty();
    638 	if (v & WSDISPLAY_CURSOR_DOCUR)
    639 		sc->sc_curenb = p->enable;
    640 	if (v & WSDISPLAY_CURSOR_DOPOS)
    641 		set_curpos(sc, &p->pos);
    642 	if (v & WSDISPLAY_CURSOR_DOHOT)
    643 		cc->cc_hot = p->hot;
    644 	if (v & WSDISPLAY_CURSOR_DOCMAP)
    645 		memcpy(&cc->cc_color[index], &color[index], count);
    646 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    647 		cc->cc_size = p->size;
    648 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    649 		memcpy(cc->cc_image, image, icount);
    650 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    651 		memcpy(cc->cc_mask, mask, icount);
    652 	}
    653 	sc->sc_changed |= v;
    654 	splx(s);
    655 
    656 	return (0);
    657 #undef cc
    658 }
    659 
    660 static int
    661 get_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
    662 {
    663 	return (EPASSTHROUGH); /* XXX */
    664 }
    665 
    666 static void
    667 set_curpos(struct mfb_softc *sc, struct wsdisplay_curpos *curpos)
    668 {
    669 	struct rasops_info *ri = sc->sc_ri;
    670 	int x = curpos->x, y = curpos->y;
    671 
    672 	if (y < 0)
    673 		y = 0;
    674 	else if (y > ri->ri_height)
    675 		y = ri->ri_height;
    676 	if (x < 0)
    677 		x = 0;
    678 	else if (x > ri->ri_width)
    679 		x = ri->ri_width;
    680 	sc->sc_cursor.cc_pos.x = x;
    681 	sc->sc_cursor.cc_pos.y = y;
    682 }
    683