xref: /netbsd-src/sys/dev/tc/mfb.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /* $NetBSD: mfb.c,v 1.44 2005/12/11 12:24:00 christos Exp $ */
2 
3 /*
4  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tohru Nishimura
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.44 2005/12/11 12:24:00 christos Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52 
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt431reg.h>
55 
56 #include <uvm/uvm_extern.h>
57 
58 #if defined(pmax)
59 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
60 #endif
61 
62 #if defined(alpha)
63 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
64 #endif
65 
66 /* Bt455 hardware registers, memory-mapped in 32bit stride */
67 #define	bt_reg	0x0
68 #define	bt_cmap	0x4
69 #define	bt_clr	0x8
70 #define	bt_ovly	0xc
71 
72 /* Bt431 hardware registers, memory-mapped in 32bit stride */
73 #define	bt_lo	0x0
74 #define	bt_hi	0x4
75 #define	bt_ram	0x8
76 #define	bt_ctl	0xc
77 
78 #define	REGWRITE32(p,i,v) do {					\
79 	*(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb();	\
80     } while (0)
81 
82 #define	SELECT455(p,r) do {					\
83 	REGWRITE32((p), bt_reg, (r));				\
84 	REGWRITE32((p), bt_clr, 0);				\
85    } while (0)
86 
87 #define	TWIN(x)    ((x)|((x) << 8))
88 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
89 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
90 
91 #define	SELECT431(p,r) do {					\
92 	REGWRITE32((p), bt_lo, TWIN(r));			\
93 	REGWRITE32((p), bt_hi, 0);				\
94    } while (0)
95 
96 struct hwcursor64 {
97 	struct wsdisplay_curpos cc_pos;
98 	struct wsdisplay_curpos cc_hot;
99 	struct wsdisplay_curpos cc_size;
100 	struct wsdisplay_curpos cc_magic;
101 #define	CURSOR_MAX_SIZE	64
102 	u_int8_t cc_color[6];
103 	u_int64_t cc_image[CURSOR_MAX_SIZE];
104 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
105 };
106 
107 struct mfb_softc {
108 	struct device sc_dev;
109 	vaddr_t sc_vaddr;
110 	size_t sc_size;
111 	struct rasops_info *sc_ri;
112 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
113 	int sc_blanked;
114 	int sc_curenb;			/* cursor sprite enabled */
115 	int sc_changed;			/* need update of hardware */
116 	int nscreens;
117 };
118 
119 #define	MX_MAGIC_X	360
120 #define	MX_MAGIC_Y	36
121 
122 #define	MX_FB_OFFSET	0x200000
123 #define	MX_FB_SIZE	0x200000
124 #define	MX_BT455_OFFSET	0x100000
125 #define	MX_BT431_OFFSET	0x180000
126 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
127 
128 static int  mfbmatch(struct device *, struct cfdata *, void *);
129 static void mfbattach(struct device *, struct device *, void *);
130 
131 CFATTACH_DECL(mfb, sizeof(struct mfb_softc),
132     mfbmatch, mfbattach, NULL, NULL);
133 
134 static void mfb_common_init(struct rasops_info *);
135 static struct rasops_info mfb_console_ri;
136 static tc_addr_t mfb_consaddr;
137 
138 static struct wsscreen_descr mfb_stdscreen = {
139 	"std", 0, 0,
140 	0, /* textops */
141 	0, 0,
142 	WSSCREEN_REVERSE
143 };
144 
145 static const struct wsscreen_descr *_mfb_scrlist[] = {
146 	&mfb_stdscreen,
147 };
148 
149 static const struct wsscreen_list mfb_screenlist = {
150 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
151 };
152 
153 static int	mfbioctl(void *, u_long, caddr_t, int, struct lwp *);
154 static paddr_t	mfbmmap(void *, off_t, int);
155 
156 static int	mfb_alloc_screen(void *, const struct wsscreen_descr *,
157 				      void **, int *, int *, long *);
158 static void	mfb_free_screen(void *, void *);
159 static int	mfb_show_screen(void *, void *, int,
160 				     void (*) (void *, int, int), void *);
161 
162 static const struct wsdisplay_accessops mfb_accessops = {
163 	mfbioctl,
164 	mfbmmap,
165 	mfb_alloc_screen,
166 	mfb_free_screen,
167 	mfb_show_screen,
168 	0 /* load_font */
169 };
170 
171 int  mfb_cnattach(tc_addr_t);
172 static int  mfbintr(void *);
173 static void mfbhwinit(caddr_t);
174 
175 static int  set_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
176 static int  get_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
177 static void set_curpos(struct mfb_softc *, struct wsdisplay_curpos *);
178 
179 /* bit order reverse */
180 static const u_int8_t flip[256] = {
181 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
182 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
183 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
184 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
185 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
186 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
187 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
188 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
189 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
190 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
191 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
192 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
193 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
194 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
195 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
196 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
197 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
198 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
199 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
200 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
201 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
202 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
203 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
204 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
205 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
206 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
207 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
208 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
209 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
210 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
211 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
212 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
213 };
214 
215 static int
216 mfbmatch(parent, match, aux)
217 	struct device *parent;
218 	struct cfdata *match;
219 	void *aux;
220 {
221 	struct tc_attach_args *ta = aux;
222 
223 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
224 		return (0);
225 
226 	return (1);
227 }
228 
229 static void
230 mfbattach(parent, self, aux)
231 	struct device *parent, *self;
232 	void *aux;
233 {
234 	struct mfb_softc *sc = (struct mfb_softc *)self;
235 	struct tc_attach_args *ta = aux;
236 	struct rasops_info *ri;
237 	struct wsemuldisplaydev_attach_args waa;
238 	int console;
239 	volatile register int junk;
240 
241 	console = (ta->ta_addr == mfb_consaddr);
242 	if (console) {
243 		sc->sc_ri = ri = &mfb_console_ri;
244 		sc->nscreens = 1;
245 	}
246 	else {
247 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
248 			M_DEVBUF, M_NOWAIT);
249 		if (ri == NULL) {
250 			printf(": can't alloc memory\n");
251 			return;
252 		}
253 		memset(ri, 0, sizeof(struct rasops_info));
254 
255 		ri->ri_hw = (void *)ta->ta_addr;
256 		mfb_common_init(ri);
257 		sc->sc_ri = ri;
258 	}
259 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
260 
261 	sc->sc_vaddr = ta->ta_addr;
262 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
263 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
264 	sc->sc_blanked = sc->sc_curenb = 0;
265 
266 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
267 
268 	/* clear any pending interrupts */
269 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 0;
270 	junk = *(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET);
271 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 1;
272 
273 	waa.console = console;
274 	waa.scrdata = &mfb_screenlist;
275 	waa.accessops = &mfb_accessops;
276 	waa.accesscookie = sc;
277 
278 	config_found(self, &waa, wsemuldisplaydevprint);
279 }
280 
281 static void
282 mfb_common_init(ri)
283 	struct rasops_info *ri;
284 {
285 	caddr_t base;
286 	int cookie;
287 
288 	base = (caddr_t)ri->ri_hw;
289 
290 	/* initialize colormap and cursor hardware */
291 	mfbhwinit(base);
292 
293 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
294 	ri->ri_depth = 8;	/* !! watch out !! */
295 	ri->ri_width = 1280;
296 	ri->ri_height = 1024;
297 	ri->ri_stride = 2048;
298 	ri->ri_bits = base + MX_FB_OFFSET;
299 
300 	/* clear the screen */
301 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
302 
303 	wsfont_init();
304 	/* prefer 12 pixel wide font */
305 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
306 	    WSDISPLAY_FONTORDER_L2R);
307 	if (cookie <= 0)
308 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
309 		    WSDISPLAY_FONTORDER_L2R);
310 	if (cookie <= 0) {
311 		printf("mfb: font table is empty\n");
312 		return;
313 	}
314 
315 	if (wsfont_lock(cookie, &ri->ri_font)) {
316 		printf("mfb: couldn't lock font\n");
317 		return;
318 	}
319 	ri->ri_wsfcookie = cookie;
320 
321 	rasops_init(ri, 34, 80);
322 
323 	/* XXX shouldn't be global */
324 	mfb_stdscreen.nrows = ri->ri_rows;
325 	mfb_stdscreen.ncols = ri->ri_cols;
326 	mfb_stdscreen.textops = &ri->ri_ops;
327 	mfb_stdscreen.capabilities = ri->ri_caps;
328 }
329 
330 static int
331 mfbioctl(v, cmd, data, flag, l)
332 	void *v;
333 	u_long cmd;
334 	caddr_t data;
335 	int flag;
336 	struct lwp *l;
337 {
338 	struct mfb_softc *sc = v;
339 	struct rasops_info *ri = sc->sc_ri;
340 	int turnoff, s;
341 
342 	switch (cmd) {
343 	case WSDISPLAYIO_GTYPE:
344 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
345 		return (0);
346 
347 	case WSDISPLAYIO_GINFO:
348 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
349 		wsd_fbip->height = ri->ri_height;
350 		wsd_fbip->width = ri->ri_width;
351 		wsd_fbip->depth = ri->ri_depth;
352 		wsd_fbip->cmsize = 0;
353 #undef fbt
354 		return (0);
355 
356 	case WSDISPLAYIO_GETCMAP:
357 	case WSDISPLAYIO_PUTCMAP:
358 		return (EPASSTHROUGH);
359 
360 	case WSDISPLAYIO_SVIDEO:
361 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
362 		if (sc->sc_blanked != turnoff) {
363 			sc->sc_blanked = turnoff;
364 #if 0	/* XXX later XXX */
365 	To turn off,
366 	- assign Bt455 cmap[1].green with value 0 (black),
367 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
368 #endif	/* XXX XXX XXX */
369 		}
370 		return (0);
371 
372 	case WSDISPLAYIO_GVIDEO:
373 		*(u_int *)data = sc->sc_blanked ?
374 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
375 		return (0);
376 
377 	case WSDISPLAYIO_GCURPOS:
378 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
379 		return (0);
380 
381 	case WSDISPLAYIO_SCURPOS:
382 		s = spltty();
383 		set_curpos(sc, (struct wsdisplay_curpos *)data);
384 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
385 		splx(s);
386 		return (0);
387 
388 	case WSDISPLAYIO_GCURMAX:
389 		((struct wsdisplay_curpos *)data)->x =
390 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
391 		return (0);
392 
393 	case WSDISPLAYIO_GCURSOR:
394 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
395 
396 	case WSDISPLAYIO_SCURSOR:
397 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
398 
399 	case WSDISPLAYIO_SMODE:
400 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
401 			s = spltty();
402 			sc->sc_curenb = 0;
403 			sc->sc_blanked = 0;
404 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
405 			splx(s);
406 		}
407 		return (0);
408 	}
409 	return (EPASSTHROUGH);
410 }
411 
412 static paddr_t
413 mfbmmap(v, offset, prot)
414 	void *v;
415 	off_t offset;
416 	int prot;
417 {
418 	struct mfb_softc *sc = v;
419 
420 	if (offset >= MX_FB_SIZE || offset < 0)
421 		return (-1);
422 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
423 }
424 
425 static int
426 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
427 	void *v;
428 	const struct wsscreen_descr *type;
429 	void **cookiep;
430 	int *curxp, *curyp;
431 	long *attrp;
432 {
433 	struct mfb_softc *sc = v;
434 	struct rasops_info *ri = sc->sc_ri;
435 	long defattr;
436 
437 	if (sc->nscreens > 0)
438 		return (ENOMEM);
439 
440 	*cookiep = ri;		 /* one and only for now */
441 	*curxp = 0;
442 	*curyp = 0;
443 	(*ri->ri_ops.allocattr)(ri, 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_ri == &mfb_console_ri)
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)(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 rasops_info *ri;
479 	long defattr;
480 
481 	ri = &mfb_console_ri;
482 	ri->ri_hw = (void *)addr;
483 	mfb_common_init(ri);
484 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
485 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
486 	mfb_consaddr = addr;
487 	return (0);
488 }
489 
490 static int
491 mfbintr(arg)
492 	void *arg;
493 {
494 	struct mfb_softc *sc = arg;
495 	caddr_t base, vdac, curs;
496 	int v;
497 	volatile register int junk;
498 
499 	base = (caddr_t)sc->sc_ri->ri_hw;
500 	junk = *(u_int8_t *)(base + MX_IREQ_OFFSET);
501 #if 0
502 	*(u_int8_t *)(base + MX_IREQ_OFFSET) = 0;
503 #endif
504 	if (sc->sc_changed == 0)
505 		return (1);
506 
507 	vdac = base + MX_BT455_OFFSET;
508 	curs = base + MX_BT431_OFFSET;
509 	v = sc->sc_changed;
510 	if (v & WSDISPLAY_CURSOR_DOCUR) {
511 		int  onoff;
512 
513 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
514 		SELECT431(curs, BT431_REG_COMMAND);
515 		REGWRITE32(curs, bt_ctl, onoff);
516 	}
517 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
518 		int x, y;
519 		u_int32_t twin;
520 
521 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
522 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
523 
524 		x += sc->sc_cursor.cc_magic.x;
525 		y += sc->sc_cursor.cc_magic.y;
526 
527 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
528 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
529 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
530 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
531 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
532 	}
533 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
534 		u_int8_t *cp = sc->sc_cursor.cc_color;
535 
536 		SELECT455(vdac, 8);
537 		REGWRITE32(vdac, bt_cmap, 0);
538 		REGWRITE32(vdac, bt_cmap, cp[1]);
539 		REGWRITE32(vdac, bt_cmap, 0);
540 
541 		REGWRITE32(vdac, bt_cmap, 0);
542 		REGWRITE32(vdac, bt_cmap, cp[1]);
543 		REGWRITE32(vdac, bt_cmap, 0);
544 
545 		REGWRITE32(vdac, bt_ovly, 0);
546 		REGWRITE32(vdac, bt_ovly, cp[0]);
547 		REGWRITE32(vdac, bt_ovly, 0);
548 	}
549 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
550 		u_int8_t *ip, *mp, img, msk;
551 		int bcnt;
552 
553 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
554 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
555 		bcnt = 0;
556 		SELECT431(curs, BT431_REG_CRAM_BASE);
557 
558 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
559 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
560 			/* pad right half 32 pixel when smaller than 33 */
561 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
562 				REGWRITE32(curs, bt_ram, 0);
563 			}
564 			else {
565 				int half;
566 
567 				img = *ip++;
568 				msk = *mp++;
569 				img &= msk;	/* cookie off image */
570 				half = (flip[msk] << 8) | flip[img];
571 				REGWRITE32(curs, bt_ram, half);
572 			}
573 			bcnt += 2;
574 		}
575 		/* pad unoccupied scan lines */
576 		while (bcnt < CURSOR_MAX_SIZE * 16) {
577 			REGWRITE32(curs, bt_ram, 0);
578 			bcnt += 2;
579 		}
580 	}
581 	sc->sc_changed = 0;
582 	return (1);
583 }
584 
585 static void
586 mfbhwinit(mfbbase)
587 	caddr_t mfbbase;
588 {
589 	caddr_t vdac, curs;
590 	int i;
591 
592 	vdac = mfbbase + MX_BT455_OFFSET;
593 	curs = mfbbase + MX_BT431_OFFSET;
594 	SELECT431(curs, BT431_REG_COMMAND);
595 	REGWRITE32(curs, bt_ctl, 0x0404);
596 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
597 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
598 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
599 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
600 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
601 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
602 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
603 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
604 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
605 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
606 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
607 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
608 
609 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
610 	SELECT455(vdac, 0);
611 	REGWRITE32(vdac, bt_cmap, 0);
612 	REGWRITE32(vdac, bt_cmap, 0);
613 	REGWRITE32(vdac, bt_cmap, 0);
614 	REGWRITE32(vdac, bt_cmap, 0);
615 	REGWRITE32(vdac, bt_cmap, 0xff);
616 	REGWRITE32(vdac, bt_cmap, 0);
617 	for (i = 2; i < 16; i++) {
618 		REGWRITE32(vdac, bt_cmap, 0);
619 		REGWRITE32(vdac, bt_cmap, 0);
620 		REGWRITE32(vdac, bt_cmap, 0);
621 	}
622 	REGWRITE32(vdac, bt_ovly, 0);
623 	REGWRITE32(vdac, bt_ovly, 0xff);
624 	REGWRITE32(vdac, bt_ovly, 0);
625 
626 	SELECT431(curs, BT431_REG_CRAM_BASE);
627 	for (i = 0; i < 512; i++) {
628 		REGWRITE32(curs, bt_ram, 0);
629 	}
630 }
631 
632 static int
633 set_cursor(sc, p)
634 	struct mfb_softc *sc;
635 	struct wsdisplay_cursor *p;
636 {
637 #define	cc (&sc->sc_cursor)
638 	u_int v, count = 0, icount = 0, index = 0;
639 	uint64_t image[CURSOR_MAX_SIZE];
640 	uint64_t mask[CURSOR_MAX_SIZE];
641 	uint8_t color[6];
642 	int error, s;
643 
644 	v = p->which;
645 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
646 		index = p->cmap.index;
647 		count = p->cmap.count;
648 		if (index >= 2 || (index + count) > 2)
649 			return (EINVAL);
650 		error = copyin(p->cmap.red, &color[index], count);
651 		if (error)
652 			return error;
653 	}
654 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
655 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
656 			return (EINVAL);
657 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
658 		error = copyin(p->image, image, icount);
659 		if (error)
660 			return error;
661 		error = copyin(p->mask, mask, icount);
662 		if (error)
663 			return error;
664 	}
665 
666 	s = spltty();
667 	if (v & WSDISPLAY_CURSOR_DOCUR)
668 		sc->sc_curenb = p->enable;
669 	if (v & WSDISPLAY_CURSOR_DOPOS)
670 		set_curpos(sc, &p->pos);
671 	if (v & WSDISPLAY_CURSOR_DOHOT)
672 		cc->cc_hot = p->hot;
673 	if (v & WSDISPLAY_CURSOR_DOCMAP)
674 		memcpy(&cc->cc_color[index], &color[index], count);
675 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
676 		cc->cc_size = p->size;
677 		memset(cc->cc_image, 0, sizeof cc->cc_image);
678 		memcpy(cc->cc_image, image, icount);
679 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
680 		memcpy(cc->cc_mask, mask, icount);
681 	}
682 	sc->sc_changed |= v;
683 	splx(s);
684 
685 	return (0);
686 #undef cc
687 }
688 
689 static int
690 get_cursor(sc, p)
691 	struct mfb_softc *sc;
692 	struct wsdisplay_cursor *p;
693 {
694 	return (EPASSTHROUGH); /* XXX */
695 }
696 
697 static void
698 set_curpos(sc, curpos)
699 	struct mfb_softc *sc;
700 	struct wsdisplay_curpos *curpos;
701 {
702 	struct rasops_info *ri = sc->sc_ri;
703 	int x = curpos->x, y = curpos->y;
704 
705 	if (y < 0)
706 		y = 0;
707 	else if (y > ri->ri_height)
708 		y = ri->ri_height;
709 	if (x < 0)
710 		x = 0;
711 	else if (x > ri->ri_width)
712 		x = ri->ri_width;
713 	sc->sc_cursor.cc_pos.x = x;
714 	sc->sc_cursor.cc_pos.y = y;
715 }
716