xref: /netbsd-src/sys/dev/tc/tfb.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /* $NetBSD: tfb.c,v 1.63 2019/11/10 21:16:37 chs 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: tfb.c,v 1.63 2019/11/10 21:16:37 chs 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/bt463reg.h>
54 #include <dev/ic/bt431reg.h>
55 
56 #if defined(pmax)
57 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
58 #endif
59 
60 #if defined(alpha)
61 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
62 #endif
63 
64 /*
65  * struct bt463reg {
66  * 	uint8_t		bt_lo;
67  * 	unsigned : 24;
68  * 	uint8_t		bt_hi;
69  * 	unsigned : 24;
70  * 	uint8_t		bt_reg;
71  * 	unsigned : 24;
72  * 	uint8_t		bt_cmap;
73  * };
74  *
75  * N.B. a pair of Bt431s are located adjascently.
76  * 	struct bt431twin {
77  *		struct {
78  *			uint8_t u0;	for sprite mask
79  *			uint8_t u1;	for sprite image
80  *			unsigned :16;
81  *		} bt_lo;
82  *		...
83  *
84  * struct bt431reg {
85  * 	uint16_t	bt_lo;
86  * 	unsigned : 16;
87  * 	uint16_t	bt_hi;
88  * 	unsigned : 16;
89  * 	uint16_t	bt_ram;
90  * 	unsigned : 16;
91  * 	uint16_t	bt_ctl;
92  * };
93  */
94 
95 /* Bt463 hardware registers, memory-mapped in 32bit stride */
96 #define	bt_lo	0x0
97 #define	bt_hi	0x4
98 #define	bt_reg	0x8
99 #define	bt_cmap	0xc
100 
101 /* Bt431 hardware registers, memory-mapped in 32bit stride */
102 #define	bt_ram	0x8
103 #define	bt_ctl	0xc
104 
105 #define	REGWRITE32(p,i,v) do {					\
106 	*(volatile uint32_t *)((p) + (i)) = (v); tc_wmb();	\
107     } while (0)
108 
109 #define	SELECT463(p,r) do {					\
110 	REGWRITE32((p), bt_lo, 0xff & (r));			\
111 	REGWRITE32((p), bt_hi, 0xff & ((r)>>8));		\
112    } while (0)
113 
114 #define	TWIN(x)	   ((x) | ((x) << 8))
115 #define	TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
116 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
117 
118 #define	SELECT431(p,r) do {					\
119 	REGWRITE32((p), bt_lo, TWIN(r));			\
120 	REGWRITE32((p), bt_hi, 0);				\
121    } while (0)
122 
123 struct hwcmap256 {
124 #define	CMAP_SIZE	256	/* R/G/B entries */
125 	uint8_t r[CMAP_SIZE];
126 	uint8_t g[CMAP_SIZE];
127 	uint8_t b[CMAP_SIZE];
128 };
129 
130 struct hwcursor64 {
131 	struct wsdisplay_curpos cc_pos;
132 	struct wsdisplay_curpos cc_hot;
133 	struct wsdisplay_curpos cc_size;
134 	struct wsdisplay_curpos cc_magic;
135 #define	CURSOR_MAX_SIZE	64
136 	uint8_t cc_color[6];
137 	uint64_t cc_image[CURSOR_MAX_SIZE];
138 	uint64_t cc_mask[CURSOR_MAX_SIZE];
139 };
140 
141 struct tfb_softc {
142 	vaddr_t sc_vaddr;
143 	size_t sc_size;
144 	struct rasops_info *sc_ri;
145 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
146 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
147 	int sc_blanked;			/* video visibility disabled */
148 	int sc_curenb;			/* cursor sprite enabled */
149 	int sc_changed;			/* need update of hardware */
150 #define	WSDISPLAY_CMAP_DOLUT	0x20
151 	int nscreens;
152 };
153 
154 #define	TX_MAGIC_X	360
155 #define	TX_MAGIC_Y	36
156 
157 #define	TX_BT463_OFFSET	0x040000
158 #define	TX_BT431_OFFSET	0x040010
159 #define	TX_CONTROL	0x040030
160 #define	TX_MAP_REGISTER	0x040030
161 #define	TX_PIP_OFFSET	0x0800c0
162 #define	TX_SELECTION	0x100000
163 #define	TX_8BPP_OFFSET	0x200000
164 #define	TX_8BPP_SIZE	0x200000
165 #define	TX_24BPP_OFFSET	0x400000
166 #define	TX_24BPP_SIZE	0x600000
167 #define	TX_VIDEO_ENABLE	0xa00000
168 
169 #define	TX_CTL_VIDEO_ON	0x80
170 #define	TX_CTL_INT_ENA	0x40
171 #define	TX_CTL_INT_PEND	0x20
172 #define	TX_CTL_SEG_ENA	0x10
173 #define	TX_CTL_SEG	0x0f
174 
175 static int  tfbmatch(device_t, cfdata_t, void *);
176 static void tfbattach(device_t, device_t, void *);
177 
178 CFATTACH_DECL_NEW(tfb, sizeof(struct tfb_softc),
179     tfbmatch, tfbattach, NULL, NULL);
180 
181 static void tfb_common_init(struct rasops_info *);
182 static void tfb_cmap_init(struct tfb_softc *);
183 static struct rasops_info tfb_console_ri;
184 static tc_addr_t tfb_consaddr;
185 
186 static struct wsscreen_descr tfb_stdscreen = {
187 	"std", 0, 0,
188 	0, /* textops */
189 	0, 0,
190 	WSSCREEN_REVERSE
191 };
192 
193 static const struct wsscreen_descr *_tfb_scrlist[] = {
194 	&tfb_stdscreen,
195 };
196 
197 static const struct wsscreen_list tfb_screenlist = {
198 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
199 };
200 
201 static int	tfbioctl(void *, void *, u_long, void *, int, struct lwp *);
202 static paddr_t	tfbmmap(void *, void *, off_t, int);
203 
204 static int	tfb_alloc_screen(void *, const struct wsscreen_descr *,
205 				      void **, int *, int *, long *);
206 static void	tfb_free_screen(void *, void *);
207 static int	tfb_show_screen(void *, void *, int,
208 				     void (*) (void *, int, int), void *);
209 
210 static const struct wsdisplay_accessops tfb_accessops = {
211 	tfbioctl,
212 	tfbmmap,
213 	tfb_alloc_screen,
214 	tfb_free_screen,
215 	tfb_show_screen,
216 	0 /* load_font */
217 };
218 
219 int  tfb_cnattach(tc_addr_t);
220 static int  tfbintr(void *);
221 static void tfbhwinit(void *);
222 
223 static int  get_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
224 static int  set_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
225 static int  set_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
226 static int  get_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
227 static void set_curpos(struct tfb_softc *, struct wsdisplay_curpos *);
228 
229 /* bit order reverse */
230 static const uint8_t flip[256] = {
231 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
232 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
233 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
234 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
235 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
236 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
237 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
238 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
239 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
240 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
241 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
242 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
243 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
244 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
245 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
246 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
247 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
248 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
249 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
250 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
251 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
252 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
253 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
254 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
255 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
256 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
257 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
258 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
259 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
260 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
261 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
262 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
263 };
264 
265 static int
266 tfbmatch(device_t parent, cfdata_t match, void *aux)
267 {
268 	struct tc_attach_args *ta = aux;
269 
270 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
271 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
272 		return (0);
273 
274 	return (1);
275 }
276 
277 
278 static void
279 tfbattach(device_t parent, device_t self, void *aux)
280 {
281 	struct tfb_softc *sc = device_private(self);
282 	struct tc_attach_args *ta = aux;
283 	struct rasops_info *ri;
284 	struct wsemuldisplaydev_attach_args waa;
285 	int console;
286 
287 	console = (ta->ta_addr == tfb_consaddr);
288 	if (console) {
289 		sc->sc_ri = ri = &tfb_console_ri;
290 		ri->ri_flg &= ~RI_NO_AUTO;
291 		sc->nscreens = 1;
292 	}
293 	else {
294 		ri = malloc(sizeof(struct rasops_info),
295 			M_DEVBUF, M_WAITOK | M_ZERO);
296 		ri->ri_hw = (void *)ta->ta_addr;
297 		tfb_common_init(ri);
298 		sc->sc_ri = ri;
299 	}
300 	printf(": %dx%d, 8,24bpp\n", ri->ri_width, ri->ri_height);
301 
302 	tfb_cmap_init(sc);
303 
304 	sc->sc_vaddr = ta->ta_addr;
305 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
306 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
307 	sc->sc_blanked = sc->sc_curenb = 0;
308 
309 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
310 
311 	*(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) &= ~0x40;
312 	*(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) |= 0x40;
313 
314 	waa.console = console;
315 	waa.scrdata = &tfb_screenlist;
316 	waa.accessops = &tfb_accessops;
317 	waa.accesscookie = sc;
318 
319 	config_found(self, &waa, wsemuldisplaydevprint);
320 }
321 
322 static void
323 tfb_common_init(struct rasops_info *ri)
324 {
325 	char *base;
326 	int cookie;
327 
328 	base = (void *)ri->ri_hw;
329 
330 	/* initialize colormap and cursor hardware */
331 	tfbhwinit(base);
332 
333 	ri->ri_flg = RI_CENTER;
334 	if (ri == &tfb_console_ri)
335 		ri->ri_flg |= RI_NO_AUTO;
336 	ri->ri_depth = 8;
337 	ri->ri_width = 1280;
338 	ri->ri_height = 1024;
339 	ri->ri_stride = 1280;
340 	ri->ri_bits = base + TX_8BPP_OFFSET;
341 
342 	/* clear the screen */
343 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
344 
345 	wsfont_init();
346 	/* prefer 12 pixel wide font */
347 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
348 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
349 	if (cookie <= 0)
350 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
351 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
352 	if (cookie <= 0) {
353 		printf("tfb: font table is empty\n");
354 		return;
355 	}
356 
357 	if (wsfont_lock(cookie, &ri->ri_font)) {
358 		printf("tfb: couldn't lock font\n");
359 		return;
360 	}
361 	ri->ri_wsfcookie = cookie;
362 
363 	rasops_init(ri, 34, 80);
364 
365 	/* XXX shouldn't be global */
366 	tfb_stdscreen.nrows = ri->ri_rows;
367 	tfb_stdscreen.ncols = ri->ri_cols;
368 	tfb_stdscreen.textops = &ri->ri_ops;
369 	tfb_stdscreen.capabilities = ri->ri_caps;
370 }
371 
372 static void
373 tfb_cmap_init(struct tfb_softc *sc)
374 {
375 	struct hwcmap256 *cm;
376 	const uint8_t *p;
377 	int index;
378 
379 	cm = &sc->sc_cmap;
380 	p = rasops_cmap;
381 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
382 		cm->r[index] = p[0];
383 		cm->g[index] = p[1];
384 		cm->b[index] = p[2];
385 	}
386 }
387 
388 static int
389 tfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
390 {
391 	struct tfb_softc *sc = v;
392 	struct rasops_info *ri = sc->sc_ri;
393 	int turnoff, s;
394 
395 	switch (cmd) {
396 	case WSDISPLAYIO_GTYPE:
397 		*(u_int *)data = WSDISPLAY_TYPE_TX;
398 		return (0);
399 
400 	case WSDISPLAYIO_GINFO:
401 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
402 		wsd_fbip->height = ri->ri_height;
403 		wsd_fbip->width = ri->ri_width;
404 		wsd_fbip->depth = ri->ri_depth;
405 		wsd_fbip->cmsize = CMAP_SIZE;
406 #undef fbt
407 		return (0);
408 
409 	case WSDISPLAYIO_GETCMAP:
410 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
411 
412 	case WSDISPLAYIO_PUTCMAP:
413 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
414 
415 	case WSDISPLAYIO_SVIDEO:
416 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
417 		if (sc->sc_blanked != turnoff) {
418 			sc->sc_blanked = turnoff;
419 #if 0	/* XXX later XXX */
420 	To turn off;
421 	- clear the MSB of TX control register; &= ~0x80,
422 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
423 #endif	/* XXX XXX XXX */
424 		}
425 		return (0);
426 
427 	case WSDISPLAYIO_GVIDEO:
428 		*(u_int *)data = sc->sc_blanked ?
429 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
430 		return (0);
431 
432 	case WSDISPLAYIO_GCURPOS:
433 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
434 		return (0);
435 
436 	case WSDISPLAYIO_SCURPOS:
437 		s = spltty();
438 		set_curpos(sc, (struct wsdisplay_curpos *)data);
439 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
440 		splx(s);
441 		return (0);
442 
443 	case WSDISPLAYIO_GCURMAX:
444 		((struct wsdisplay_curpos *)data)->x =
445 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
446 		return (0);
447 
448 	case WSDISPLAYIO_GCURSOR:
449 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
450 
451 	case WSDISPLAYIO_SCURSOR:
452 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
453 
454 	case WSDISPLAYIO_SMODE:
455 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
456 			s = spltty();
457 			tfb_cmap_init(sc);
458 			sc->sc_curenb = 0;
459 			sc->sc_blanked = 0;
460 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
461 			    WSDISPLAY_CMAP_DOLUT);
462 			splx(s);
463 		}
464 		return (0);
465 	}
466 	return (EPASSTHROUGH);
467 }
468 
469 static paddr_t
470 tfbmmap(void *v, void *vs, off_t offset, int prot)
471 {
472 	struct tfb_softc *sc = v;
473 
474 	if (offset >= TX_8BPP_SIZE || offset < 0) /* XXX 24bpp XXX */
475 		return (-1);
476 	return machine_btop(sc->sc_vaddr + TX_8BPP_OFFSET + offset);
477 }
478 
479 static int
480 tfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
481     int *curxp, int *curyp, long *attrp)
482 {
483 	struct tfb_softc *sc = v;
484 	struct rasops_info *ri = sc->sc_ri;
485 	long defattr;
486 
487 	if (sc->nscreens > 0)
488 		return (ENOMEM);
489 
490 	*cookiep = ri; /* one and only for now */
491 	*curxp = 0;
492 	*curyp = 0;
493 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
494 	*attrp = defattr;
495 	sc->nscreens++;
496 	return (0);
497 }
498 
499 static void
500 tfb_free_screen(void *v, void *cookie)
501 {
502 	struct tfb_softc *sc = v;
503 
504 	if (sc->sc_ri == &tfb_console_ri)
505 		panic("tfb_free_screen: console");
506 
507 	sc->nscreens--;
508 }
509 
510 static int
511 tfb_show_screen(void *v, void *cookie, int waitok,
512     void (*cb)(void *, int, int), void *cbarg)
513 {
514 
515 	return (0);
516 }
517 
518 /* EXPORT */ int
519 tfb_cnattach(tc_addr_t addr)
520 {
521 	struct rasops_info *ri;
522 	long defattr;
523 
524 	ri = &tfb_console_ri;
525 	ri->ri_hw = (void *)addr;
526 	tfb_common_init(ri);
527 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
528 	wsdisplay_cnattach(&tfb_stdscreen, ri, 0, 0, defattr);
529 	tfb_consaddr = addr;
530 	return (0);
531 }
532 
533 static int
534 tfbintr(void *arg)
535 {
536 	struct tfb_softc *sc = arg;
537 	char *base, *vdac, *curs;
538 	int v;
539 
540 	base = (void *)sc->sc_ri->ri_hw;
541 	*(uint8_t *)(base + TX_CONTROL) &= ~0x40;
542 	if (sc->sc_changed == 0)
543 		goto done;
544 
545 	vdac = base + TX_BT463_OFFSET;
546 	curs = base + TX_BT431_OFFSET;
547 	v = sc->sc_changed;
548 	if (v & WSDISPLAY_CURSOR_DOCUR) {
549 		int onoff;
550 
551 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
552 		SELECT431(curs, BT431_REG_COMMAND);
553 		REGWRITE32(curs, bt_ctl, onoff);
554 	}
555 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
556 		int x, y;
557 		uint32_t twin;
558 
559 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
560 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
561 
562 		x += sc->sc_cursor.cc_magic.x;
563 		y += sc->sc_cursor.cc_magic.y;
564 
565 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
566 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
567 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
568 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
569 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
570 	}
571 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
572 		uint8_t *cp = sc->sc_cursor.cc_color;
573 
574 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
575 		REGWRITE32(vdac, bt_reg, cp[1]);
576 		REGWRITE32(vdac, bt_reg, cp[3]);
577 		REGWRITE32(vdac, bt_reg, cp[5]);
578 
579 		REGWRITE32(vdac, bt_reg, cp[0]);
580 		REGWRITE32(vdac, bt_reg, cp[2]);
581 		REGWRITE32(vdac, bt_reg, cp[4]);
582 
583 		REGWRITE32(vdac, bt_reg, cp[1]);
584 		REGWRITE32(vdac, bt_reg, cp[3]);
585 		REGWRITE32(vdac, bt_reg, cp[5]);
586 
587 		REGWRITE32(vdac, bt_reg, cp[1]);
588 		REGWRITE32(vdac, bt_reg, cp[3]);
589 		REGWRITE32(vdac, bt_reg, cp[5]);
590 	}
591 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
592 		uint8_t *ip, *mp, img, msk;
593 		int bcnt;
594 
595 		ip = (uint8_t *)sc->sc_cursor.cc_image;
596 		mp = (uint8_t *)sc->sc_cursor.cc_mask;
597 		bcnt = 0;
598 		SELECT431(curs, BT431_REG_CRAM_BASE);
599 
600 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
601 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
602 			/* pad right half 32 pixel when smaller than 33 */
603 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
604 				REGWRITE32(curs, bt_ram, 0);
605 			}
606 			else {
607 				int half;
608 				img = *ip++;
609 				msk = *mp++;
610 				img &= msk;	/* cookie off image */
611 				half = (flip[img] << 8) | flip[msk];
612 				REGWRITE32(curs, bt_ram, half);
613 			}
614 			bcnt += 2;
615 		}
616 		/* pad unoccupied scan lines */
617 		while (bcnt < CURSOR_MAX_SIZE * 16) {
618 			REGWRITE32(curs, bt_ram, 0);
619 			bcnt += 2;
620 		}
621 	}
622 	if (v & WSDISPLAY_CMAP_DOLUT) {
623 		struct hwcmap256 *cm = &sc->sc_cmap;
624 		int index;
625 
626 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
627 		for (index = 0; index < CMAP_SIZE; index++) {
628 			REGWRITE32(vdac, bt_cmap, cm->r[index]);
629 			REGWRITE32(vdac, bt_cmap, cm->g[index]);
630 			REGWRITE32(vdac, bt_cmap, cm->b[index]);
631 		}
632 	}
633 	sc->sc_changed = 0;
634 done:
635 	*(uint8_t *)(base + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
636 	*(uint8_t *)(base + TX_CONTROL) |= 0x40;
637 	return (1);
638 }
639 
640 static void
641 tfbhwinit(void *tfbbase)
642 {
643 	char *vdac, *curs;
644 	const uint8_t *p;
645 	int i;
646 
647 	vdac = (char *)tfbbase + TX_BT463_OFFSET;
648 	curs = (char *)tfbbase + TX_BT431_OFFSET;
649 	SELECT463(vdac, BT463_IREG_COMMAND_0);
650 	REGWRITE32(vdac, bt_reg, 0x40);	/* CMD 0 */
651 	REGWRITE32(vdac, bt_reg, 0x46);	/* CMD 1 */
652 	REGWRITE32(vdac, bt_reg, 0xc0);	/* CMD 2 */
653 	REGWRITE32(vdac, bt_reg, 0);	/* !? 204 !? */
654 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  0:7  */
655 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  8:15 */
656 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 16:23 */
657 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 24:27 */
658 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  0:7  */
659 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  8:15 */
660 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 16:23 */
661 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 24:27 */
662 	REGWRITE32(vdac, bt_reg, 0x00);
663 
664 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
665   {
666 	static uint32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
667 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
668 	};
669 
670 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
671 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
672 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
673 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
674 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
675 	}
676   }
677 #endif
678 
679 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
680 	p = rasops_cmap;
681 	for (i = 0; i < 256; i++, p += 3) {
682 		REGWRITE32(vdac, bt_cmap, p[0]);
683 		REGWRITE32(vdac, bt_cmap, p[1]);
684 		REGWRITE32(vdac, bt_cmap, p[2]);
685 	}
686 
687 	/* !? Eeeh !? */
688 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
689 	for (i = 0; i < 256; i++) {
690 		REGWRITE32(vdac, bt_cmap, i);
691 		REGWRITE32(vdac, bt_cmap, i);
692 		REGWRITE32(vdac, bt_cmap, i);
693 	}
694 
695 	SELECT431(curs, BT431_REG_COMMAND);
696 	REGWRITE32(curs, bt_ctl, 0x0404);
697 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
698 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
699 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
700 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
701 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
702 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
703 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
704 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
705 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
706 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
707 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
708 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
709 
710 	SELECT431(curs, BT431_REG_CRAM_BASE);
711 	for (i = 0; i < 512; i++) {
712 		REGWRITE32(curs, bt_ram, 0);
713 	}
714 }
715 
716 static int
717 get_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
718 {
719 	u_int index = p->index, count = p->count;
720 	int error;
721 
722 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
723 		return (EINVAL);
724 
725 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
726 	if (error)
727 		return error;
728 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
729 	if (error)
730 		return error;
731 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
732 	return error;
733 }
734 
735 static int
736 set_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
737 {
738 	struct hwcmap256 cmap;
739 	u_int index = p->index, count = p->count;
740 	int error, s;
741 
742 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
743 		return (EINVAL);
744 
745 	error = copyin(p->red, &cmap.r[index], count);
746 	if (error)
747 		return error;
748 	error = copyin(p->green, &cmap.g[index], count);
749 	if (error)
750 		return error;
751 	error = copyin(p->blue, &cmap.b[index], count);
752 	if (error)
753 		return error;
754 	s = spltty();
755 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
756 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
757 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
758 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
759 	splx(s);
760 	return (0);
761 }
762 
763 static int
764 set_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
765 {
766 #define	cc (&sc->sc_cursor)
767 	u_int v, index = 0, count = 0, icount = 0;
768 	uint8_t r[2], g[2], b[2], image[512], mask[512];
769 	int error, s;
770 
771 	v = p->which;
772 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
773 		index = p->cmap.index;
774 		count = p->cmap.count;
775 		if (index >= 2 || count > 2 - index)
776 			return (EINVAL);
777 		error = copyin(p->cmap.red, &r[index], count);
778 		if (error)
779 			return error;
780 		error = copyin(p->cmap.green, &g[index], count);
781 		if (error)
782 			return error;
783 		error = copyin(p->cmap.blue, &b[index], count);
784 		if (error)
785 			return error;
786 	}
787 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
788 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
789 			return (EINVAL);
790 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
791 		error = copyin(p->image, image, icount);
792 		if (error)
793 			return error;
794 		error = copyin(p->mask, mask, icount);
795 		if (error)
796 			return error;
797 	}
798 
799 	s = spltty();
800 	if (v & WSDISPLAY_CURSOR_DOCUR)
801 		sc->sc_curenb = p->enable;
802 	if (v & WSDISPLAY_CURSOR_DOPOS)
803 		set_curpos(sc, &p->pos);
804 	if (v & WSDISPLAY_CURSOR_DOHOT)
805 		cc->cc_hot = p->hot;
806 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
807 		memcpy(&cc->cc_color[index], &r[index], count);
808 		memcpy(&cc->cc_color[index + 2], &g[index], count);
809 		memcpy(&cc->cc_color[index + 4], &b[index], count);
810 	}
811 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
812 		cc->cc_size = p->size;
813 		memset(cc->cc_image, 0, sizeof cc->cc_image);
814 		memcpy(cc->cc_image, image, icount);
815 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
816 		memcpy(cc->cc_mask, mask, icount);
817 	}
818 	sc->sc_changed |= v;
819 	splx(s);
820 
821 	return (0);
822 #undef cc
823 }
824 
825 static int
826 get_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
827 {
828 	return (EPASSTHROUGH); /* XXX */
829 }
830 
831 static void
832 set_curpos(struct tfb_softc *sc, struct wsdisplay_curpos *curpos)
833 {
834 	struct rasops_info *ri = sc->sc_ri;
835 	int x = curpos->x, y = curpos->y;
836 
837 	if (y < 0)
838 		y = 0;
839 	else if (y > ri->ri_height)
840 		y = ri->ri_height;
841 	if (x < 0)
842 		x = 0;
843 	else if (x > ri->ri_width)
844 		x = ri->ri_width;
845 	sc->sc_cursor.cc_pos.x = x;
846 	sc->sc_cursor.cc_pos.y = y;
847 }
848