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