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