xref: /netbsd-src/sys/dev/tc/mfb.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /* $NetBSD: mfb.c,v 1.60 2018/01/24 05:35:58 riastradh 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.60 2018/01/24 05:35:58 riastradh 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_NOWAIT);
241 		if (ri == NULL) {
242 			printf(": can't alloc memory\n");
243 			return;
244 		}
245 		memset(ri, 0, sizeof(struct rasops_info));
246 
247 		ri->ri_hw = (void *)ta->ta_addr;
248 		mfb_common_init(ri);
249 		sc->sc_ri = ri;
250 	}
251 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
252 
253 	sc->sc_vaddr = ta->ta_addr;
254 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
255 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
256 	sc->sc_blanked = sc->sc_curenb = 0;
257 
258 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
259 
260 	/* clear any pending interrupts */
261 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
262 	junk = *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
263 	__USE(junk);
264 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
265 
266 	waa.console = console;
267 	waa.scrdata = &mfb_screenlist;
268 	waa.accessops = &mfb_accessops;
269 	waa.accesscookie = sc;
270 
271 	config_found(self, &waa, wsemuldisplaydevprint);
272 }
273 
274 static void
275 mfb_common_init(struct rasops_info *ri)
276 {
277 	char *base;
278 	int cookie;
279 
280 	base = (void *)ri->ri_hw;
281 
282 	/* initialize colormap and cursor hardware */
283 	mfbhwinit(base);
284 
285 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
286 	if (ri == &mfb_console_ri)
287 		ri->ri_flg |= RI_NO_AUTO;
288 	ri->ri_depth = 8;	/* !! watch out !! */
289 	ri->ri_width = 1280;
290 	ri->ri_height = 1024;
291 	ri->ri_stride = 2048;
292 	ri->ri_bits = base + MX_FB_OFFSET;
293 
294 	/* clear the screen */
295 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
296 
297 	wsfont_init();
298 	/* prefer 12 pixel wide font */
299 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
300 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
301 	if (cookie <= 0)
302 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
303 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
304 	if (cookie <= 0) {
305 		printf("mfb: font table is empty\n");
306 		return;
307 	}
308 
309 	if (wsfont_lock(cookie, &ri->ri_font)) {
310 		printf("mfb: couldn't lock font\n");
311 		return;
312 	}
313 	ri->ri_wsfcookie = cookie;
314 
315 	rasops_init(ri, 34, 80);
316 
317 	/* XXX shouldn't be global */
318 	mfb_stdscreen.nrows = ri->ri_rows;
319 	mfb_stdscreen.ncols = ri->ri_cols;
320 	mfb_stdscreen.textops = &ri->ri_ops;
321 	mfb_stdscreen.capabilities = ri->ri_caps;
322 }
323 
324 static int
325 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
326 {
327 	struct mfb_softc *sc = v;
328 	struct rasops_info *ri = sc->sc_ri;
329 	int turnoff, s;
330 
331 	switch (cmd) {
332 	case WSDISPLAYIO_GTYPE:
333 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
334 		return (0);
335 
336 	case WSDISPLAYIO_GINFO:
337 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
338 		wsd_fbip->height = ri->ri_height;
339 		wsd_fbip->width = ri->ri_width;
340 		wsd_fbip->depth = ri->ri_depth;
341 		wsd_fbip->cmsize = 0;
342 #undef fbt
343 		return (0);
344 
345 	case WSDISPLAYIO_GETCMAP:
346 	case WSDISPLAYIO_PUTCMAP:
347 		return (EPASSTHROUGH);
348 
349 	case WSDISPLAYIO_SVIDEO:
350 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
351 		if (sc->sc_blanked != turnoff) {
352 			sc->sc_blanked = turnoff;
353 #if 0	/* XXX later XXX */
354 	To turn off,
355 	- assign Bt455 cmap[1].green with value 0 (black),
356 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
357 #endif	/* XXX XXX XXX */
358 		}
359 		return (0);
360 
361 	case WSDISPLAYIO_GVIDEO:
362 		*(u_int *)data = sc->sc_blanked ?
363 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
364 		return (0);
365 
366 	case WSDISPLAYIO_GCURPOS:
367 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
368 		return (0);
369 
370 	case WSDISPLAYIO_SCURPOS:
371 		s = spltty();
372 		set_curpos(sc, (struct wsdisplay_curpos *)data);
373 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
374 		splx(s);
375 		return (0);
376 
377 	case WSDISPLAYIO_GCURMAX:
378 		((struct wsdisplay_curpos *)data)->x =
379 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
380 		return (0);
381 
382 	case WSDISPLAYIO_GCURSOR:
383 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
384 
385 	case WSDISPLAYIO_SCURSOR:
386 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
387 
388 	case WSDISPLAYIO_SMODE:
389 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
390 			s = spltty();
391 			sc->sc_curenb = 0;
392 			sc->sc_blanked = 0;
393 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
394 			splx(s);
395 		}
396 		return (0);
397 	}
398 	return (EPASSTHROUGH);
399 }
400 
401 static paddr_t
402 mfbmmap(void *v, void *vs, off_t offset, int prot)
403 {
404 	struct mfb_softc *sc = v;
405 
406 	if (offset >= MX_FB_SIZE || offset < 0)
407 		return (-1);
408 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
409 }
410 
411 static int
412 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
413     int *curxp, int *curyp, long *attrp)
414 {
415 	struct mfb_softc *sc = v;
416 	struct rasops_info *ri = sc->sc_ri;
417 	long defattr;
418 
419 	if (sc->nscreens > 0)
420 		return (ENOMEM);
421 
422 	*cookiep = ri;		 /* one and only for now */
423 	*curxp = 0;
424 	*curyp = 0;
425 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
426 	*attrp = defattr;
427 	sc->nscreens++;
428 	return (0);
429 }
430 
431 static void
432 mfb_free_screen(void *v, void *cookie)
433 {
434 	struct mfb_softc *sc = v;
435 
436 	if (sc->sc_ri == &mfb_console_ri)
437 		panic("mfb_free_screen: console");
438 
439 	sc->nscreens--;
440 }
441 
442 static int
443 mfb_show_screen(void *v, void *cookie, int waitok,
444     void (*cb)(void *, int, int), void *cbarg)
445 {
446 
447 	return (0);
448 }
449 
450 /* EXPORT */ int
451 mfb_cnattach(tc_addr_t addr)
452 {
453 	struct rasops_info *ri;
454 	long defattr;
455 
456 	ri = &mfb_console_ri;
457 	ri->ri_hw = (void *)addr;
458 	mfb_common_init(ri);
459 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
460 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
461 	mfb_consaddr = addr;
462 	return (0);
463 }
464 
465 static int
466 mfbintr(void *arg)
467 {
468 	struct mfb_softc *sc = arg;
469 	char *base, *vdac, *curs;
470 	int v;
471 	volatile register int junk;
472 
473 	base = (void *)sc->sc_ri->ri_hw;
474 	junk = *(uint8_t *)(base + MX_IREQ_OFFSET);
475 	__USE(junk);
476 #if 0
477 	*(uint8_t *)(base + MX_IREQ_OFFSET) = 0;
478 #endif
479 	if (sc->sc_changed == 0)
480 		return (1);
481 
482 	vdac = base + MX_BT455_OFFSET;
483 	curs = base + MX_BT431_OFFSET;
484 	v = sc->sc_changed;
485 	if (v & WSDISPLAY_CURSOR_DOCUR) {
486 		int  onoff;
487 
488 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
489 		SELECT431(curs, BT431_REG_COMMAND);
490 		REGWRITE32(curs, bt_ctl, onoff);
491 	}
492 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
493 		int x, y;
494 		uint32_t twin;
495 
496 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
497 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
498 
499 		x += sc->sc_cursor.cc_magic.x;
500 		y += sc->sc_cursor.cc_magic.y;
501 
502 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
503 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
504 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
505 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
506 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
507 	}
508 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
509 		uint8_t *cp = sc->sc_cursor.cc_color;
510 
511 		SELECT455(vdac, 8);
512 		REGWRITE32(vdac, bt_cmap, 0);
513 		REGWRITE32(vdac, bt_cmap, cp[1]);
514 		REGWRITE32(vdac, bt_cmap, 0);
515 
516 		REGWRITE32(vdac, bt_cmap, 0);
517 		REGWRITE32(vdac, bt_cmap, cp[1]);
518 		REGWRITE32(vdac, bt_cmap, 0);
519 
520 		REGWRITE32(vdac, bt_ovly, 0);
521 		REGWRITE32(vdac, bt_ovly, cp[0]);
522 		REGWRITE32(vdac, bt_ovly, 0);
523 	}
524 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
525 		uint8_t *ip, *mp, img, msk;
526 		int bcnt;
527 
528 		ip = (uint8_t *)sc->sc_cursor.cc_image;
529 		mp = (uint8_t *)sc->sc_cursor.cc_mask;
530 		bcnt = 0;
531 		SELECT431(curs, BT431_REG_CRAM_BASE);
532 
533 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
534 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
535 			/* pad right half 32 pixel when smaller than 33 */
536 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
537 				REGWRITE32(curs, bt_ram, 0);
538 			}
539 			else {
540 				int half;
541 
542 				img = *ip++;
543 				msk = *mp++;
544 				img &= msk;	/* cookie off image */
545 				half = (flip[msk] << 8) | flip[img];
546 				REGWRITE32(curs, bt_ram, half);
547 			}
548 			bcnt += 2;
549 		}
550 		/* pad unoccupied scan lines */
551 		while (bcnt < CURSOR_MAX_SIZE * 16) {
552 			REGWRITE32(curs, bt_ram, 0);
553 			bcnt += 2;
554 		}
555 	}
556 	sc->sc_changed = 0;
557 	return (1);
558 }
559 
560 static void
561 mfbhwinit(void *mfbbase)
562 {
563 	char *vdac, *curs;
564 	int i;
565 
566 	vdac = (char *)mfbbase + MX_BT455_OFFSET;
567 	curs = (char *)mfbbase + MX_BT431_OFFSET;
568 	SELECT431(curs, BT431_REG_COMMAND);
569 	REGWRITE32(curs, bt_ctl, 0x0404);
570 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
571 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
572 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
573 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
574 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
575 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
576 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
577 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
578 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
579 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
580 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
581 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
582 
583 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
584 	SELECT455(vdac, 0);
585 	REGWRITE32(vdac, bt_cmap, 0);
586 	REGWRITE32(vdac, bt_cmap, 0);
587 	REGWRITE32(vdac, bt_cmap, 0);
588 	REGWRITE32(vdac, bt_cmap, 0);
589 	REGWRITE32(vdac, bt_cmap, 0xff);
590 	REGWRITE32(vdac, bt_cmap, 0);
591 	for (i = 2; i < 16; i++) {
592 		REGWRITE32(vdac, bt_cmap, 0);
593 		REGWRITE32(vdac, bt_cmap, 0);
594 		REGWRITE32(vdac, bt_cmap, 0);
595 	}
596 	REGWRITE32(vdac, bt_ovly, 0);
597 	REGWRITE32(vdac, bt_ovly, 0xff);
598 	REGWRITE32(vdac, bt_ovly, 0);
599 
600 	SELECT431(curs, BT431_REG_CRAM_BASE);
601 	for (i = 0; i < 512; i++) {
602 		REGWRITE32(curs, bt_ram, 0);
603 	}
604 }
605 
606 static int
607 set_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
608 {
609 #define	cc (&sc->sc_cursor)
610 	u_int v, count = 0, icount = 0, index = 0;
611 	uint64_t image[CURSOR_MAX_SIZE];
612 	uint64_t mask[CURSOR_MAX_SIZE];
613 	uint8_t color[6];
614 	int error, s;
615 
616 	v = p->which;
617 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
618 		index = p->cmap.index;
619 		count = p->cmap.count;
620 		if (index >= 2 || count > 2 - index)
621 			return (EINVAL);
622 		error = copyin(p->cmap.red, &color[index], count);
623 		if (error)
624 			return error;
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 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
630 		error = copyin(p->image, image, icount);
631 		if (error)
632 			return error;
633 		error = copyin(p->mask, mask, icount);
634 		if (error)
635 			return error;
636 	}
637 
638 	s = spltty();
639 	if (v & WSDISPLAY_CURSOR_DOCUR)
640 		sc->sc_curenb = p->enable;
641 	if (v & WSDISPLAY_CURSOR_DOPOS)
642 		set_curpos(sc, &p->pos);
643 	if (v & WSDISPLAY_CURSOR_DOHOT)
644 		cc->cc_hot = p->hot;
645 	if (v & WSDISPLAY_CURSOR_DOCMAP)
646 		memcpy(&cc->cc_color[index], &color[index], count);
647 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
648 		cc->cc_size = p->size;
649 		memset(cc->cc_image, 0, sizeof cc->cc_image);
650 		memcpy(cc->cc_image, image, icount);
651 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
652 		memcpy(cc->cc_mask, mask, icount);
653 	}
654 	sc->sc_changed |= v;
655 	splx(s);
656 
657 	return (0);
658 #undef cc
659 }
660 
661 static int
662 get_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
663 {
664 	return (EPASSTHROUGH); /* XXX */
665 }
666 
667 static void
668 set_curpos(struct mfb_softc *sc, struct wsdisplay_curpos *curpos)
669 {
670 	struct rasops_info *ri = sc->sc_ri;
671 	int x = curpos->x, y = curpos->y;
672 
673 	if (y < 0)
674 		y = 0;
675 	else if (y > ri->ri_height)
676 		y = ri->ri_height;
677 	if (x < 0)
678 		x = 0;
679 	else if (x > ri->ri_width)
680 		x = ri->ri_width;
681 	sc->sc_cursor.cc_pos.x = x;
682 	sc->sc_cursor.cc_pos.y = y;
683 }
684