Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.57.2.1
      1 /* $NetBSD: tfb.c,v 1.57.2.1 2010/08/17 06:46:41 uebayasi 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.57.2.1 2010/08/17 06:46:41 uebayasi 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