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