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