Home | History | Annotate | Line # | Download | only in tc
mfb.c revision 1.52
      1 /* $NetBSD: mfb.c,v 1.52 2008/07/09 13:19:33 joerg 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.52 2008/07/09 13:19:33 joerg 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 u_int32_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 	u_int8_t cc_color[6];
    102 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    103 	u_int64_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 u_int8_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 		sc->nscreens = 1;
    238 	}
    239 	else {
    240 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    241 			M_DEVBUF, M_NOWAIT);
    242 		if (ri == NULL) {
    243 			printf(": can't alloc memory\n");
    244 			return;
    245 		}
    246 		memset(ri, 0, sizeof(struct rasops_info));
    247 
    248 		ri->ri_hw = (void *)ta->ta_addr;
    249 		mfb_common_init(ri);
    250 		sc->sc_ri = ri;
    251 	}
    252 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
    253 
    254 	sc->sc_vaddr = ta->ta_addr;
    255 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
    256 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
    257 	sc->sc_blanked = sc->sc_curenb = 0;
    258 
    259 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
    260 
    261 	/* clear any pending interrupts */
    262 	*(u_int8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
    263 	junk = *(u_int8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
    264 	*(u_int8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
    265 
    266 	waa.console = console;
    267 	waa.scrdata = &mfb_screenlist;
    268 	waa.accessops = &mfb_accessops;
    269 	waa.accesscookie = sc;
    270 
    271 	config_found(self, &waa, wsemuldisplaydevprint);
    272 }
    273 
    274 static void
    275 mfb_common_init(struct rasops_info *ri)
    276 {
    277 	char *base;
    278 	int cookie;
    279 
    280 	base = (void *)ri->ri_hw;
    281 
    282 	/* initialize colormap and cursor hardware */
    283 	mfbhwinit(base);
    284 
    285 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
    286 	ri->ri_depth = 8;	/* !! watch out !! */
    287 	ri->ri_width = 1280;
    288 	ri->ri_height = 1024;
    289 	ri->ri_stride = 2048;
    290 	ri->ri_bits = base + MX_FB_OFFSET;
    291 
    292 	/* clear the screen */
    293 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    294 
    295 	wsfont_init();
    296 	/* prefer 12 pixel wide font */
    297 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    298 	    WSDISPLAY_FONTORDER_L2R);
    299 	if (cookie <= 0)
    300 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    301 		    WSDISPLAY_FONTORDER_L2R);
    302 	if (cookie <= 0) {
    303 		printf("mfb: font table is empty\n");
    304 		return;
    305 	}
    306 
    307 	if (wsfont_lock(cookie, &ri->ri_font)) {
    308 		printf("mfb: couldn't lock font\n");
    309 		return;
    310 	}
    311 	ri->ri_wsfcookie = cookie;
    312 
    313 	rasops_init(ri, 34, 80);
    314 
    315 	/* XXX shouldn't be global */
    316 	mfb_stdscreen.nrows = ri->ri_rows;
    317 	mfb_stdscreen.ncols = ri->ri_cols;
    318 	mfb_stdscreen.textops = &ri->ri_ops;
    319 	mfb_stdscreen.capabilities = ri->ri_caps;
    320 }
    321 
    322 static int
    323 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    324 {
    325 	struct mfb_softc *sc = v;
    326 	struct rasops_info *ri = sc->sc_ri;
    327 	int turnoff, s;
    328 
    329 	switch (cmd) {
    330 	case WSDISPLAYIO_GTYPE:
    331 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
    332 		return (0);
    333 
    334 	case WSDISPLAYIO_GINFO:
    335 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    336 		wsd_fbip->height = ri->ri_height;
    337 		wsd_fbip->width = ri->ri_width;
    338 		wsd_fbip->depth = ri->ri_depth;
    339 		wsd_fbip->cmsize = 0;
    340 #undef fbt
    341 		return (0);
    342 
    343 	case WSDISPLAYIO_GETCMAP:
    344 	case WSDISPLAYIO_PUTCMAP:
    345 		return (EPASSTHROUGH);
    346 
    347 	case WSDISPLAYIO_SVIDEO:
    348 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    349 		if (sc->sc_blanked != turnoff) {
    350 			sc->sc_blanked = turnoff;
    351 #if 0	/* XXX later XXX */
    352 	To turn off,
    353 	- assign Bt455 cmap[1].green with value 0 (black),
    354 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
    355 #endif	/* XXX XXX XXX */
    356 		}
    357 		return (0);
    358 
    359 	case WSDISPLAYIO_GVIDEO:
    360 		*(u_int *)data = sc->sc_blanked ?
    361 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    362 		return (0);
    363 
    364 	case WSDISPLAYIO_GCURPOS:
    365 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    366 		return (0);
    367 
    368 	case WSDISPLAYIO_SCURPOS:
    369 		s = spltty();
    370 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    371 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    372 		splx(s);
    373 		return (0);
    374 
    375 	case WSDISPLAYIO_GCURMAX:
    376 		((struct wsdisplay_curpos *)data)->x =
    377 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    378 		return (0);
    379 
    380 	case WSDISPLAYIO_GCURSOR:
    381 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    382 
    383 	case WSDISPLAYIO_SCURSOR:
    384 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    385 
    386 	case WSDISPLAYIO_SMODE:
    387 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    388 			s = spltty();
    389 			sc->sc_curenb = 0;
    390 			sc->sc_blanked = 0;
    391 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
    392 			splx(s);
    393 		}
    394 		return (0);
    395 	}
    396 	return (EPASSTHROUGH);
    397 }
    398 
    399 static paddr_t
    400 mfbmmap(void *v, void *vs, off_t offset, int prot)
    401 {
    402 	struct mfb_softc *sc = v;
    403 
    404 	if (offset >= MX_FB_SIZE || offset < 0)
    405 		return (-1);
    406 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
    407 }
    408 
    409 static int
    410 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    411     int *curxp, int *curyp, long *attrp)
    412 {
    413 	struct mfb_softc *sc = v;
    414 	struct rasops_info *ri = sc->sc_ri;
    415 	long defattr;
    416 
    417 	if (sc->nscreens > 0)
    418 		return (ENOMEM);
    419 
    420 	*cookiep = ri;		 /* one and only for now */
    421 	*curxp = 0;
    422 	*curyp = 0;
    423 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    424 	*attrp = defattr;
    425 	sc->nscreens++;
    426 	return (0);
    427 }
    428 
    429 static void
    430 mfb_free_screen(void *v, void *cookie)
    431 {
    432 	struct mfb_softc *sc = v;
    433 
    434 	if (sc->sc_ri == &mfb_console_ri)
    435 		panic("mfb_free_screen: console");
    436 
    437 	sc->nscreens--;
    438 }
    439 
    440 static int
    441 mfb_show_screen(void *v, void *cookie, int waitok,
    442     void (*cb)(void *, int, int), void *cbarg)
    443 {
    444 
    445 	return (0);
    446 }
    447 
    448 /* EXPORT */ int
    449 mfb_cnattach(tc_addr_t addr)
    450 {
    451 	struct rasops_info *ri;
    452 	long defattr;
    453 
    454 	ri = &mfb_console_ri;
    455 	ri->ri_hw = (void *)addr;
    456 	mfb_common_init(ri);
    457 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    458 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
    459 	mfb_consaddr = addr;
    460 	return (0);
    461 }
    462 
    463 static int
    464 mfbintr(void *arg)
    465 {
    466 	struct mfb_softc *sc = arg;
    467 	char *base, *vdac, *curs;
    468 	int v;
    469 	volatile register int junk;
    470 
    471 	base = (void *)sc->sc_ri->ri_hw;
    472 	junk = *(u_int8_t *)(base + MX_IREQ_OFFSET);
    473 #if 0
    474 	*(u_int8_t *)(base + MX_IREQ_OFFSET) = 0;
    475 #endif
    476 	if (sc->sc_changed == 0)
    477 		return (1);
    478 
    479 	vdac = base + MX_BT455_OFFSET;
    480 	curs = base + MX_BT431_OFFSET;
    481 	v = sc->sc_changed;
    482 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    483 		int  onoff;
    484 
    485 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
    486 		SELECT431(curs, BT431_REG_COMMAND);
    487 		REGWRITE32(curs, bt_ctl, onoff);
    488 	}
    489 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    490 		int x, y;
    491 		u_int32_t twin;
    492 
    493 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    494 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    495 
    496 		x += sc->sc_cursor.cc_magic.x;
    497 		y += sc->sc_cursor.cc_magic.y;
    498 
    499 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    500 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
    501 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
    502 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
    503 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
    504 	}
    505 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    506 		u_int8_t *cp = sc->sc_cursor.cc_color;
    507 
    508 		SELECT455(vdac, 8);
    509 		REGWRITE32(vdac, bt_cmap, 0);
    510 		REGWRITE32(vdac, bt_cmap, cp[1]);
    511 		REGWRITE32(vdac, bt_cmap, 0);
    512 
    513 		REGWRITE32(vdac, bt_cmap, 0);
    514 		REGWRITE32(vdac, bt_cmap, cp[1]);
    515 		REGWRITE32(vdac, bt_cmap, 0);
    516 
    517 		REGWRITE32(vdac, bt_ovly, 0);
    518 		REGWRITE32(vdac, bt_ovly, cp[0]);
    519 		REGWRITE32(vdac, bt_ovly, 0);
    520 	}
    521 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    522 		u_int8_t *ip, *mp, img, msk;
    523 		int bcnt;
    524 
    525 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    526 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    527 		bcnt = 0;
    528 		SELECT431(curs, BT431_REG_CRAM_BASE);
    529 
    530 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    531 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    532 			/* pad right half 32 pixel when smaller than 33 */
    533 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    534 				REGWRITE32(curs, bt_ram, 0);
    535 			}
    536 			else {
    537 				int half;
    538 
    539 				img = *ip++;
    540 				msk = *mp++;
    541 				img &= msk;	/* cookie off image */
    542 				half = (flip[msk] << 8) | flip[img];
    543 				REGWRITE32(curs, bt_ram, half);
    544 			}
    545 			bcnt += 2;
    546 		}
    547 		/* pad unoccupied scan lines */
    548 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    549 			REGWRITE32(curs, bt_ram, 0);
    550 			bcnt += 2;
    551 		}
    552 	}
    553 	sc->sc_changed = 0;
    554 	return (1);
    555 }
    556 
    557 static void
    558 mfbhwinit(void *mfbbase)
    559 {
    560 	char *vdac, *curs;
    561 	int i;
    562 
    563 	vdac = (char *)mfbbase + MX_BT455_OFFSET;
    564 	curs = (char *)mfbbase + MX_BT431_OFFSET;
    565 	SELECT431(curs, BT431_REG_COMMAND);
    566 	REGWRITE32(curs, bt_ctl, 0x0404);
    567 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
    568 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
    569 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
    570 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
    571 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
    572 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
    573 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    574 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    575 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
    576 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
    577 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
    578 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
    579 
    580 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
    581 	SELECT455(vdac, 0);
    582 	REGWRITE32(vdac, bt_cmap, 0);
    583 	REGWRITE32(vdac, bt_cmap, 0);
    584 	REGWRITE32(vdac, bt_cmap, 0);
    585 	REGWRITE32(vdac, bt_cmap, 0);
    586 	REGWRITE32(vdac, bt_cmap, 0xff);
    587 	REGWRITE32(vdac, bt_cmap, 0);
    588 	for (i = 2; i < 16; i++) {
    589 		REGWRITE32(vdac, bt_cmap, 0);
    590 		REGWRITE32(vdac, bt_cmap, 0);
    591 		REGWRITE32(vdac, bt_cmap, 0);
    592 	}
    593 	REGWRITE32(vdac, bt_ovly, 0);
    594 	REGWRITE32(vdac, bt_ovly, 0xff);
    595 	REGWRITE32(vdac, bt_ovly, 0);
    596 
    597 	SELECT431(curs, BT431_REG_CRAM_BASE);
    598 	for (i = 0; i < 512; i++) {
    599 		REGWRITE32(curs, bt_ram, 0);
    600 	}
    601 }
    602 
    603 static int
    604 set_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
    605 {
    606 #define	cc (&sc->sc_cursor)
    607 	u_int v, count = 0, icount = 0, index = 0;
    608 	uint64_t image[CURSOR_MAX_SIZE];
    609 	uint64_t mask[CURSOR_MAX_SIZE];
    610 	uint8_t color[6];
    611 	int error, s;
    612 
    613 	v = p->which;
    614 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    615 		index = p->cmap.index;
    616 		count = p->cmap.count;
    617 		if (index >= 2 || (index + count) > 2)
    618 			return (EINVAL);
    619 		error = copyin(p->cmap.red, &color[index], count);
    620 		if (error)
    621 			return error;
    622 	}
    623 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    624 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    625 			return (EINVAL);
    626 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    627 		error = copyin(p->image, image, icount);
    628 		if (error)
    629 			return error;
    630 		error = copyin(p->mask, mask, icount);
    631 		if (error)
    632 			return error;
    633 	}
    634 
    635 	s = spltty();
    636 	if (v & WSDISPLAY_CURSOR_DOCUR)
    637 		sc->sc_curenb = p->enable;
    638 	if (v & WSDISPLAY_CURSOR_DOPOS)
    639 		set_curpos(sc, &p->pos);
    640 	if (v & WSDISPLAY_CURSOR_DOHOT)
    641 		cc->cc_hot = p->hot;
    642 	if (v & WSDISPLAY_CURSOR_DOCMAP)
    643 		memcpy(&cc->cc_color[index], &color[index], count);
    644 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    645 		cc->cc_size = p->size;
    646 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    647 		memcpy(cc->cc_image, image, icount);
    648 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    649 		memcpy(cc->cc_mask, mask, icount);
    650 	}
    651 	sc->sc_changed |= v;
    652 	splx(s);
    653 
    654 	return (0);
    655 #undef cc
    656 }
    657 
    658 static int
    659 get_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
    660 {
    661 	return (EPASSTHROUGH); /* XXX */
    662 }
    663 
    664 static void
    665 set_curpos(struct mfb_softc *sc, struct wsdisplay_curpos *curpos)
    666 {
    667 	struct rasops_info *ri = sc->sc_ri;
    668 	int x = curpos->x, y = curpos->y;
    669 
    670 	if (y < 0)
    671 		y = 0;
    672 	else if (y > ri->ri_height)
    673 		y = ri->ri_height;
    674 	if (x < 0)
    675 		x = 0;
    676 	else if (x > ri->ri_width)
    677 		x = ri->ri_width;
    678 	sc->sc_cursor.cc_pos.x = x;
    679 	sc->sc_cursor.cc_pos.y = y;
    680 }
    681