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