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