Home | History | Annotate | Line # | Download | only in tc
mfb.c revision 1.48
      1 /* $NetBSD: mfb.c,v 1.48 2007/03/04 06:02:46 christos Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Tohru Nishimura
     17  *	for the NetBSD Project.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.48 2007/03/04 06:02:46 christos Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/device.h>
     40 #include <sys/malloc.h>
     41 #include <sys/buf.h>
     42 #include <sys/ioctl.h>
     43 
     44 #include <machine/bus.h>
     45 #include <machine/intr.h>
     46 
     47 #include <dev/wscons/wsconsio.h>
     48 #include <dev/wscons/wsdisplayvar.h>
     49 
     50 #include <dev/rasops/rasops.h>
     51 #include <dev/wsfont/wsfont.h>
     52 
     53 #include <dev/tc/tcvar.h>
     54 #include <dev/ic/bt431reg.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 /* Bt455 hardware registers, memory-mapped in 32bit stride */
     67 #define	bt_reg	0x0
     68 #define	bt_cmap	0x4
     69 #define	bt_clr	0x8
     70 #define	bt_ovly	0xc
     71 
     72 /* Bt431 hardware registers, memory-mapped in 32bit stride */
     73 #define	bt_lo	0x0
     74 #define	bt_hi	0x4
     75 #define	bt_ram	0x8
     76 #define	bt_ctl	0xc
     77 
     78 #define	REGWRITE32(p,i,v) do {					\
     79 	*(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb();	\
     80     } while (0)
     81 
     82 #define	SELECT455(p,r) do {					\
     83 	REGWRITE32((p), bt_reg, (r));				\
     84 	REGWRITE32((p), bt_clr, 0);				\
     85    } while (0)
     86 
     87 #define	TWIN(x)    ((x)|((x) << 8))
     88 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
     89 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
     90 
     91 #define	SELECT431(p,r) do {					\
     92 	REGWRITE32((p), bt_lo, TWIN(r));			\
     93 	REGWRITE32((p), bt_hi, 0);				\
     94    } while (0)
     95 
     96 struct hwcursor64 {
     97 	struct wsdisplay_curpos cc_pos;
     98 	struct wsdisplay_curpos cc_hot;
     99 	struct wsdisplay_curpos cc_size;
    100 	struct wsdisplay_curpos cc_magic;
    101 #define	CURSOR_MAX_SIZE	64
    102 	u_int8_t cc_color[6];
    103 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    104 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
    105 };
    106 
    107 struct mfb_softc {
    108 	struct device sc_dev;
    109 	vaddr_t sc_vaddr;
    110 	size_t sc_size;
    111 	struct rasops_info *sc_ri;
    112 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    113 	int sc_blanked;
    114 	int sc_curenb;			/* cursor sprite enabled */
    115 	int sc_changed;			/* need update of hardware */
    116 	int nscreens;
    117 };
    118 
    119 #define	MX_MAGIC_X	360
    120 #define	MX_MAGIC_Y	36
    121 
    122 #define	MX_FB_OFFSET	0x200000
    123 #define	MX_FB_SIZE	0x200000
    124 #define	MX_BT455_OFFSET	0x100000
    125 #define	MX_BT431_OFFSET	0x180000
    126 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
    127 
    128 static int  mfbmatch(struct device *, struct cfdata *, void *);
    129 static void mfbattach(struct device *, struct device *, void *);
    130 
    131 CFATTACH_DECL(mfb, sizeof(struct mfb_softc),
    132     mfbmatch, mfbattach, NULL, NULL);
    133 
    134 static void mfb_common_init(struct rasops_info *);
    135 static struct rasops_info mfb_console_ri;
    136 static tc_addr_t mfb_consaddr;
    137 
    138 static struct wsscreen_descr mfb_stdscreen = {
    139 	"std", 0, 0,
    140 	0, /* textops */
    141 	0, 0,
    142 	WSSCREEN_REVERSE
    143 };
    144 
    145 static const struct wsscreen_descr *_mfb_scrlist[] = {
    146 	&mfb_stdscreen,
    147 };
    148 
    149 static const struct wsscreen_list mfb_screenlist = {
    150 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
    151 };
    152 
    153 static int	mfbioctl(void *, void *, u_long, void *, int, struct lwp *);
    154 static paddr_t	mfbmmap(void *, void *, off_t, int);
    155 
    156 static int	mfb_alloc_screen(void *, const struct wsscreen_descr *,
    157 				      void **, int *, int *, long *);
    158 static void	mfb_free_screen(void *, void *);
    159 static int	mfb_show_screen(void *, void *, int,
    160 				     void (*) (void *, int, int), void *);
    161 
    162 static const struct wsdisplay_accessops mfb_accessops = {
    163 	mfbioctl,
    164 	mfbmmap,
    165 	mfb_alloc_screen,
    166 	mfb_free_screen,
    167 	mfb_show_screen,
    168 	0 /* load_font */
    169 };
    170 
    171 int  mfb_cnattach(tc_addr_t);
    172 static int  mfbintr(void *);
    173 static void mfbhwinit(void *);
    174 
    175 static int  set_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
    176 static int  get_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
    177 static void set_curpos(struct mfb_softc *, struct wsdisplay_curpos *);
    178 
    179 /* bit order reverse */
    180 static const u_int8_t flip[256] = {
    181 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    182 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    183 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    184 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    185 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    186 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    187 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    188 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    189 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    190 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    191 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    192 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    193 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    194 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    195 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    196 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    197 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    198 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    199 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    200 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    201 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    202 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    203 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    204 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    205 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    206 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    207 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    208 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    209 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    210 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    211 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    212 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    213 };
    214 
    215 static int
    216 mfbmatch(struct device *parent, struct cfdata *match, void *aux)
    217 {
    218 	struct tc_attach_args *ta = aux;
    219 
    220 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    221 		return (0);
    222 
    223 	return (1);
    224 }
    225 
    226 static void
    227 mfbattach(struct device *parent, struct device *self, void *aux)
    228 {
    229 	struct mfb_softc *sc = device_private(self);
    230 	struct tc_attach_args *ta = aux;
    231 	struct rasops_info *ri;
    232 	struct wsemuldisplaydev_attach_args waa;
    233 	int console;
    234 	volatile register int junk;
    235 
    236 	console = (ta->ta_addr == mfb_consaddr);
    237 	if (console) {
    238 		sc->sc_ri = ri = &mfb_console_ri;
    239 		sc->nscreens = 1;
    240 	}
    241 	else {
    242 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    243 			M_DEVBUF, M_NOWAIT);
    244 		if (ri == NULL) {
    245 			printf(": can't alloc memory\n");
    246 			return;
    247 		}
    248 		memset(ri, 0, sizeof(struct rasops_info));
    249 
    250 		ri->ri_hw = (void *)ta->ta_addr;
    251 		mfb_common_init(ri);
    252 		sc->sc_ri = ri;
    253 	}
    254 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
    255 
    256 	sc->sc_vaddr = ta->ta_addr;
    257 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
    258 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
    259 	sc->sc_blanked = sc->sc_curenb = 0;
    260 
    261 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
    262 
    263 	/* clear any pending interrupts */
    264 	*(u_int8_t *)((void *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
    265 	junk = *(u_int8_t *)((void *)ri->ri_hw + MX_IREQ_OFFSET);
    266 	*(u_int8_t *)((void *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
    267 
    268 	waa.console = console;
    269 	waa.scrdata = &mfb_screenlist;
    270 	waa.accessops = &mfb_accessops;
    271 	waa.accesscookie = sc;
    272 
    273 	config_found(self, &waa, wsemuldisplaydevprint);
    274 }
    275 
    276 static void
    277 mfb_common_init(struct rasops_info *ri)
    278 {
    279 	void *base;
    280 	int cookie;
    281 
    282 	base = (void *)ri->ri_hw;
    283 
    284 	/* initialize colormap and cursor hardware */
    285 	mfbhwinit(base);
    286 
    287 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
    288 	ri->ri_depth = 8;	/* !! watch out !! */
    289 	ri->ri_width = 1280;
    290 	ri->ri_height = 1024;
    291 	ri->ri_stride = 2048;
    292 	ri->ri_bits = base + MX_FB_OFFSET;
    293 
    294 	/* clear the screen */
    295 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    296 
    297 	wsfont_init();
    298 	/* prefer 12 pixel wide font */
    299 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    300 	    WSDISPLAY_FONTORDER_L2R);
    301 	if (cookie <= 0)
    302 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    303 		    WSDISPLAY_FONTORDER_L2R);
    304 	if (cookie <= 0) {
    305 		printf("mfb: font table is empty\n");
    306 		return;
    307 	}
    308 
    309 	if (wsfont_lock(cookie, &ri->ri_font)) {
    310 		printf("mfb: couldn't lock font\n");
    311 		return;
    312 	}
    313 	ri->ri_wsfcookie = cookie;
    314 
    315 	rasops_init(ri, 34, 80);
    316 
    317 	/* XXX shouldn't be global */
    318 	mfb_stdscreen.nrows = ri->ri_rows;
    319 	mfb_stdscreen.ncols = ri->ri_cols;
    320 	mfb_stdscreen.textops = &ri->ri_ops;
    321 	mfb_stdscreen.capabilities = ri->ri_caps;
    322 }
    323 
    324 static int
    325 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    326 {
    327 	struct mfb_softc *sc = v;
    328 	struct rasops_info *ri = sc->sc_ri;
    329 	int turnoff, s;
    330 
    331 	switch (cmd) {
    332 	case WSDISPLAYIO_GTYPE:
    333 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
    334 		return (0);
    335 
    336 	case WSDISPLAYIO_GINFO:
    337 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    338 		wsd_fbip->height = ri->ri_height;
    339 		wsd_fbip->width = ri->ri_width;
    340 		wsd_fbip->depth = ri->ri_depth;
    341 		wsd_fbip->cmsize = 0;
    342 #undef fbt
    343 		return (0);
    344 
    345 	case WSDISPLAYIO_GETCMAP:
    346 	case WSDISPLAYIO_PUTCMAP:
    347 		return (EPASSTHROUGH);
    348 
    349 	case WSDISPLAYIO_SVIDEO:
    350 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    351 		if (sc->sc_blanked != turnoff) {
    352 			sc->sc_blanked = turnoff;
    353 #if 0	/* XXX later XXX */
    354 	To turn off,
    355 	- assign Bt455 cmap[1].green with value 0 (black),
    356 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
    357 #endif	/* XXX XXX XXX */
    358 		}
    359 		return (0);
    360 
    361 	case WSDISPLAYIO_GVIDEO:
    362 		*(u_int *)data = sc->sc_blanked ?
    363 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    364 		return (0);
    365 
    366 	case WSDISPLAYIO_GCURPOS:
    367 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    368 		return (0);
    369 
    370 	case WSDISPLAYIO_SCURPOS:
    371 		s = spltty();
    372 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    373 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    374 		splx(s);
    375 		return (0);
    376 
    377 	case WSDISPLAYIO_GCURMAX:
    378 		((struct wsdisplay_curpos *)data)->x =
    379 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    380 		return (0);
    381 
    382 	case WSDISPLAYIO_GCURSOR:
    383 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    384 
    385 	case WSDISPLAYIO_SCURSOR:
    386 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    387 
    388 	case WSDISPLAYIO_SMODE:
    389 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    390 			s = spltty();
    391 			sc->sc_curenb = 0;
    392 			sc->sc_blanked = 0;
    393 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
    394 			splx(s);
    395 		}
    396 		return (0);
    397 	}
    398 	return (EPASSTHROUGH);
    399 }
    400 
    401 static paddr_t
    402 mfbmmap(void *v, void *vs, off_t offset, int prot)
    403 {
    404 	struct mfb_softc *sc = v;
    405 
    406 	if (offset >= MX_FB_SIZE || offset < 0)
    407 		return (-1);
    408 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
    409 }
    410 
    411 static int
    412 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    413     int *curxp, int *curyp, long *attrp)
    414 {
    415 	struct mfb_softc *sc = v;
    416 	struct rasops_info *ri = sc->sc_ri;
    417 	long defattr;
    418 
    419 	if (sc->nscreens > 0)
    420 		return (ENOMEM);
    421 
    422 	*cookiep = ri;		 /* one and only for now */
    423 	*curxp = 0;
    424 	*curyp = 0;
    425 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    426 	*attrp = defattr;
    427 	sc->nscreens++;
    428 	return (0);
    429 }
    430 
    431 static void
    432 mfb_free_screen(void *v, void *cookie)
    433 {
    434 	struct mfb_softc *sc = v;
    435 
    436 	if (sc->sc_ri == &mfb_console_ri)
    437 		panic("mfb_free_screen: console");
    438 
    439 	sc->nscreens--;
    440 }
    441 
    442 static int
    443 mfb_show_screen(void *v, void *cookie, int waitok,
    444     void (*cb)(void *, int, int), void *cbarg)
    445 {
    446 
    447 	return (0);
    448 }
    449 
    450 /* EXPORT */ int
    451 mfb_cnattach(tc_addr_t addr)
    452 {
    453 	struct rasops_info *ri;
    454 	long defattr;
    455 
    456 	ri = &mfb_console_ri;
    457 	ri->ri_hw = (void *)addr;
    458 	mfb_common_init(ri);
    459 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    460 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
    461 	mfb_consaddr = addr;
    462 	return (0);
    463 }
    464 
    465 static int
    466 mfbintr(void *arg)
    467 {
    468 	struct mfb_softc *sc = arg;
    469 	void *base, vdac, curs;
    470 	int v;
    471 	volatile register int junk;
    472 
    473 	base = (void *)sc->sc_ri->ri_hw;
    474 	junk = *(u_int8_t *)(base + MX_IREQ_OFFSET);
    475 #if 0
    476 	*(u_int8_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 		u_int32_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 		u_int8_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 		u_int8_t *ip, *mp, img, msk;
    525 		int bcnt;
    526 
    527 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    528 		mp = (u_int8_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 	void *vdac, curs;
    563 	int i;
    564 
    565 	vdac = mfbbase + MX_BT455_OFFSET;
    566 	curs = 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 || (index + count) > 2)
    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