1/* $NetBSD: mfb.c,v 1.64 2021/12/06 16:00:07 abs Exp $ */
2
3/*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.64 2021/12/06 16:00:07 abs Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/device.h>
39#include <sys/malloc.h>
40#include <sys/buf.h>
41#include <sys/ioctl.h>
42
43#include <sys/bus.h>
44#include <sys/intr.h>
45
46#include <dev/wscons/wsconsio.h>
47#include <dev/wscons/wsdisplayvar.h>
48
49#include <dev/rasops/rasops.h>
50#include <dev/wsfont/wsfont.h>
51
52#include <dev/tc/tcvar.h>
53#include <dev/ic/bt431reg.h>
54
55#if defined(pmax)
56#define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
57#endif
58
59#if defined(alpha)
60#define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
61#endif
62
63/* Bt455 hardware registers, memory-mapped in 32bit stride */
64#define	bt_reg	0x0
65#define	bt_cmap	0x4
66#define	bt_clr	0x8
67#define	bt_ovly	0xc
68
69/* Bt431 hardware registers, memory-mapped in 32bit stride */
70#define	bt_lo	0x0
71#define	bt_hi	0x4
72#define	bt_ram	0x8
73#define	bt_ctl	0xc
74
75#define	REGWRITE32(p,i,v) do {					\
76	*(volatile uint32_t *)((p) + (i)) = (v); tc_wmb();	\
77    } while (0)
78
79#define	SELECT455(p,r) do {					\
80	REGWRITE32((p), bt_reg, (r));				\
81	REGWRITE32((p), bt_clr, 0);				\
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(p,r) do {					\
89	REGWRITE32((p), bt_lo, TWIN(r));			\
90	REGWRITE32((p), bt_hi, 0);				\
91   } while (0)
92
93struct hwcursor64 {
94	struct wsdisplay_curpos cc_pos;
95	struct wsdisplay_curpos cc_hot;
96	struct wsdisplay_curpos cc_size;
97	struct wsdisplay_curpos cc_magic;
98#define	CURSOR_MAX_SIZE	64
99	uint8_t cc_color[6];
100	uint64_t cc_image[CURSOR_MAX_SIZE];
101	uint64_t cc_mask[CURSOR_MAX_SIZE];
102};
103
104struct mfb_softc {
105	vaddr_t sc_vaddr;
106	size_t sc_size;
107	struct rasops_info *sc_ri;
108	struct hwcursor64 sc_cursor;	/* software copy of cursor */
109	int sc_blanked;
110	int sc_curenb;			/* cursor sprite enabled */
111	int sc_changed;			/* need update of hardware */
112	int nscreens;
113};
114
115#define	MX_MAGIC_X	360
116#define	MX_MAGIC_Y	36
117
118#define	MX_FB_OFFSET	0x200000
119#define	MX_FB_SIZE	0x200000
120#define	MX_BT455_OFFSET	0x100000
121#define	MX_BT431_OFFSET	0x180000
122#define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
123
124static int  mfbmatch(device_t, cfdata_t, void *);
125static void mfbattach(device_t, device_t, void *);
126
127CFATTACH_DECL_NEW(mfb, sizeof(struct mfb_softc),
128    mfbmatch, mfbattach, NULL, NULL);
129
130static void mfb_common_init(struct rasops_info *);
131static struct rasops_info mfb_console_ri;
132static tc_addr_t mfb_consaddr;
133
134static struct wsscreen_descr mfb_stdscreen = {
135	"std", 0, 0,
136	0, /* textops */
137	0, 0,
138	WSSCREEN_REVERSE
139};
140
141static const struct wsscreen_descr *_mfb_scrlist[] = {
142	&mfb_stdscreen,
143};
144
145static const struct wsscreen_list mfb_screenlist = {
146	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
147};
148
149static int	mfbioctl(void *, void *, u_long, void *, int, struct lwp *);
150static paddr_t	mfbmmap(void *, void *, off_t, int);
151
152static int	mfb_alloc_screen(void *, const struct wsscreen_descr *,
153				      void **, int *, int *, long *);
154static void	mfb_free_screen(void *, void *);
155static int	mfb_show_screen(void *, void *, int,
156				     void (*) (void *, int, int), void *);
157
158static const struct wsdisplay_accessops mfb_accessops = {
159	mfbioctl,
160	mfbmmap,
161	mfb_alloc_screen,
162	mfb_free_screen,
163	mfb_show_screen,
164	0 /* load_font */
165};
166
167int  mfb_cnattach(tc_addr_t);
168static int  mfbintr(void *);
169static void mfbhwinit(void *);
170
171static int  set_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
172static int  get_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
173static void set_curpos(struct mfb_softc *, struct wsdisplay_curpos *);
174
175/* bit order reverse */
176static const uint8_t flip[256] = {
177	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
178	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
179	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
180	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
181	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
182	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
183	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
184	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
185	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
186	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
187	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
188	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
189	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
190	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
191	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
192	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
193	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
194	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
195	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
196	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
197	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
198	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
199	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
200	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
201	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
202	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
203	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
204	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
205	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
206	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
207	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
208	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
209};
210
211static int
212mfbmatch(device_t parent, cfdata_t match, void *aux)
213{
214	struct tc_attach_args *ta = aux;
215
216	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
217		return (0);
218
219	return (1);
220}
221
222static void
223mfbattach(device_t parent, device_t self, void *aux)
224{
225	struct mfb_softc *sc = device_private(self);
226	struct tc_attach_args *ta = aux;
227	struct rasops_info *ri;
228	struct wsemuldisplaydev_attach_args waa;
229	int console;
230	volatile register int junk;
231
232	console = (ta->ta_addr == mfb_consaddr);
233	if (console) {
234		sc->sc_ri = ri = &mfb_console_ri;
235		ri->ri_flg &= ~RI_NO_AUTO;
236		sc->nscreens = 1;
237	}
238	else {
239		ri = malloc(sizeof(struct rasops_info),
240			M_DEVBUF, M_WAITOK | M_ZERO);
241		ri->ri_hw = (void *)ta->ta_addr;
242		mfb_common_init(ri);
243		sc->sc_ri = ri;
244	}
245	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
246
247	sc->sc_vaddr = ta->ta_addr;
248	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
249	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
250	sc->sc_blanked = sc->sc_curenb = 0;
251
252	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
253
254	/* clear any pending interrupts */
255	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
256	junk = *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
257	__USE(junk);
258	*(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
259
260	waa.console = console;
261	waa.scrdata = &mfb_screenlist;
262	waa.accessops = &mfb_accessops;
263	waa.accesscookie = sc;
264
265	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
266}
267
268static void
269mfb_common_init(struct rasops_info *ri)
270{
271	char *base;
272	int cookie;
273
274	base = (void *)ri->ri_hw;
275
276	/* initialize colormap and cursor hardware */
277	mfbhwinit(base);
278
279	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
280	if (ri == &mfb_console_ri)
281		ri->ri_flg |= RI_NO_AUTO;
282	ri->ri_depth = 8;	/* !! watch out !! */
283	ri->ri_width = 1280;
284	ri->ri_height = 1024;
285	ri->ri_stride = 2048;
286	ri->ri_bits = base + MX_FB_OFFSET;
287
288	/* clear the screen */
289	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
290
291	wsfont_init();
292	/* prefer 12 pixel wide font */
293	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
294	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
295	if (cookie <= 0)
296		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
297		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
298	if (cookie <= 0) {
299		printf("mfb: font table is empty\n");
300		return;
301	}
302
303	if (wsfont_lock(cookie, &ri->ri_font)) {
304		printf("mfb: couldn't lock font\n");
305		return;
306	}
307	ri->ri_wsfcookie = cookie;
308
309	rasops_init(ri, 34, 80);
310
311	/* XXX shouldn't be global */
312	mfb_stdscreen.nrows = ri->ri_rows;
313	mfb_stdscreen.ncols = ri->ri_cols;
314	mfb_stdscreen.textops = &ri->ri_ops;
315	mfb_stdscreen.capabilities = ri->ri_caps;
316}
317
318static int
319mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
320{
321	struct mfb_softc *sc = v;
322	struct rasops_info *ri = sc->sc_ri;
323	int turnoff, s;
324
325	switch (cmd) {
326	case WSDISPLAYIO_GTYPE:
327		*(u_int *)data = WSDISPLAY_TYPE_MFB;
328		return (0);
329
330	case WSDISPLAYIO_GET_FBINFO: {
331		struct wsdisplayio_fbinfo *fbi = data;
332		return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
333	}
334
335	case WSDISPLAYIO_GINFO:
336#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
337		wsd_fbip->height = ri->ri_height;
338		wsd_fbip->width = ri->ri_width;
339		wsd_fbip->depth = ri->ri_depth;
340		wsd_fbip->cmsize = 0;
341#undef fbt
342		return (0);
343
344	case WSDISPLAYIO_GETCMAP:
345	case WSDISPLAYIO_PUTCMAP:
346		return (EPASSTHROUGH);
347
348	case WSDISPLAYIO_SVIDEO:
349		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
350		if (sc->sc_blanked != turnoff) {
351			sc->sc_blanked = turnoff;
352#if 0	/* XXX later XXX */
353	To turn off,
354	- assign Bt455 cmap[1].green with value 0 (black),
355	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
356#endif	/* XXX XXX XXX */
357		}
358		return (0);
359
360	case WSDISPLAYIO_GVIDEO:
361		*(u_int *)data = sc->sc_blanked ?
362		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
363		return (0);
364
365	case WSDISPLAYIO_GCURPOS:
366		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
367		return (0);
368
369	case WSDISPLAYIO_SCURPOS:
370		s = spltty();
371		set_curpos(sc, (struct wsdisplay_curpos *)data);
372		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
373		splx(s);
374		return (0);
375
376	case WSDISPLAYIO_GCURMAX:
377		((struct wsdisplay_curpos *)data)->x =
378		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
379		return (0);
380
381	case WSDISPLAYIO_GCURSOR:
382		return get_cursor(sc, (struct wsdisplay_cursor *)data);
383
384	case WSDISPLAYIO_SCURSOR:
385		return set_cursor(sc, (struct wsdisplay_cursor *)data);
386
387	case WSDISPLAYIO_SMODE:
388		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
389			s = spltty();
390			sc->sc_curenb = 0;
391			sc->sc_blanked = 0;
392			sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
393			splx(s);
394		}
395		return (0);
396	}
397	return (EPASSTHROUGH);
398}
399
400static paddr_t
401mfbmmap(void *v, void *vs, off_t offset, int prot)
402{
403	struct mfb_softc *sc = v;
404
405	if (offset >= MX_FB_SIZE || offset < 0)
406		return (-1);
407	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
408}
409
410static int
411mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
412    int *curxp, int *curyp, long *attrp)
413{
414	struct mfb_softc *sc = v;
415	struct rasops_info *ri = sc->sc_ri;
416	long defattr;
417
418	if (sc->nscreens > 0)
419		return (ENOMEM);
420
421	*cookiep = ri;		 /* one and only for now */
422	*curxp = 0;
423	*curyp = 0;
424	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
425	*attrp = defattr;
426	sc->nscreens++;
427	return (0);
428}
429
430static void
431mfb_free_screen(void *v, void *cookie)
432{
433	struct mfb_softc *sc = v;
434
435	if (sc->sc_ri == &mfb_console_ri)
436		panic("mfb_free_screen: console");
437
438	sc->nscreens--;
439}
440
441static int
442mfb_show_screen(void *v, void *cookie, int waitok,
443    void (*cb)(void *, int, int), void *cbarg)
444{
445
446	return (0);
447}
448
449/* EXPORT */ int
450mfb_cnattach(tc_addr_t addr)
451{
452	struct rasops_info *ri;
453	long defattr;
454
455	ri = &mfb_console_ri;
456	ri->ri_hw = (void *)addr;
457	mfb_common_init(ri);
458	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
459	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
460	mfb_consaddr = addr;
461	return (0);
462}
463
464static int
465mfbintr(void *arg)
466{
467	struct mfb_softc *sc = arg;
468	char *base, *vdac, *curs;
469	int v;
470	volatile register int junk;
471
472	base = (void *)sc->sc_ri->ri_hw;
473	junk = *(uint8_t *)(base + MX_IREQ_OFFSET);
474	__USE(junk);
475#if 0
476	*(uint8_t *)(base + MX_IREQ_OFFSET) = 0;
477#endif
478	if (sc->sc_changed == 0)
479		return (1);
480
481	vdac = base + MX_BT455_OFFSET;
482	curs = base + MX_BT431_OFFSET;
483	v = sc->sc_changed;
484	if (v & WSDISPLAY_CURSOR_DOCUR) {
485		int  onoff;
486
487		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
488		SELECT431(curs, BT431_REG_COMMAND);
489		REGWRITE32(curs, bt_ctl, onoff);
490	}
491	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
492		int x, y;
493		uint32_t twin;
494
495		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
496		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
497
498		x += sc->sc_cursor.cc_magic.x;
499		y += sc->sc_cursor.cc_magic.y;
500
501		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
502		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
503		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
504		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
505		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
506	}
507	if (v & WSDISPLAY_CURSOR_DOCMAP) {
508		uint8_t *cp = sc->sc_cursor.cc_color;
509
510		SELECT455(vdac, 8);
511		REGWRITE32(vdac, bt_cmap, 0);
512		REGWRITE32(vdac, bt_cmap, cp[1]);
513		REGWRITE32(vdac, bt_cmap, 0);
514
515		REGWRITE32(vdac, bt_cmap, 0);
516		REGWRITE32(vdac, bt_cmap, cp[1]);
517		REGWRITE32(vdac, bt_cmap, 0);
518
519		REGWRITE32(vdac, bt_ovly, 0);
520		REGWRITE32(vdac, bt_ovly, cp[0]);
521		REGWRITE32(vdac, bt_ovly, 0);
522	}
523	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
524		uint8_t *ip, *mp, img, msk;
525		int bcnt;
526
527		ip = (uint8_t *)sc->sc_cursor.cc_image;
528		mp = (uint8_t *)sc->sc_cursor.cc_mask;
529		bcnt = 0;
530		SELECT431(curs, BT431_REG_CRAM_BASE);
531
532		/* 64 pixel scan line is consisted with 16 byte cursor ram */
533		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
534			/* pad right half 32 pixel when smaller than 33 */
535			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
536				REGWRITE32(curs, bt_ram, 0);
537			}
538			else {
539				int half;
540
541				img = *ip++;
542				msk = *mp++;
543				img &= msk;	/* cookie off image */
544				half = (flip[msk] << 8) | flip[img];
545				REGWRITE32(curs, bt_ram, half);
546			}
547			bcnt += 2;
548		}
549		/* pad unoccupied scan lines */
550		while (bcnt < CURSOR_MAX_SIZE * 16) {
551			REGWRITE32(curs, bt_ram, 0);
552			bcnt += 2;
553		}
554	}
555	sc->sc_changed = 0;
556	return (1);
557}
558
559static void
560mfbhwinit(void *mfbbase)
561{
562	char *vdac, *curs;
563	int i;
564
565	vdac = (char *)mfbbase + MX_BT455_OFFSET;
566	curs = (char *)mfbbase + MX_BT431_OFFSET;
567	SELECT431(curs, BT431_REG_COMMAND);
568	REGWRITE32(curs, bt_ctl, 0x0404);
569	REGWRITE32(curs, bt_ctl, 0); /* XLO */
570	REGWRITE32(curs, bt_ctl, 0); /* XHI */
571	REGWRITE32(curs, bt_ctl, 0); /* YLO */
572	REGWRITE32(curs, bt_ctl, 0); /* YHI */
573	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
574	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
575	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
576	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
577	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
578	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
579	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
580	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
581
582	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
583	SELECT455(vdac, 0);
584	REGWRITE32(vdac, bt_cmap, 0);
585	REGWRITE32(vdac, bt_cmap, 0);
586	REGWRITE32(vdac, bt_cmap, 0);
587	REGWRITE32(vdac, bt_cmap, 0);
588	REGWRITE32(vdac, bt_cmap, 0xff);
589	REGWRITE32(vdac, bt_cmap, 0);
590	for (i = 2; i < 16; i++) {
591		REGWRITE32(vdac, bt_cmap, 0);
592		REGWRITE32(vdac, bt_cmap, 0);
593		REGWRITE32(vdac, bt_cmap, 0);
594	}
595	REGWRITE32(vdac, bt_ovly, 0);
596	REGWRITE32(vdac, bt_ovly, 0xff);
597	REGWRITE32(vdac, bt_ovly, 0);
598
599	SELECT431(curs, BT431_REG_CRAM_BASE);
600	for (i = 0; i < 512; i++) {
601		REGWRITE32(curs, bt_ram, 0);
602	}
603}
604
605static int
606set_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
607{
608#define	cc (&sc->sc_cursor)
609	u_int v, count = 0, icount = 0, index = 0;
610	uint64_t image[CURSOR_MAX_SIZE];
611	uint64_t mask[CURSOR_MAX_SIZE];
612	uint8_t color[6];
613	int error, s;
614
615	v = p->which;
616	if (v & WSDISPLAY_CURSOR_DOCMAP) {
617		index = p->cmap.index;
618		count = p->cmap.count;
619		if (index >= 2 || count > 2 - index)
620			return (EINVAL);
621		error = copyin(p->cmap.red, &color[index], count);
622		if (error)
623			return error;
624	}
625	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
626		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
627			return (EINVAL);
628		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
629		error = copyin(p->image, image, icount);
630		if (error)
631			return error;
632		error = copyin(p->mask, mask, icount);
633		if (error)
634			return error;
635	}
636
637	s = spltty();
638	if (v & WSDISPLAY_CURSOR_DOCUR)
639		sc->sc_curenb = p->enable;
640	if (v & WSDISPLAY_CURSOR_DOPOS)
641		set_curpos(sc, &p->pos);
642	if (v & WSDISPLAY_CURSOR_DOHOT)
643		cc->cc_hot = p->hot;
644	if (v & WSDISPLAY_CURSOR_DOCMAP)
645		memcpy(&cc->cc_color[index], &color[index], count);
646	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
647		cc->cc_size = p->size;
648		memset(cc->cc_image, 0, sizeof cc->cc_image);
649		memcpy(cc->cc_image, image, icount);
650		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
651		memcpy(cc->cc_mask, mask, icount);
652	}
653	sc->sc_changed |= v;
654	splx(s);
655
656	return (0);
657#undef cc
658}
659
660static int
661get_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
662{
663	return (EPASSTHROUGH); /* XXX */
664}
665
666static void
667set_curpos(struct mfb_softc *sc, struct wsdisplay_curpos *curpos)
668{
669	struct rasops_info *ri = sc->sc_ri;
670	int x = curpos->x, y = curpos->y;
671
672	if (y < 0)
673		y = 0;
674	else if (y > ri->ri_height)
675		y = ri->ri_height;
676	if (x < 0)
677		x = 0;
678	else if (x > ri->ri_width)
679		x = ri->ri_width;
680	sc->sc_cursor.cc_pos.x = x;
681	sc->sc_cursor.cc_pos.y = y;
682}
683