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