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