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