Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.63.10.1
      1 /* $NetBSD: tfb.c,v 1.63.10.1 2021/03/21 21:09:15 thorpej 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.10.1 2021/03/21 21:09:15 thorpej 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, CFARG_EOL);
    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