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