xref: /netbsd-src/sys/dev/tc/mfb.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* $NetBSD: mfb.c,v 1.56 2010/05/15 08:53:27 tsutsui 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.56 2010/05/15 08:53:27 tsutsui 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 uint32_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 	uint8_t cc_color[6];
102 	uint64_t cc_image[CURSOR_MAX_SIZE];
103 	uint64_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 uint8_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 		ri->ri_flg &= ~RI_NO_AUTO;
238 		sc->nscreens = 1;
239 	}
240 	else {
241 		ri = malloc(sizeof(struct rasops_info),
242 			M_DEVBUF, M_NOWAIT);
243 		if (ri == NULL) {
244 			printf(": can't alloc memory\n");
245 			return;
246 		}
247 		memset(ri, 0, sizeof(struct rasops_info));
248 
249 		ri->ri_hw = (void *)ta->ta_addr;
250 		mfb_common_init(ri);
251 		sc->sc_ri = ri;
252 	}
253 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
254 
255 	sc->sc_vaddr = ta->ta_addr;
256 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
257 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
258 	sc->sc_blanked = sc->sc_curenb = 0;
259 
260 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
261 
262 	/* clear any pending interrupts */
263 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
264 	junk = *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
265 	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
266 
267 	waa.console = console;
268 	waa.scrdata = &mfb_screenlist;
269 	waa.accessops = &mfb_accessops;
270 	waa.accesscookie = sc;
271 
272 	config_found(self, &waa, wsemuldisplaydevprint);
273 }
274 
275 static void
276 mfb_common_init(struct rasops_info *ri)
277 {
278 	char *base;
279 	int cookie;
280 
281 	base = (void *)ri->ri_hw;
282 
283 	/* initialize colormap and cursor hardware */
284 	mfbhwinit(base);
285 
286 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
287 	if (ri == &mfb_console_ri)
288 		ri->ri_flg |= RI_NO_AUTO;
289 	ri->ri_depth = 8;	/* !! watch out !! */
290 	ri->ri_width = 1280;
291 	ri->ri_height = 1024;
292 	ri->ri_stride = 2048;
293 	ri->ri_bits = base + MX_FB_OFFSET;
294 
295 	/* clear the screen */
296 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
297 
298 	wsfont_init();
299 	/* prefer 12 pixel wide font */
300 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
301 	    WSDISPLAY_FONTORDER_L2R);
302 	if (cookie <= 0)
303 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
304 		    WSDISPLAY_FONTORDER_L2R);
305 	if (cookie <= 0) {
306 		printf("mfb: font table is empty\n");
307 		return;
308 	}
309 
310 	if (wsfont_lock(cookie, &ri->ri_font)) {
311 		printf("mfb: couldn't lock font\n");
312 		return;
313 	}
314 	ri->ri_wsfcookie = cookie;
315 
316 	rasops_init(ri, 34, 80);
317 
318 	/* XXX shouldn't be global */
319 	mfb_stdscreen.nrows = ri->ri_rows;
320 	mfb_stdscreen.ncols = ri->ri_cols;
321 	mfb_stdscreen.textops = &ri->ri_ops;
322 	mfb_stdscreen.capabilities = ri->ri_caps;
323 }
324 
325 static int
326 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
327 {
328 	struct mfb_softc *sc = v;
329 	struct rasops_info *ri = sc->sc_ri;
330 	int turnoff, s;
331 
332 	switch (cmd) {
333 	case WSDISPLAYIO_GTYPE:
334 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
335 		return (0);
336 
337 	case WSDISPLAYIO_GINFO:
338 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
339 		wsd_fbip->height = ri->ri_height;
340 		wsd_fbip->width = ri->ri_width;
341 		wsd_fbip->depth = ri->ri_depth;
342 		wsd_fbip->cmsize = 0;
343 #undef fbt
344 		return (0);
345 
346 	case WSDISPLAYIO_GETCMAP:
347 	case WSDISPLAYIO_PUTCMAP:
348 		return (EPASSTHROUGH);
349 
350 	case WSDISPLAYIO_SVIDEO:
351 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
352 		if (sc->sc_blanked != turnoff) {
353 			sc->sc_blanked = turnoff;
354 #if 0	/* XXX later XXX */
355 	To turn off,
356 	- assign Bt455 cmap[1].green with value 0 (black),
357 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
358 #endif	/* XXX XXX XXX */
359 		}
360 		return (0);
361 
362 	case WSDISPLAYIO_GVIDEO:
363 		*(u_int *)data = sc->sc_blanked ?
364 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
365 		return (0);
366 
367 	case WSDISPLAYIO_GCURPOS:
368 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
369 		return (0);
370 
371 	case WSDISPLAYIO_SCURPOS:
372 		s = spltty();
373 		set_curpos(sc, (struct wsdisplay_curpos *)data);
374 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
375 		splx(s);
376 		return (0);
377 
378 	case WSDISPLAYIO_GCURMAX:
379 		((struct wsdisplay_curpos *)data)->x =
380 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
381 		return (0);
382 
383 	case WSDISPLAYIO_GCURSOR:
384 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
385 
386 	case WSDISPLAYIO_SCURSOR:
387 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
388 
389 	case WSDISPLAYIO_SMODE:
390 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
391 			s = spltty();
392 			sc->sc_curenb = 0;
393 			sc->sc_blanked = 0;
394 			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
395 			splx(s);
396 		}
397 		return (0);
398 	}
399 	return (EPASSTHROUGH);
400 }
401 
402 static paddr_t
403 mfbmmap(void *v, void *vs, off_t offset, int prot)
404 {
405 	struct mfb_softc *sc = v;
406 
407 	if (offset >= MX_FB_SIZE || offset < 0)
408 		return (-1);
409 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
410 }
411 
412 static int
413 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
414     int *curxp, int *curyp, long *attrp)
415 {
416 	struct mfb_softc *sc = v;
417 	struct rasops_info *ri = sc->sc_ri;
418 	long defattr;
419 
420 	if (sc->nscreens > 0)
421 		return (ENOMEM);
422 
423 	*cookiep = ri;		 /* one and only for now */
424 	*curxp = 0;
425 	*curyp = 0;
426 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
427 	*attrp = defattr;
428 	sc->nscreens++;
429 	return (0);
430 }
431 
432 static void
433 mfb_free_screen(void *v, void *cookie)
434 {
435 	struct mfb_softc *sc = v;
436 
437 	if (sc->sc_ri == &mfb_console_ri)
438 		panic("mfb_free_screen: console");
439 
440 	sc->nscreens--;
441 }
442 
443 static int
444 mfb_show_screen(void *v, void *cookie, int waitok,
445     void (*cb)(void *, int, int), void *cbarg)
446 {
447 
448 	return (0);
449 }
450 
451 /* EXPORT */ int
452 mfb_cnattach(tc_addr_t addr)
453 {
454 	struct rasops_info *ri;
455 	long defattr;
456 
457 	ri = &mfb_console_ri;
458 	ri->ri_hw = (void *)addr;
459 	mfb_common_init(ri);
460 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
461 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
462 	mfb_consaddr = addr;
463 	return (0);
464 }
465 
466 static int
467 mfbintr(void *arg)
468 {
469 	struct mfb_softc *sc = arg;
470 	char *base, *vdac, *curs;
471 	int v;
472 	volatile register int junk;
473 
474 	base = (void *)sc->sc_ri->ri_hw;
475 	junk = *(uint8_t *)(base + MX_IREQ_OFFSET);
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 || (index + count) > 2)
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