xref: /netbsd-src/sys/dev/tc/tfb.c (revision cac8e449158efc7261bebc8657cbb0125a2cfdde)
1 /* $NetBSD: tfb.c,v 1.55 2008/07/09 13:19:33 joerg 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.55 2008/07/09 13:19:33 joerg 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  * 	u_int8_t	bt_lo;
69  * 	unsigned : 24;
70  * 	u_int8_t	bt_hi;
71  * 	unsigned : 24;
72  * 	u_int8_t	bt_reg;
73  * 	unsigned : 24;
74  * 	u_int8_t	bt_cmap;
75  * };
76  *
77  * N.B. a pair of Bt431s are located adjascently.
78  * 	struct bt431twin {
79  *		struct {
80  *			u_int8_t u0;	for sprite mask
81  *			u_int8_t u1;	for sprite image
82  *			unsigned :16;
83  *		} bt_lo;
84  *		...
85  *
86  * struct bt431reg {
87  * 	u_int16_t	bt_lo;
88  * 	unsigned : 16;
89  * 	u_int16_t	bt_hi;
90  * 	unsigned : 16;
91  * 	u_int16_t	bt_ram;
92  * 	unsigned : 16;
93  * 	u_int16_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 u_int32_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 	u_int8_t r[CMAP_SIZE];
128 	u_int8_t g[CMAP_SIZE];
129 	u_int8_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 	u_int8_t cc_color[6];
139 	u_int64_t cc_image[CURSOR_MAX_SIZE];
140 	u_int64_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 u_int8_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 		sc->nscreens = 1;
293 	}
294 	else {
295 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
296 			M_DEVBUF, M_NOWAIT);
297 		if (ri == NULL) {
298 			printf(": can't alloc memory\n");
299 			return;
300 		}
301 		memset(ri, 0, sizeof(struct rasops_info));
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 	*(u_int8_t *)((char *)ri->ri_hw + TX_CONTROL) &= ~0x40;
319 	*(u_int8_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 	ri->ri_depth = 8;
342 	ri->ri_width = 1280;
343 	ri->ri_height = 1024;
344 	ri->ri_stride = 1280;
345 	ri->ri_bits = base + TX_8BPP_OFFSET;
346 
347 	/* clear the screen */
348 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
349 
350 	wsfont_init();
351 	/* prefer 12 pixel wide font */
352 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
353 	    WSDISPLAY_FONTORDER_L2R);
354 	if (cookie <= 0)
355 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
356 		    WSDISPLAY_FONTORDER_L2R);
357 	if (cookie <= 0) {
358 		printf("tfb: font table is empty\n");
359 		return;
360 	}
361 
362 	if (wsfont_lock(cookie, &ri->ri_font)) {
363 		printf("tfb: couldn't lock font\n");
364 		return;
365 	}
366 	ri->ri_wsfcookie = cookie;
367 
368 	rasops_init(ri, 34, 80);
369 
370 	/* XXX shouldn't be global */
371 	tfb_stdscreen.nrows = ri->ri_rows;
372 	tfb_stdscreen.ncols = ri->ri_cols;
373 	tfb_stdscreen.textops = &ri->ri_ops;
374 	tfb_stdscreen.capabilities = ri->ri_caps;
375 }
376 
377 static void
378 tfb_cmap_init(struct tfb_softc *sc)
379 {
380 	struct hwcmap256 *cm;
381 	const u_int8_t *p;
382 	int index;
383 
384 	cm = &sc->sc_cmap;
385 	p = rasops_cmap;
386 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
387 		cm->r[index] = p[0];
388 		cm->g[index] = p[1];
389 		cm->b[index] = p[2];
390 	}
391 }
392 
393 static int
394 tfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
395 {
396 	struct tfb_softc *sc = v;
397 	struct rasops_info *ri = sc->sc_ri;
398 	int turnoff, s;
399 
400 	switch (cmd) {
401 	case WSDISPLAYIO_GTYPE:
402 		*(u_int *)data = WSDISPLAY_TYPE_TX;
403 		return (0);
404 
405 	case WSDISPLAYIO_GINFO:
406 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
407 		wsd_fbip->height = ri->ri_height;
408 		wsd_fbip->width = ri->ri_width;
409 		wsd_fbip->depth = ri->ri_depth;
410 		wsd_fbip->cmsize = CMAP_SIZE;
411 #undef fbt
412 		return (0);
413 
414 	case WSDISPLAYIO_GETCMAP:
415 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
416 
417 	case WSDISPLAYIO_PUTCMAP:
418 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
419 
420 	case WSDISPLAYIO_SVIDEO:
421 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
422 		if (sc->sc_blanked != turnoff) {
423 			sc->sc_blanked = turnoff;
424 #if 0	/* XXX later XXX */
425 	To turn off;
426 	- clear the MSB of TX control register; &= ~0x80,
427 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
428 #endif	/* XXX XXX XXX */
429 		}
430 		return (0);
431 
432 	case WSDISPLAYIO_GVIDEO:
433 		*(u_int *)data = sc->sc_blanked ?
434 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
435 		return (0);
436 
437 	case WSDISPLAYIO_GCURPOS:
438 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
439 		return (0);
440 
441 	case WSDISPLAYIO_SCURPOS:
442 		s = spltty();
443 		set_curpos(sc, (struct wsdisplay_curpos *)data);
444 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
445 		splx(s);
446 		return (0);
447 
448 	case WSDISPLAYIO_GCURMAX:
449 		((struct wsdisplay_curpos *)data)->x =
450 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
451 		return (0);
452 
453 	case WSDISPLAYIO_GCURSOR:
454 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
455 
456 	case WSDISPLAYIO_SCURSOR:
457 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
458 
459 	case WSDISPLAYIO_SMODE:
460 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
461 			s = spltty();
462 			tfb_cmap_init(sc);
463 			sc->sc_curenb = 0;
464 			sc->sc_blanked = 0;
465 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
466 			    WSDISPLAY_CMAP_DOLUT);
467 			splx(s);
468 		}
469 		return (0);
470 	}
471 	return (EPASSTHROUGH);
472 }
473 
474 static paddr_t
475 tfbmmap(void *v, void *vs, off_t offset, int prot)
476 {
477 	struct tfb_softc *sc = v;
478 
479 	if (offset >= TX_8BPP_SIZE || offset < 0) /* XXX 24bpp XXX */
480 		return (-1);
481 	return machine_btop(sc->sc_vaddr + TX_8BPP_OFFSET + offset);
482 }
483 
484 static int
485 tfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
486     int *curxp, int *curyp, long *attrp)
487 {
488 	struct tfb_softc *sc = v;
489 	struct rasops_info *ri = sc->sc_ri;
490 	long defattr;
491 
492 	if (sc->nscreens > 0)
493 		return (ENOMEM);
494 
495 	*cookiep = ri; /* one and only for now */
496 	*curxp = 0;
497 	*curyp = 0;
498 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
499 	*attrp = defattr;
500 	sc->nscreens++;
501 	return (0);
502 }
503 
504 static void
505 tfb_free_screen(void *v, void *cookie)
506 {
507 	struct tfb_softc *sc = v;
508 
509 	if (sc->sc_ri == &tfb_console_ri)
510 		panic("tfb_free_screen: console");
511 
512 	sc->nscreens--;
513 }
514 
515 static int
516 tfb_show_screen(void *v, void *cookie, int waitok,
517     void (*cb)(void *, int, int), void *cbarg)
518 {
519 
520 	return (0);
521 }
522 
523 /* EXPORT */ int
524 tfb_cnattach(tc_addr_t addr)
525 {
526 	struct rasops_info *ri;
527 	long defattr;
528 
529 	ri = &tfb_console_ri;
530 	ri->ri_hw = (void *)addr;
531 	tfb_common_init(ri);
532 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
533 	wsdisplay_cnattach(&tfb_stdscreen, ri, 0, 0, defattr);
534 	tfb_consaddr = addr;
535 	return (0);
536 }
537 
538 static int
539 tfbintr(void *arg)
540 {
541 	struct tfb_softc *sc = arg;
542 	char *base, *vdac, *curs;
543 	int v;
544 
545 	base = (void *)sc->sc_ri->ri_hw;
546 	*(u_int8_t *)(base + TX_CONTROL) &= ~0x40;
547 	if (sc->sc_changed == 0)
548 		goto done;
549 
550 	vdac = base + TX_BT463_OFFSET;
551 	curs = base + TX_BT431_OFFSET;
552 	v = sc->sc_changed;
553 	if (v & WSDISPLAY_CURSOR_DOCUR) {
554 		int onoff;
555 
556 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
557 		SELECT431(curs, BT431_REG_COMMAND);
558 		REGWRITE32(curs, bt_ctl, onoff);
559 	}
560 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
561 		int x, y;
562 		u_int32_t twin;
563 
564 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
565 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
566 
567 		x += sc->sc_cursor.cc_magic.x;
568 		y += sc->sc_cursor.cc_magic.y;
569 
570 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
571 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
572 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
573 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
574 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
575 	}
576 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
577 		u_int8_t *cp = sc->sc_cursor.cc_color;
578 
579 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
580 		REGWRITE32(vdac, bt_reg, cp[1]);
581 		REGWRITE32(vdac, bt_reg, cp[3]);
582 		REGWRITE32(vdac, bt_reg, cp[5]);
583 
584 		REGWRITE32(vdac, bt_reg, cp[0]);
585 		REGWRITE32(vdac, bt_reg, cp[2]);
586 		REGWRITE32(vdac, bt_reg, cp[4]);
587 
588 		REGWRITE32(vdac, bt_reg, cp[1]);
589 		REGWRITE32(vdac, bt_reg, cp[3]);
590 		REGWRITE32(vdac, bt_reg, cp[5]);
591 
592 		REGWRITE32(vdac, bt_reg, cp[1]);
593 		REGWRITE32(vdac, bt_reg, cp[3]);
594 		REGWRITE32(vdac, bt_reg, cp[5]);
595 	}
596 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
597 		u_int8_t *ip, *mp, img, msk;
598 		int bcnt;
599 
600 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
601 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
602 		bcnt = 0;
603 		SELECT431(curs, BT431_REG_CRAM_BASE);
604 
605 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
606 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
607 			/* pad right half 32 pixel when smaller than 33 */
608 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
609 				REGWRITE32(curs, bt_ram, 0);
610 			}
611 			else {
612 				int half;
613 				img = *ip++;
614 				msk = *mp++;
615 				img &= msk;	/* cookie off image */
616 				half = (flip[img] << 8) | flip[msk];
617 				REGWRITE32(curs, bt_ram, half);
618 			}
619 			bcnt += 2;
620 		}
621 		/* pad unoccupied scan lines */
622 		while (bcnt < CURSOR_MAX_SIZE * 16) {
623 			REGWRITE32(curs, bt_ram, 0);
624 			bcnt += 2;
625 		}
626 	}
627 	if (v & WSDISPLAY_CMAP_DOLUT) {
628 		struct hwcmap256 *cm = &sc->sc_cmap;
629 		int index;
630 
631 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
632 		for (index = 0; index < CMAP_SIZE; index++) {
633 			REGWRITE32(vdac, bt_cmap, cm->r[index]);
634 			REGWRITE32(vdac, bt_cmap, cm->g[index]);
635 			REGWRITE32(vdac, bt_cmap, cm->b[index]);
636 		}
637 	}
638 	sc->sc_changed = 0;
639 done:
640 	*(u_int8_t *)(base + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
641 	*(u_int8_t *)(base + TX_CONTROL) |= 0x40;
642 	return (1);
643 }
644 
645 static void
646 tfbhwinit(void *tfbbase)
647 {
648 	char *vdac, *curs;
649 	const u_int8_t *p;
650 	int i;
651 
652 	vdac = (char *)tfbbase + TX_BT463_OFFSET;
653 	curs = (char *)tfbbase + TX_BT431_OFFSET;
654 	SELECT463(vdac, BT463_IREG_COMMAND_0);
655 	REGWRITE32(vdac, bt_reg, 0x40);	/* CMD 0 */
656 	REGWRITE32(vdac, bt_reg, 0x46);	/* CMD 1 */
657 	REGWRITE32(vdac, bt_reg, 0xc0);	/* CMD 2 */
658 	REGWRITE32(vdac, bt_reg, 0);	/* !? 204 !? */
659 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  0:7  */
660 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  8:15 */
661 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 16:23 */
662 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 24:27 */
663 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  0:7  */
664 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  8:15 */
665 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 16:23 */
666 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 24:27 */
667 	REGWRITE32(vdac, bt_reg, 0x00);
668 
669 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
670   {
671 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
672 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
673 	};
674 
675 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
676 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
677 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
678 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
679 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
680 	}
681   }
682 #endif
683 
684 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
685 	p = rasops_cmap;
686 	for (i = 0; i < 256; i++, p += 3) {
687 		REGWRITE32(vdac, bt_cmap, p[0]);
688 		REGWRITE32(vdac, bt_cmap, p[1]);
689 		REGWRITE32(vdac, bt_cmap, p[2]);
690 	}
691 
692 	/* !? Eeeh !? */
693 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
694 	for (i = 0; i < 256; i++) {
695 		REGWRITE32(vdac, bt_cmap, i);
696 		REGWRITE32(vdac, bt_cmap, i);
697 		REGWRITE32(vdac, bt_cmap, i);
698 	}
699 
700 	SELECT431(curs, BT431_REG_COMMAND);
701 	REGWRITE32(curs, bt_ctl, 0x0404);
702 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
703 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
704 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
705 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
706 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
707 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
708 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
709 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
710 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
711 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
712 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
713 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
714 
715 	SELECT431(curs, BT431_REG_CRAM_BASE);
716 	for (i = 0; i < 512; i++) {
717 		REGWRITE32(curs, bt_ram, 0);
718 	}
719 }
720 
721 static int
722 get_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
723 {
724 	u_int index = p->index, count = p->count;
725 	int error;
726 
727 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
728 		return (EINVAL);
729 
730 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
731 	if (error)
732 		return error;
733 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
734 	if (error)
735 		return error;
736 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
737 	return error;
738 }
739 
740 static int
741 set_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
742 {
743 	struct hwcmap256 cmap;
744 	u_int index = p->index, count = p->count;
745 	int error, s;
746 
747 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
748 		return (EINVAL);
749 
750 	error = copyin(p->red, &cmap.r[index], count);
751 	if (error)
752 		return error;
753 	error = copyin(p->green, &cmap.g[index], count);
754 	if (error)
755 		return error;
756 	error = copyin(p->blue, &cmap.b[index], count);
757 	if (error)
758 		return error;
759 	s = spltty();
760 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
761 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
762 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
763 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
764 	splx(s);
765 	return (0);
766 }
767 
768 static int
769 set_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
770 {
771 #define	cc (&sc->sc_cursor)
772 	u_int v, index = 0, count = 0, icount = 0;
773 	uint8_t r[2], g[2], b[2], image[512], mask[512];
774 	int error, s;
775 
776 	v = p->which;
777 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
778 		index = p->cmap.index;
779 		count = p->cmap.count;
780 		if (index >= 2 || (index + count) > 2)
781 			return (EINVAL);
782 		error = copyin(p->cmap.red, &r[index], count);
783 		if (error)
784 			return error;
785 		error = copyin(p->cmap.green, &g[index], count);
786 		if (error)
787 			return error;
788 		error = copyin(p->cmap.blue, &b[index], count);
789 		if (error)
790 			return error;
791 	}
792 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
793 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
794 			return (EINVAL);
795 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
796 		error = copyin(p->image, image, icount);
797 		if (error)
798 			return error;
799 		error = copyin(p->mask, mask, icount);
800 		if (error)
801 			return error;
802 	}
803 
804 	s = spltty();
805 	if (v & WSDISPLAY_CURSOR_DOCUR)
806 		sc->sc_curenb = p->enable;
807 	if (v & WSDISPLAY_CURSOR_DOPOS)
808 		set_curpos(sc, &p->pos);
809 	if (v & WSDISPLAY_CURSOR_DOHOT)
810 		cc->cc_hot = p->hot;
811 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
812 		memcpy(&cc->cc_color[index], &r[index], count);
813 		memcpy(&cc->cc_color[index + 2], &g[index], count);
814 		memcpy(&cc->cc_color[index + 4], &b[index], count);
815 	}
816 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
817 		cc->cc_size = p->size;
818 		memset(cc->cc_image, 0, sizeof cc->cc_image);
819 		memcpy(cc->cc_image, image, icount);
820 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
821 		memcpy(cc->cc_mask, mask, icount);
822 	}
823 	sc->sc_changed |= v;
824 	splx(s);
825 
826 	return (0);
827 #undef cc
828 }
829 
830 static int
831 get_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
832 {
833 	return (EPASSTHROUGH); /* XXX */
834 }
835 
836 static void
837 set_curpos(struct tfb_softc *sc, struct wsdisplay_curpos *curpos)
838 {
839 	struct rasops_info *ri = sc->sc_ri;
840 	int x = curpos->x, y = curpos->y;
841 
842 	if (y < 0)
843 		y = 0;
844 	else if (y > ri->ri_height)
845 		y = ri->ri_height;
846 	if (x < 0)
847 		x = 0;
848 	else if (x > ri->ri_width)
849 		x = ri->ri_width;
850 	sc->sc_cursor.cc_pos.x = x;
851 	sc->sc_cursor.cc_pos.y = y;
852 }
853