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