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