xref: /netbsd-src/sys/dev/tc/mfb.c (revision e4d7c2e329d54c97e0c0bd3016bbe74f550c3d5e)
1 /* $NetBSD: mfb.c,v 1.20 1999/12/06 19:26:00 drochner 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.20 1999/12/06 19:26:00 drochner 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/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.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 	struct raster	dc_raster;	/* raster description */
104 	struct rcons	dc_rcons;	/* raster blitter control info */
105 	int	    dc_blanked;		/* currently has video disabled */
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 const struct wsdisplay_emulops mfb_emulops = {
153 	rcons_cursor,			/* could use hardware cursor; punt */
154 	rcons_mapchar,
155 	rcons_putchar,
156 	rcons_copycols,
157 	rcons_erasecols,
158 	rcons_copyrows,
159 	rcons_eraserows,
160 	rcons_alloc_attr
161 };
162 
163 static struct wsscreen_descr mfb_stdscreen = {
164 	"std", 0, 0,
165 	&mfb_emulops,
166 	0, 0,
167 	WSSCREEN_REVERSE
168 };
169 
170 static const struct wsscreen_descr *_mfb_scrlist[] = {
171 	&mfb_stdscreen,
172 };
173 
174 static const struct wsscreen_list mfb_screenlist = {
175 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
176 };
177 
178 static int  mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
179 static int  mfbmmap __P((void *, off_t, int));
180 
181 static int  mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
182 				      void **, int *, int *, long *));
183 static void mfb_free_screen __P((void *, void *));
184 static int mfb_show_screen __P((void *, void *, int,
185 				void (*) (void *, int, int), void *));
186 
187 static const struct wsdisplay_accessops mfb_accessops = {
188 	mfbioctl,
189 	mfbmmap,
190 	mfb_alloc_screen,
191 	mfb_free_screen,
192 	mfb_show_screen,
193 	0 /* load_font */
194 };
195 
196 int  mfb_cnattach __P((tc_addr_t));
197 static int  mfbintr __P((void *));
198 static void mfbinit __P((struct fb_devconfig *));
199 
200 static int  set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
201 static int  get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
202 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
203 static void bt431_set_curpos __P((struct mfb_softc *));
204 
205 /* bit order reverse */
206 static const u_int8_t flip[256] = {
207 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
208 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
209 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
210 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
211 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
212 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
213 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
214 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
215 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
216 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
217 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
218 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
219 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
220 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
221 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
222 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
223 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
224 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
225 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
226 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
227 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
228 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
229 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
230 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
231 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
232 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
233 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
234 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
235 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
236 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
237 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
238 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
239 };
240 
241 static int
242 mfbmatch(parent, match, aux)
243 	struct device *parent;
244 	struct cfdata *match;
245 	void *aux;
246 {
247 	struct tc_attach_args *ta = aux;
248 
249 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
250 		return (0);
251 
252 	return (1);
253 }
254 
255 static void
256 mfb_getdevconfig(dense_addr, dc)
257 	tc_addr_t dense_addr;
258 	struct fb_devconfig *dc;
259 {
260 	struct raster *rap;
261 	struct rcons *rcp;
262 	int i;
263 
264 	dc->dc_vaddr = dense_addr;
265 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET);
266 
267 	dc->dc_wid = 1280;
268 	dc->dc_ht = 1024;
269 	dc->dc_depth = 8;
270 	dc->dc_rowbytes = 2048;
271 	dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET;
272 	dc->dc_blanked = 0;
273 
274 	/* initialize colormap and cursor resource */
275 	mfbinit(dc);
276 
277 	/* clear the screen */
278 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
279 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
280 
281 	/* initialize the raster */
282 	rap = &dc->dc_raster;
283 	rap->width = dc->dc_wid;
284 	rap->height = dc->dc_ht;
285 	rap->depth = dc->dc_depth;
286 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
287 	rap->pixels = (u_int32_t *)dc->dc_videobase;
288 
289 	/* initialize the raster console blitter */
290 	rcp = &dc->dc_rcons;
291 	rcp->rc_sp = rap;
292 	rcp->rc_crow = rcp->rc_ccol = -1;
293 	rcp->rc_crowp = &rcp->rc_crow;
294 	rcp->rc_ccolp = &rcp->rc_ccol;
295 	rcons_init(rcp, 34, 80);
296 
297 	mfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
298 	mfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
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->dc_rcons; /* one and only for now */
441 	*curxp = 0;
442 	*curyp = 0;
443 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 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 
483         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
484 
485         wsdisplay_cnattach(&mfb_stdscreen, &dcp->dc_rcons,
486                            0, 0, defattr);
487         mfb_consaddr = addr;
488         return (0);
489 }
490 
491 
492 static int
493 mfbintr(arg)
494 	void *arg;
495 {
496 	struct mfb_softc *sc = arg;
497 	caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
498 	void *vdac, *curs;
499 	int v;
500 	volatile register int junk;
501 
502 	junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
503 #if 0
504 	*(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
505 #endif
506 	if (sc->sc_changed == 0)
507 		return (1);
508 
509 	vdac = (void *)(mfbbase + MX_BT455_OFFSET);
510 	curs = (void *)(mfbbase + MX_BT431_OFFSET);
511 	v = sc->sc_changed;
512 	sc->sc_changed = 0;
513 	if (v & DATA_ENB_CHANGED) {
514 		SELECT431(curs, BT431_REG_COMMAND);
515 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
516 	}
517 	if (v & DATA_CURCMAP_CHANGED) {
518 		u_int8_t *cp = sc->sc_cursor.cc_color;
519 
520 		SELECT455(vdac, 8);
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_cmap) = 0;	tc_wmb();
526 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
527 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
528 
529 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
530 		BYTE(vdac, bt_ovly) = cp[0];	tc_wmb();
531 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
532 	}
533 	if (v & DATA_CURSHAPE_CHANGED) {
534 		u_int8_t *ip, *mp, img, msk;
535 		int bcnt;
536 
537 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
538 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
539 		bcnt = 0;
540 		SELECT431(curs, BT431_REG_CRAM_BASE);
541 
542 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
543 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
544 			/* pad right half 32 pixel when smaller than 33 */
545 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
546 				HALF(curs, bt_ram) = 0;
547 				tc_wmb();
548 			}
549 			else {
550 				img = *ip++;
551 				msk = *mp++;
552 				img &= msk;	/* cookie off image */
553 				HALF(curs, bt_ram)
554 				    = (flip[msk] << 8) | flip[img];
555 				tc_wmb();
556 			}
557 			bcnt += 2;
558 		}
559 		/* pad unoccupied scan lines */
560 		while (bcnt < CURSOR_MAX_SIZE * 16) {
561 			HALF(curs, bt_ram) = 0;
562 			tc_wmb();
563 			bcnt += 2;
564 		}
565 	}
566 	return (1);
567 }
568 
569 static void
570 mfbinit(dc)
571 	struct fb_devconfig *dc;
572 {
573 	caddr_t mfbbase = (caddr_t)dc->dc_vaddr;
574 	void *vdac = (void *)(mfbbase + MX_BT455_OFFSET);
575 	void *curs = (void *)(mfbbase + MX_BT431_OFFSET);
576 	int i;
577 
578 	SELECT431(curs, BT431_REG_COMMAND);
579 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
580 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
581 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
582 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
583 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
584 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
585 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
586 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
587 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
588 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
589 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
590 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
591 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
592 
593 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
594 	SELECT455(vdac, 0);
595 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
596 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
597 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
598 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
599 	BYTE(vdac, bt_cmap) = 0xff;		tc_wmb();
600 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
601 	for (i = 2; i < 16; i++) {
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 	}
606 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
607 	BYTE(vdac, bt_ovly) = 0xff;	tc_wmb();
608 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
609 
610 	SELECT431(curs, BT431_REG_CRAM_BASE);
611 	for (i = 0; i < 512; i++) {
612 		HALF(curs, bt_ram) = 0;	tc_wmb();
613 	}
614 }
615 
616 static int
617 set_cursor(sc, p)
618 	struct mfb_softc *sc;
619 	struct wsdisplay_cursor *p;
620 {
621 #define	cc (&sc->sc_cursor)
622 	int v, count, index;
623 
624 	v = p->which;
625 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
626 		index = p->cmap.index;
627 		count = p->cmap.count;
628 		if (index >= 2 || (index + count) > 2)
629 			return (EINVAL);
630 		if (!uvm_useracc(p->cmap.red, count, B_READ))
631 			return (EFAULT);
632 	}
633 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
634 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
635 			return (EINVAL);
636 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
637 		if (!uvm_useracc(p->image, count, B_READ) ||
638 		    !uvm_useracc(p->mask, count, B_READ))
639 			return (EFAULT);
640 	}
641 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
642 		if (v & WSDISPLAY_CURSOR_DOCUR)
643 			cc->cc_hot = p->hot;
644 		if (v & WSDISPLAY_CURSOR_DOPOS)
645 			set_curpos(sc, &p->pos);
646 		bt431_set_curpos(sc);
647 	}
648 
649 	sc->sc_changed = 0;
650 	if (v & WSDISPLAY_CURSOR_DOCUR) {
651 		sc->sc_curenb = p->enable;
652 		sc->sc_changed |= DATA_ENB_CHANGED;
653 	}
654 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
655 		copyin(p->cmap.red, &cc->cc_color[index], count);
656 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
657 	}
658 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
659 		cc->cc_size = p->size;
660 		memset(cc->cc_image, 0, sizeof cc->cc_image);
661 		copyin(p->image, cc->cc_image, count);
662 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
663 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
664 	}
665 
666 	return (0);
667 #undef cc
668 }
669 
670 static int
671 get_cursor(sc, p)
672 	struct mfb_softc *sc;
673 	struct wsdisplay_cursor *p;
674 {
675 	return (ENOTTY); /* XXX */
676 }
677 
678 static void
679 set_curpos(sc, curpos)
680 	struct mfb_softc *sc;
681 	struct wsdisplay_curpos *curpos;
682 {
683 	struct fb_devconfig *dc = sc->sc_dc;
684 	int x = curpos->x, y = curpos->y;
685 
686 	if (y < 0)
687 		y = 0;
688 	else if (y > dc->dc_ht)
689 		y = dc->dc_ht;
690 	if (x < 0)
691 		x = 0;
692 	else if (x > dc->dc_wid)
693 		x = dc->dc_wid;
694 	sc->sc_cursor.cc_pos.x = x;
695 	sc->sc_cursor.cc_pos.y = y;
696 }
697 
698 static void
699 bt431_set_curpos(sc)
700 	struct mfb_softc *sc;
701 {
702 	caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
703 	void *curs = (void *)(mfbbase + MX_BT431_OFFSET);
704 	u_int16_t twin;
705 	int x, y, s;
706 
707 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
708 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
709 
710 	x += sc->sc_cursor.cc_magic.x;
711 	y += sc->sc_cursor.cc_magic.y;
712 
713 	s = spltty();
714 
715 	SELECT431(curs, BT431_REG_CURSOR_X_LOW);
716 	HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
717 	HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
718 	HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
719 	HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
720 
721 	splx(s);
722 }
723