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