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