Home | History | Annotate | Line # | Download | only in sbus
tcx.c revision 1.32
      1 /*	$NetBSD: tcx.c,v 1.32 2009/08/06 18:26:03 macallan Exp $ */
      2 
      3 /*
      4  *  Copyright (c) 1996,1998 The NetBSD Foundation, Inc.
      5  *  All rights reserved.
      6  *
      7  *  This code is derived from software contributed to The NetBSD Foundation
      8  *  by Paul Kranenburg.
      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 /*
     33  * color display (TCX) driver.
     34  *
     35  * Does not handle interrupts, even though they can occur.
     36  *
     37  * XXX should defer colormap updates to vertical retrace interrupts
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: tcx.c,v 1.32 2009/08/06 18:26:03 macallan Exp $");
     42 
     43 /*
     44  * define for cg8 emulation on S24 (24-bit version of tcx) for the SS5;
     45  * it is bypassed on the 8-bit version (onboard framebuffer for SS4)
     46  */
     47 #undef TCX_CG8
     48 
     49 #include <sys/param.h>
     50 #include <sys/systm.h>
     51 #include <sys/buf.h>
     52 #include <sys/device.h>
     53 #include <sys/ioctl.h>
     54 #include <sys/malloc.h>
     55 #include <sys/mman.h>
     56 #include <sys/tty.h>
     57 #include <sys/conf.h>
     58 
     59 #ifdef DEBUG
     60 #include <sys/proc.h>
     61 #include <sys/syslog.h>
     62 #endif
     63 
     64 #include <sys/bus.h>
     65 #include <machine/autoconf.h>
     66 
     67 #include <dev/sun/fbio.h>
     68 #include <dev/sun/fbvar.h>
     69 #include <dev/sun/btreg.h>
     70 #include <dev/sun/btvar.h>
     71 
     72 #include <dev/sbus/sbusvar.h>
     73 #include <dev/sbus/tcxreg.h>
     74 
     75 #include <dev/wscons/wsdisplayvar.h>
     76 #include <dev/wscons/wsconsio.h>
     77 #include <dev/wsfont/wsfont.h>
     78 #include <dev/rasops/rasops.h>
     79 
     80 #include <dev/wscons/wsdisplay_vconsvar.h>
     81 
     82 #include "opt_wsemul.h"
     83 
     84 /* per-display variables */
     85 struct tcx_softc {
     86 	struct device	sc_dev;		/* base device */
     87 	struct sbusdev	sc_sd;		/* sbus device */
     88 	struct fbdevice	sc_fb;		/* frame buffer device */
     89 	bus_space_tag_t	sc_bustag;
     90 	struct openprom_addr sc_physadr[TCX_NREG];/* phys addr of h/w */
     91 
     92 	bus_space_handle_t sc_bt;	/* Brooktree registers */
     93 	bus_space_handle_t sc_thc;	/* THC registers */
     94 	uint8_t *sc_fbaddr;		/* framebuffer */
     95 	uint64_t *sc_rblit;		/* blitspace */
     96 	uint64_t *sc_rstip;		/* stipple space */
     97 
     98 	short	sc_8bit;		/* true if 8-bit hardware */
     99 	short	sc_blanked;		/* true if blanked */
    100 	u_char	sc_cmap_red[256];
    101 	u_char	sc_cmap_green[256];
    102 	u_char	sc_cmap_blue[256];
    103 	int 	sc_mode, sc_bg;
    104 	struct vcons_data vd;
    105 };
    106 
    107 static struct vcons_screen tcx_console_screen;
    108 
    109 extern const u_char rasops_cmap[768];
    110 
    111 struct wsscreen_descr tcx_defscreendesc = {
    112 	"default",
    113 	0, 0,
    114 	NULL,
    115 	8, 16,
    116 	WSSCREEN_WSCOLORS,
    117 };
    118 
    119 const struct wsscreen_descr *_tcx_scrlist[] = {
    120 	&tcx_defscreendesc,
    121 	/* XXX other formats, graphics screen? */
    122 };
    123 
    124 struct wsscreen_list tcx_screenlist = {
    125 	sizeof(_tcx_scrlist) / sizeof(struct wsscreen_descr *),
    126 	_tcx_scrlist
    127 };
    128 
    129 /*
    130  * The S24 provides the framebuffer RAM mapped in three ways:
    131  * 26 bits per pixel, in 32-bit words; the low-order 24 bits are
    132  * blue, green, and red values, and the other two bits select the
    133  * display modes, per pixel);
    134  * 24 bits per pixel, in 32-bit words; the high-order byte reads as
    135  * zero, and is ignored on writes (so the mode bits cannot be altered);
    136  * 8 bits per pixel, unpadded; writes to this space do not modify the
    137  * other 18 bits.
    138  */
    139 #define TCX_CTL_8_MAPPED	0x00000000	/* 8 bits, uses color map */
    140 #define TCX_CTL_24_MAPPED	0x01000000	/* 24 bits, uses color map */
    141 #define TCX_CTL_24_LEVEL	0x03000000	/* 24 bits, ignores color map */
    142 #define TCX_CTL_PIXELMASK	0x00FFFFFF	/* mask for index/level */
    143 
    144 /* autoconfiguration driver */
    145 static void	tcxattach(device_t, device_t, void *);
    146 static int	tcxmatch(device_t, cfdata_t, void *);
    147 static void	tcx_unblank(device_t);
    148 
    149 CFATTACH_DECL(tcx, sizeof(struct tcx_softc),
    150     tcxmatch, tcxattach, NULL, NULL);
    151 
    152 extern struct cfdriver tcx_cd;
    153 
    154 dev_type_open(tcxopen);
    155 dev_type_close(tcxclose);
    156 dev_type_ioctl(tcxioctl);
    157 dev_type_mmap(tcxmmap);
    158 
    159 const struct cdevsw tcx_cdevsw = {
    160 	tcxopen, tcxclose, noread, nowrite, tcxioctl,
    161 	nostop, notty, nopoll, tcxmmap, nokqfilter,
    162 };
    163 
    164 /* frame buffer generic driver */
    165 static struct fbdriver tcx_fbdriver = {
    166 	tcx_unblank, tcxopen, tcxclose, tcxioctl, nopoll, tcxmmap,
    167 	nokqfilter
    168 };
    169 
    170 static void tcx_reset(struct tcx_softc *);
    171 static void tcx_loadcmap(struct tcx_softc *, int, int);
    172 
    173 static int	tcx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    174 static paddr_t	tcx_mmap(void *, void *, off_t, int);
    175 
    176 static void	tcx_init_screen(void *, struct vcons_screen *, int, long *);
    177 static void	tcx_clearscreen(struct tcx_softc *);
    178 static void	tcx_copyrows(void *, int, int, int);
    179 static void	tcx_eraserows(void *, int, int, long);
    180 static void	tcx_putchar(void *, int, int, u_int, long);
    181 
    182 struct wsdisplay_accessops tcx_accessops = {
    183 	tcx_ioctl,
    184 	tcx_mmap,
    185 	NULL,	/* vcons_alloc_screen */
    186 	NULL,	/* vcons_free_screen */
    187 	NULL,	/* vcons_show_screen */
    188 	NULL,	/* load_font */
    189 	NULL,	/* polls */
    190 	NULL,	/* scroll */
    191 };
    192 
    193 #define OBPNAME	"SUNW,tcx"
    194 
    195 #ifdef TCX_CG8
    196 /*
    197  * For CG8 emulation, we map the 32-bit-deep framebuffer at an offset of
    198  * 256K; the cg8 space begins with a mono overlay plane and an overlay
    199  * enable plane (128K bytes each, 1 bit per pixel), immediately followed
    200  * by the color planes, 32 bits per pixel.  We also map just the 32-bit
    201  * framebuffer at 0x04000000 (TCX_USER_RAM_COMPAT), for compatibility
    202  * with the cg8 driver.
    203  */
    204 #define	TCX_CG8OVERLAY	(256 * 1024)
    205 #define	TCX_SIZE_DFB32	(1152 * 900 * 4) /* max size of the framebuffer */
    206 #endif
    207 
    208 /*
    209  * Match a tcx.
    210  */
    211 int
    212 tcxmatch(device_t parent, cfdata_t cf, void *aux)
    213 {
    214 	struct sbus_attach_args *sa = aux;
    215 
    216 	return (strcmp(sa->sa_name, OBPNAME) == 0);
    217 }
    218 
    219 /*
    220  * Attach a display.
    221  */
    222 void
    223 tcxattach(device_t parent, device_t self, void *args)
    224 {
    225 	struct tcx_softc *sc = device_private(self);
    226 	struct sbus_attach_args *sa = args;
    227 	struct wsemuldisplaydev_attach_args aa;
    228 	struct rasops_info *ri;
    229 	unsigned long defattr;
    230 	int node, ramsize;
    231 	struct fbdevice *fb = &sc->sc_fb;
    232 	bus_space_handle_t bh;
    233 	int isconsole, i, j;
    234 	uint32_t confreg;
    235 
    236 	sc->sc_bustag = sa->sa_bustag;
    237 	node = sa->sa_node;
    238 
    239 	fb->fb_driver = &tcx_fbdriver;
    240 	fb->fb_device = &sc->sc_dev;
    241 	/* Mask out invalid flags from the user. */
    242 	fb->fb_flags = device_cfdata(&sc->sc_dev)->cf_flags & FB_USERMASK;
    243 	/*
    244 	 * The onboard framebuffer on the SS4 supports only 8-bit mode;
    245 	 * it can be distinguished from the S24 card for the SS5 by the
    246 	 * presence of the "tcx-8-bit" attribute on the SS4 version.
    247 	 */
    248 	sc->sc_8bit = node_has_property(node, "tcx-8-bit");
    249 	fb->fb_type.fb_depth = 8;
    250 	fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node);
    251 
    252 	if (sc->sc_8bit) {
    253 		printf(" {8bit only TCX)");
    254 		ramsize = 1024 * 1024;
    255 		/* XXX - fix THC and TEC offsets */
    256 		sc->sc_physadr[TCX_REG_TEC].oa_base += 0x1000;
    257 		sc->sc_physadr[TCX_REG_THC].oa_base += 0x1000;
    258 	} else {
    259 		printf(" (S24)\n");
    260 		ramsize = 4 * 1024 * 1024;
    261 	}
    262 
    263 	fb->fb_type.fb_cmsize = 256;
    264 	fb->fb_type.fb_size = ramsize;
    265 	printf(": %s, %d x %d", OBPNAME,
    266 		fb->fb_type.fb_width,
    267 		fb->fb_type.fb_height);
    268 
    269 	fb->fb_type.fb_type = FBTYPE_SUNTCX;
    270 
    271 
    272 	if (sa->sa_nreg != TCX_NREG) {
    273 		printf("%s: only %d register sets\n",
    274 			device_xname(self), sa->sa_nreg);
    275 		return;
    276 	}
    277 	memcpy(sc->sc_physadr, sa->sa_reg,
    278 	      sa->sa_nreg * sizeof(struct openprom_addr));
    279 
    280 	/* Map the register banks we care about */
    281 	if (sbus_bus_map(sa->sa_bustag,
    282 			 sc->sc_physadr[TCX_REG_THC].oa_space,
    283 			 sc->sc_physadr[TCX_REG_THC].oa_base,
    284 			 0x1000,
    285 			 BUS_SPACE_MAP_LINEAR, &sc->sc_thc) != 0) {
    286 		printf("tcxattach: cannot map thc registers\n");
    287 		return;
    288 	}
    289 
    290 	if (sbus_bus_map(sa->sa_bustag,
    291 			 sc->sc_physadr[TCX_REG_CMAP].oa_space,
    292 			 sc->sc_physadr[TCX_REG_CMAP].oa_base,
    293 			 0x1000,
    294 			 BUS_SPACE_MAP_LINEAR, &sc->sc_bt) != 0) {
    295 		printf("tcxattach: cannot map bt registers\n");
    296 		return;
    297 	}
    298 
    299 	/* map the 8bit dumb FB for the console */
    300 	if (sbus_bus_map(sa->sa_bustag,
    301 		 sc->sc_physadr[TCX_REG_DFB8].oa_space,
    302 		 sc->sc_physadr[TCX_REG_DFB8].oa_base,
    303 			 1024 * 1024,
    304 			 BUS_SPACE_MAP_LINEAR,
    305 			 &bh) != 0) {
    306 		printf("tcxattach: cannot map framebuffer\n");
    307 		return;
    308 	}
    309 	sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh);
    310 
    311 	/* RBLIT space */
    312 	if (sbus_bus_map(sa->sa_bustag,
    313 		 sc->sc_physadr[TCX_REG_RBLIT].oa_space,
    314 		 sc->sc_physadr[TCX_REG_RBLIT].oa_base,
    315 			 8 * 1024 * 1024,
    316 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    317 			 &bh) != 0) {
    318 		printf("tcxattach: cannot map RBLIT space\n");
    319 		return;
    320 	}
    321 	sc->sc_rblit = bus_space_vaddr(sa->sa_bustag, bh);
    322 
    323 	/* RSTIP space */
    324 	if (sbus_bus_map(sa->sa_bustag,
    325 		 sc->sc_physadr[TCX_REG_RSTIP].oa_space,
    326 		 sc->sc_physadr[TCX_REG_RSTIP].oa_base,
    327 			 8 * 1024 * 1024,
    328 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    329 			 &bh) != 0) {
    330 		printf("tcxattach: cannot map RSTIP space\n");
    331 		return;
    332 	}
    333 	sc->sc_rstip = bus_space_vaddr(sa->sa_bustag, bh);
    334 
    335 	isconsole = fb_is_console(node);
    336 
    337 	confreg = bus_space_read_4(sa->sa_bustag, sc->sc_thc, THC_CONFIG);
    338 	printf(", id %d, rev %d, sense %d",
    339 		(confreg & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT,
    340 		(confreg & THC_CFG_REV) >> THC_CFG_REV_SHIFT,
    341 		(confreg & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT
    342 	);
    343 
    344 	/* reset cursor & frame buffer controls */
    345 	tcx_reset(sc);
    346 
    347 	/* Initialize the default color map. */
    348 	j = 0;
    349 	for (i = 0; i < 256; i++) {
    350 
    351 		sc->sc_cmap_red[i] = rasops_cmap[j];
    352 		sc->sc_cmap_green[i] = rasops_cmap[j + 1];
    353 		sc->sc_cmap_blue[i] = rasops_cmap[j + 2];
    354 		j += 3;
    355 	}
    356 	tcx_loadcmap(sc, 0, 256);
    357 
    358 	/* enable video */
    359 	confreg = bus_space_read_4(sa->sa_bustag, sc->sc_thc, THC_MISC);
    360 	confreg |= THC_MISC_VIDEN;
    361 	bus_space_write_4(sa->sa_bustag, sc->sc_thc, THC_MISC, confreg);
    362 
    363 	if (isconsole) {
    364 		printf(" (console)\n");
    365 	} else
    366 		printf("\n");
    367 
    368 	bus_space_write_4(sa->sa_bustag, sc->sc_bt, DAC_ADDRESS, 0);
    369 	printf("DAC ID: %02x %02x\n",
    370 	    bus_space_read_1(sa->sa_bustag, sc->sc_bt, DAC_CONTROL_1),
    371 	    bus_space_read_1(sa->sa_bustag, sc->sc_bt, DAC_CONTROL_1));
    372 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
    373 	fb_attach(&sc->sc_fb, isconsole);
    374 
    375 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    376 	wsfont_init();
    377 
    378 	vcons_init(&sc->vd, sc, &tcx_defscreendesc, &tcx_accessops);
    379 	sc->vd.init_screen = tcx_init_screen;
    380 
    381 	vcons_init_screen(&sc->vd, &tcx_console_screen, 1, &defattr);
    382 	tcx_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    383 
    384 	sc->sc_bg = (defattr >> 16) & 0xff;
    385 	tcx_clearscreen(sc);
    386 
    387 	ri = &tcx_console_screen.scr_ri;
    388 
    389 	tcx_defscreendesc.nrows = ri->ri_rows;
    390 	tcx_defscreendesc.ncols = ri->ri_cols;
    391 	tcx_defscreendesc.textops = &ri->ri_ops;
    392 	tcx_defscreendesc.capabilities = ri->ri_caps;
    393 
    394 	if(isconsole) {
    395 		wsdisplay_cnattach(&tcx_defscreendesc, ri, 0, 0, defattr);
    396 	}
    397 
    398 	aa.console = isconsole;
    399 	aa.scrdata = &tcx_screenlist;
    400 	aa.accessops = &tcx_accessops;
    401 	aa.accesscookie = &sc->vd;
    402 
    403 	config_found(self, &aa, wsemuldisplaydevprint);
    404 	/*
    405 	 * we need to do this again - something overwrites a handful
    406 	 * palette registers and we end up with white in reg. 0
    407 	 */
    408 	tcx_loadcmap(sc, 0, 256);
    409 }
    410 
    411 #ifdef TCX_CG8
    412 /*
    413  * keep track of the number of opens, so we can switch to 24-bit mode
    414  * when the device is first opened, and return to 8-bit mode on the
    415  * last close.  (stolen from cgfourteen driver...)  There can only be
    416  * one TCX per system, so we only need one flag.
    417  */
    418 static int tcx_opens = 0;
    419 #endif
    420 
    421 int
    422 tcxopen(dev_t dev, int flags, int mode, struct lwp *l)
    423 {
    424 #ifdef TCX_CG8
    425 	int unit = minor(dev);
    426 	struct tcx_softc *sc;
    427 	int i, s, oldopens;
    428 	volatile ulong *cptr;
    429 	struct fbdevice *fb;
    430 
    431 	sc = device_lookup_private(&tcx_cd, unit);
    432 	if (!sc)
    433 		return (ENXIO);
    434 	if (!sc->sc_8bit) {
    435 		s = splhigh();
    436 		oldopens = tcx_opens++;
    437 		splx(s);
    438 		if (oldopens == 0) {
    439 			/*
    440 			 * rewrite the control planes to select 24-bit mode
    441 			 * and clear the screen
    442 			 */
    443 			fb = &sc->sc_fb;
    444 			i = fb->fb_type.fb_height * fb->fb_type.fb_width;
    445 			cptr = sc->sc_cplane;
    446 			while (--i >= 0)
    447 				*cptr++ = TCX_CTL_24_LEVEL;
    448 		}
    449 	}
    450 #endif
    451 	return (0);
    452 }
    453 
    454 int
    455 tcxclose(dev_t dev, int flags, int mode, struct lwp *l)
    456 {
    457 	struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev));
    458 #ifdef TCX_CG8
    459 	int i, s, opens;
    460 	volatile ulong *cptr;
    461 	struct fbdevice *fb;
    462 #endif
    463 
    464 	tcx_reset(sc);
    465 #ifdef TCX_CG8
    466 	if (!sc->sc_8bit) {
    467 		s = splhigh();
    468 		opens = --tcx_opens;
    469 		if (tcx_opens <= 0)
    470 			opens = tcx_opens = 0;
    471 		splx(s);
    472 		if (opens == 0) {
    473 			/*
    474 			 * rewrite the control planes to select 8-bit mode,
    475 			 * preserving the contents of the screen.
    476 			 * (or we could just bzero the whole thing...)
    477 			 */
    478 			fb = &sc->sc_fb;
    479 			i = fb->fb_type.fb_height * fb->fb_type.fb_width;
    480 			cptr = sc->sc_cplane;
    481 			while (--i >= 0)
    482 				*cptr++ &= TCX_CTL_PIXELMASK;
    483 		}
    484 	}
    485 #endif
    486 	return (0);
    487 }
    488 
    489 int
    490 tcxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
    491 {
    492 	struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev));
    493 	//int error;
    494 
    495 	switch (cmd) {
    496 
    497 	case FBIOGTYPE:
    498 		*(struct fbtype *)data = sc->sc_fb.fb_type;
    499 		break;
    500 
    501 	case FBIOGATTR:
    502 #define fba ((struct fbgattr *)data)
    503 		fba->real_type = sc->sc_fb.fb_type.fb_type;
    504 		fba->owner = 0;		/* XXX ??? */
    505 		fba->fbtype = sc->sc_fb.fb_type;
    506 		fba->sattr.flags = 0;
    507 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
    508 		fba->sattr.dev_specific[0] = -1;
    509 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
    510 		fba->emu_types[1] = FBTYPE_SUN3COLOR;
    511 		fba->emu_types[2] = -1;
    512 #undef fba
    513 		break;
    514 #if 0
    515 	case FBIOGETCMAP:
    516 #define	p ((struct fbcmap *)data)
    517 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
    518 
    519 	case FBIOPUTCMAP:
    520 		/* copy to software map */
    521 #ifdef TCX_CG8
    522 		if (!sc->sc_8bit) {
    523 			/*
    524 			 * cg8 has extra bits in high-order byte of the index
    525 			 * that bt_putcmap doesn't recognize
    526 			 */
    527 			p->index &= 0xffffff;
    528 		}
    529 #endif
    530 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
    531 		if (error)
    532 			return (error);
    533 		/* now blast them into the chip */
    534 		/* XXX should use retrace interrupt */
    535 		tcx_loadcmap(sc, p->index, p->count);
    536 #undef p
    537 		break;
    538 #endif
    539 	case FBIOGVIDEO:
    540 		*(int *)data = sc->sc_blanked;
    541 		break;
    542 
    543 	case FBIOSVIDEO:
    544 		if (*(int *)data)
    545 			tcx_unblank(&sc->sc_dev);
    546 		else if (!sc->sc_blanked) {
    547 			sc->sc_blanked = 1;
    548 			//sc->sc_thc->thc_hcmisc &= ~THC_MISC_VIDEN;
    549 			/* Put monitor in `power-saving mode' */
    550 			//sc->sc_thc->thc_hcmisc |= THC_MISC_VSYNC_DISABLE;
    551 			//sc->sc_thc->thc_hcmisc |= THC_MISC_HSYNC_DISABLE;
    552 		}
    553 		break;
    554 
    555 	default:
    556 #ifdef DEBUG
    557 		log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd,
    558 		    l->l_proc->p_comm, l->l_proc->p_pid);
    559 #endif
    560 		return (ENOTTY);
    561 	}
    562 	return (0);
    563 }
    564 
    565 /*
    566  * Clean up hardware state (e.g., after bootup or after X crashes).
    567  */
    568 static void
    569 tcx_reset(struct tcx_softc *sc)
    570 {
    571 
    572 	/* Enable cursor in Brooktree DAC. */
    573 	/* TODO: bus_spacify */
    574 //	bt->bt_addr = 0x06 << 24;
    575 //	bt->bt_ctrl |= 0x03 << 24;
    576 }
    577 
    578 /*
    579  * Load a subset of the current (new) colormap into the color DAC.
    580  */
    581 static void
    582 tcx_loadcmap(struct tcx_softc *sc, int start, int ncolors)
    583 {
    584 	int i;
    585 
    586 	for (i = 0; i < ncolors; i++) {
    587 		bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_ADDRESS,
    588 		    (start + i) << 24);
    589 		bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT,
    590 		    sc->sc_cmap_red[i + start] << 24);
    591 		bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT,
    592 		    sc->sc_cmap_green[i + start] << 24);
    593 		bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_FB_LUT,
    594 		    sc->sc_cmap_blue[i + start] << 24);
    595 	}
    596 	bus_space_write_4(sc->sc_bustag, sc->sc_bt, DAC_ADDRESS, 0);
    597 }
    598 
    599 static void
    600 tcx_unblank(device_t dev)
    601 {
    602 	struct tcx_softc *sc = device_private(dev);
    603 
    604 	if (sc->sc_blanked) {
    605 
    606 		sc->sc_blanked = 0;
    607 		//sc->sc_thc->thc_hcmisc &= ~THC_MISC_VSYNC_DISABLE;
    608 		//sc->sc_thc->thc_hcmisc &= ~THC_MISC_HSYNC_DISABLE;
    609 		//sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN;
    610 	}
    611 }
    612 
    613 /*
    614  * Base addresses at which users can mmap() the various pieces of a tcx.
    615  */
    616 #define	TCX_USER_RAM	0x00000000
    617 #define	TCX_USER_RAM24	0x01000000
    618 #define	TCX_USER_RAM_COMPAT	0x04000000	/* cg3 emulation */
    619 #define	TCX_USER_STIP	0x10000000
    620 #define	TCX_USER_BLIT	0x20000000
    621 #define	TCX_USER_RDFB32	0x28000000
    622 #define	TCX_USER_RSTIP	0x30000000
    623 #define	TCX_USER_RBLIT	0x38000000
    624 #define	TCX_USER_TEC	0x70001000
    625 #define	TCX_USER_BTREGS	0x70002000
    626 #define	TCX_USER_THC	0x70004000
    627 #define	TCX_USER_DHC	0x70008000
    628 #define	TCX_USER_ALT	0x7000a000
    629 #define	TCX_USER_UART	0x7000c000
    630 #define	TCX_USER_VRT	0x7000e000
    631 #define	TCX_USER_ROM	0x70010000
    632 
    633 struct mmo {
    634 	u_int	mo_uaddr;	/* user (virtual) address */
    635 	u_int	mo_size;	/* size, or 0 for video ram size */
    636 	u_int	mo_bank;	/* register bank number */
    637 };
    638 
    639 /*
    640  * Return the address that would map the given device at the given
    641  * offset, allowing for the given protection, or return -1 for error.
    642  *
    643  * XXX	needs testing against `demanding' applications (e.g., aviator)
    644  */
    645 paddr_t
    646 tcxmmap(dev_t dev, off_t off, int prot)
    647 {
    648 	struct tcx_softc *sc = device_lookup_private(&tcx_cd, minor(dev));
    649 	struct openprom_addr *rr = sc->sc_physadr;
    650 	struct mmo *mo, *mo_end;
    651 	u_int u, sz;
    652 	static struct mmo mmo[] = {
    653 		{ TCX_USER_RAM, 0, TCX_REG_DFB8 },
    654 		{ TCX_USER_RAM24, 0, TCX_REG_DFB24 },
    655 		{ TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 },
    656 
    657 		{ TCX_USER_STIP, 1, TCX_REG_STIP },
    658 		{ TCX_USER_BLIT, 1, TCX_REG_BLIT },
    659 		{ TCX_USER_RDFB32, 0, TCX_REG_RDFB32 },
    660 		{ TCX_USER_RSTIP, 1, TCX_REG_RSTIP },
    661 		{ TCX_USER_RBLIT, 1, TCX_REG_RBLIT },
    662 		{ TCX_USER_TEC, 1, TCX_REG_TEC },
    663 		{ TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP },
    664 		{ TCX_USER_THC, 0x1000, TCX_REG_THC },
    665 		{ TCX_USER_DHC, 1, TCX_REG_DHC },
    666 		{ TCX_USER_ALT, 1, TCX_REG_ALT },
    667 		{ TCX_USER_ROM, 65536, TCX_REG_ROM },
    668 	};
    669 #define NMMO (sizeof mmo / sizeof *mmo)
    670 #ifdef TCX_CG8
    671 	/*
    672 	 * alternate mapping for CG8 emulation:
    673 	 * map part of the 8-bit-deep framebuffer into the cg8 overlay
    674 	 * space, just so there's something there, and map the 32-bit-deep
    675 	 * framebuffer where cg8 users expect to find it.
    676 	 */
    677 	static struct mmo mmo_cg8[] = {
    678 		{ TCX_USER_RAM, TCX_CG8OVERLAY, TCX_REG_DFB8 },
    679 		{ TCX_CG8OVERLAY, TCX_SIZE_DFB32, TCX_REG_DFB24 },
    680 		{ TCX_USER_RAM_COMPAT, TCX_SIZE_DFB32, TCX_REG_DFB24 }
    681 	};
    682 #define NMMO_CG8 (sizeof mmo_cg8 / sizeof *mmo_cg8)
    683 #endif
    684 
    685 	if (off & PGOFSET)
    686 		panic("tcxmmap");
    687 
    688 	/*
    689 	 * Entries with size 0 map video RAM (i.e., the size in fb data).
    690 	 * Entries that map 32-bit deep regions are adjusted for their
    691 	 * depth (fb_size gives the size of the 8-bit-deep region).
    692 	 *
    693 	 * Since we work in pages, the fact that the map offset table's
    694 	 * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
    695 	 * one byte is as good as one page.
    696 	 */
    697 #ifdef TCX_CG8
    698 	if (sc->sc_8bit) {
    699 		mo = mmo;
    700 		mo_end = &mmo[NMMO];
    701 	} else {
    702 		mo = mmo_cg8;
    703 		mo_end = &mmo_cg8[NMMO_CG8];
    704 	}
    705 #else
    706 	mo = mmo;
    707 	mo_end = &mmo[NMMO];
    708 #endif
    709 	for (; mo < mo_end; mo++) {
    710 		if ((u_int)off < mo->mo_uaddr)
    711 			continue;
    712 		u = off - mo->mo_uaddr;
    713 		sz = mo->mo_size;
    714 		if (sz == 0) {
    715 			sz = sc->sc_fb.fb_type.fb_size;
    716 			/*
    717 			 * check for the 32-bit-deep regions and adjust
    718 			 * accordingly
    719 			 */
    720 			if (mo->mo_uaddr == TCX_USER_RAM24 ||
    721 			    mo->mo_uaddr == TCX_USER_RDFB32) {
    722 				if (sc->sc_8bit) {
    723 					/*
    724 					 * not present on 8-bit hardware
    725 					 */
    726 					continue;
    727 				}
    728 				sz *= 4;
    729 			}
    730 		}
    731 		if (u < sz) {
    732 			return (bus_space_mmap(sc->sc_bustag,
    733 				BUS_ADDR(rr[mo->mo_bank].oa_space,
    734 					 rr[mo->mo_bank].oa_base),
    735 				u,
    736 				prot,
    737 				BUS_SPACE_MAP_LINEAR));
    738 		}
    739 	}
    740 	return (-1);
    741 }
    742 
    743 int
    744 tcx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    745 	struct lwp *l)
    746 {
    747 	struct vcons_data *vd = v;
    748 	struct tcx_softc *sc = vd->cookie;
    749 	struct wsdisplay_fbinfo *wdf;
    750 	struct vcons_screen *ms = vd->active;
    751 
    752 	switch (cmd) {
    753 		case WSDISPLAYIO_GTYPE:
    754 			*(u_int *)data = WSDISPLAY_TYPE_SUNTCX;
    755 			return 0;
    756 
    757 #if 0
    758 		case FBIOGVIDEO:
    759 		case WSDISPLAYIO_GVIDEO:
    760 			*(int *)data = tcx_get_video(sc);
    761 			return 0;
    762 
    763 		case WSDISPLAYIO_SVIDEO:
    764 		case FBIOSVIDEO:
    765 			tcx_set_video(sc, *(int *)data);
    766 			return 0;
    767 #endif
    768 		case WSDISPLAYIO_GINFO:
    769 			wdf = (void *)data;
    770 			wdf->height = ms->scr_ri.ri_height;
    771 			wdf->width = ms->scr_ri.ri_width;
    772 			wdf->depth = ms->scr_ri.ri_depth;
    773 			wdf->cmsize = 256;
    774 			return 0;
    775 #if 0
    776 		case WSDISPLAYIO_GETCMAP:
    777 			return tcx_getcmap(sc, (struct wsdisplay_cmap *)data);
    778 
    779 		case WSDISPLAYIO_PUTCMAP:
    780 			return tcx_putcmap(sc, (struct wsdisplay_cmap *)data);
    781 #endif
    782 		case WSDISPLAYIO_SMODE:
    783 			{
    784 				int new_mode = *(int*)data;
    785 				if (new_mode != sc->sc_mode)
    786 				{
    787 					sc->sc_mode = new_mode;
    788 					if (new_mode == WSDISPLAYIO_MODE_EMUL)
    789 					{
    790 #if 0
    791 						tcxloadcmap(sc, 0, 256);
    792 						tcx_clearscreen(sc);
    793 #endif
    794 						vcons_redraw_screen(ms);
    795 					}
    796 				}
    797 			}
    798 	}
    799 	return EPASSTHROUGH;
    800 }
    801 
    802 static paddr_t
    803 tcx_mmap(void *v, void *vs, off_t offset, int prot)
    804 {
    805 #if 0
    806 	struct vcons_data *vd = v;
    807 	struct tcx_softc *sc = vd->cookie;
    808 	paddr_t pa;
    809 
    810 	/* 'regular' framebuffer mmap()ing */
    811 	if (offset < sc->sc_fb_psize) {
    812 		pa = bus_space_mmap(sc->sc_bustag, sc->sc_fb_paddr + offset, 0,
    813 		    prot, BUS_SPACE_MAP_LINEAR);
    814 		return pa;
    815 	}
    816 
    817 	if ((offset >= sc->sc_fb_paddr) && (offset < (sc->sc_fb_paddr +
    818 	    sc->sc_fb_psize))) {
    819 		pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot,
    820 		    BUS_SPACE_MAP_LINEAR);
    821 		return pa;
    822 	}
    823 
    824 	if ((offset >= sc->sc_ctl_paddr) && (offset < (sc->sc_ctl_paddr +
    825 	    sc->sc_ctl_psize))) {
    826 		pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot,
    827 		    BUS_SPACE_MAP_LINEAR);
    828 		return pa;
    829 	}
    830 #endif
    831 	return -1;
    832 }
    833 
    834 static void
    835 tcx_init_screen(void *cookie, struct vcons_screen *scr,
    836     int existing, long *defattr)
    837 {
    838 	struct tcx_softc *sc = cookie;
    839 	struct rasops_info *ri = &scr->scr_ri;
    840 
    841 	ri->ri_depth = 8;
    842 	ri->ri_width = sc->sc_fb.fb_type.fb_width;
    843 	ri->ri_height = sc->sc_fb.fb_type.fb_height;
    844 	ri->ri_stride = sc->sc_fb.fb_linebytes;
    845 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
    846 
    847 	ri->ri_bits = sc->sc_fbaddr;
    848 
    849 	rasops_init(ri, ri->ri_height/8, ri->ri_width/8);
    850 	ri->ri_caps = WSSCREEN_WSCOLORS;
    851 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
    852 		    ri->ri_width / ri->ri_font->fontwidth);
    853 
    854 	/* enable acceleration */
    855 	ri->ri_ops.copyrows  = tcx_copyrows;
    856 	ri->ri_ops.eraserows = tcx_eraserows;
    857 	ri->ri_ops.putchar   = tcx_putchar;
    858 #if 0
    859 	ri->ri_ops.cursor    = tcx_cursor;
    860 	ri->ri_ops.copycols  = tcx_copycols;
    861 	ri->ri_ops.erasecols = tcx_erasecols;
    862 #endif
    863 }
    864 
    865 static void
    866 tcx_clearscreen(struct tcx_softc *sc)
    867 {
    868 	uint64_t bg = ((uint64_t)sc->sc_bg << 32) | 0xffffffffLL;
    869 	int i;
    870 
    871 	for (i = 0; i < 1024 * 1024; i += 32)
    872 		sc->sc_rstip[i] = bg;
    873 }
    874 
    875 static void
    876 tcx_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
    877 {
    878 	struct rasops_info *ri = cookie;
    879 	struct vcons_screen *scr = ri->ri_hw;
    880 	struct tcx_softc *sc = scr->scr_cookie;
    881 	int i, last, first, len, dest, leftover;
    882 
    883 	i = ri->ri_width * ri->ri_font->fontheight * nrows;
    884 	len = i & 0xffffe0;
    885 	leftover = i & 0x1f;
    886 	if (srcrow < dstrow) {
    887 		/* we must go bottom to top */
    888 		first = ri->ri_width *
    889 		    (ri->ri_font->fontheight * srcrow + ri->ri_yorigin);
    890 		last = first + len;
    891 		dest = ri->ri_width *
    892 		    (ri->ri_font->fontheight * dstrow + ri->ri_yorigin) + len;
    893 		if (leftover > 0) {
    894 			sc->sc_rblit[dest + 32] =
    895 			    (uint64_t)((leftover - 1) << 24) |
    896 			    (uint64_t)(i + 32);
    897 		}
    898 		for (i = last; i >= first; i -= 32) {
    899 			sc->sc_rblit[dest] = 0x300000001f000000LL | (uint64_t)i;
    900 			dest -= 32;
    901 		}
    902 	} else {
    903 		/* top to bottom */
    904 		first = ri->ri_width *
    905 		    (ri->ri_font->fontheight * srcrow + ri->ri_yorigin);
    906 		dest = ri->ri_width *
    907 		    (ri->ri_font->fontheight * dstrow + ri->ri_yorigin);
    908 		last = first + len;
    909 		for (i = first; i <= last; i+= 32) {
    910 			sc->sc_rblit[dest] = 0x300000001f000000LL | (uint64_t)i;
    911 			dest += 32;
    912 		}
    913 		if (leftover > 0) {
    914 			sc->sc_rblit[dest] =
    915 			    (uint64_t)((leftover - 1) << 24) | (uint64_t)i;
    916 		}
    917 	}
    918 }
    919 
    920 static void
    921 tcx_eraserows(void *cookie, int start, int nrows, long attr)
    922 {
    923 	struct rasops_info *ri = cookie;
    924 	struct vcons_screen *scr = ri->ri_hw;
    925 	struct tcx_softc *sc = scr->scr_cookie;
    926 	uint64_t temp;
    927 	int i, last, first, len, leftover;
    928 
    929 	i = ri->ri_width * ri->ri_font->fontheight * nrows;
    930 	len = i & 0xffffe0;
    931 	leftover = i & 0x1f;
    932 	first = ri->ri_width *
    933 	    (ri->ri_font->fontheight * start + ri->ri_yorigin);
    934 	last = first + len;
    935 	temp = 0x30000000ffffffffLL |
    936 	    ((uint64_t)ri->ri_devcmap[(attr >> 16) & 0xff] << 32);
    937 
    938 	for (i = first; i <= last; i+= 32)
    939 		sc->sc_rblit[i] = temp;
    940 
    941 	if (leftover > 0) {
    942 		temp &= 0xffffffffffffffffLL << (32 - leftover);
    943 		sc->sc_rblit[i] = temp;
    944 	}
    945 }
    946 /*
    947  * The stipple engine is 100% retarded. All drawing operations have to start
    948  * at 32 pixel boundaries so we'll have to deal with characters being split.
    949  */
    950 
    951 static void
    952 tcx_putchar(void *cookie, int row, int col, u_int c, long attr)
    953 {
    954 	struct rasops_info *ri = cookie;
    955 	struct vcons_screen *scr = ri->ri_hw;
    956 	struct tcx_softc *sc = scr->scr_cookie;
    957 	uint64_t bg, fg, temp, mask;
    958 	int addr, i, uc, shift;
    959 	uint32_t fmask;
    960 	uint8_t *cdata;
    961 	uint16_t *wdata;
    962 
    963 	addr = ri->ri_xorigin +
    964 	    col * ri->ri_font->fontwidth +
    965 	    (ri->ri_yorigin + row * ri->ri_font->fontheight) * ri->ri_width;
    966 
    967 	/* check if the character is crossing a 32 pixel boundary */
    968 	if ((addr & 0xffffe0) ==
    969 	    ((addr + ri->ri_font->fontwidth - 1) & 0xffffe0)) {
    970 		/* phew, not split */
    971 		shift = addr & 0x1f;
    972 		addr &= 0xffffe0;
    973 		fmask = 0xffffffff >> (32 - ri->ri_font->fontwidth);
    974 		fmask = fmask << (32 - ri->ri_font->fontwidth - shift);
    975 		mask = fmask;
    976 		bg = 0x3000000000000000LL |
    977 		    ((uint64_t)ri->ri_devcmap[(attr >> 16) & 0xff] &
    978 		      0xff) << 32;
    979 		bg |= mask;
    980 		temp = 0x3000000000000000LL |
    981 		    ((uint64_t)ri->ri_devcmap[(attr >> 24) & 0xff] & 0xff) <<
    982 		    	32;
    983 		uc = c - ri->ri_font->firstchar;
    984 		cdata = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale;
    985 
    986 		if (ri->ri_font->fontwidth < 9) {
    987 			/* byte by byte */
    988 			for (i = 0; i < ri->ri_font->fontheight; i++) {
    989 				sc->sc_rstip[addr] = bg;
    990 				if (*cdata != 0) {
    991 					if (shift > 24) {
    992 						fg = (uint64_t)*cdata >>
    993 					  	  (shift - 24);
    994 					} else {
    995 						fg = (uint64_t)*cdata <<
    996 					  	  (24 - shift);
    997 					}
    998 					sc->sc_rstip[addr] = fg | temp;
    999 				}
   1000 				cdata++;
   1001 				addr += ri->ri_width;
   1002 			}
   1003 		} else if (ri->ri_font->fontwidth < 17) {
   1004 			/* short by short */
   1005 			wdata = (uint16_t *)cdata;
   1006 			for (i = 0; i < ri->ri_font->fontheight; i++) {
   1007 				sc->sc_rstip[addr] = bg;
   1008 				if (*wdata != 0) {
   1009 					if (shift > 16) {
   1010 						fg = temp | (uint64_t)*wdata >>
   1011 					  	  (shift - 16);
   1012 					} else {
   1013 						fg = temp | (uint64_t)*wdata <<
   1014 					  	  (16 - shift);
   1015 					}
   1016 					sc->sc_rstip[addr] = fg;
   1017 				}
   1018 				wdata++;
   1019 				addr += ri->ri_width;
   1020 			}
   1021 		}
   1022 	} else {
   1023 		/* and now the split case ( man this hardware is dumb ) */
   1024 		uint64_t bgr, maskr, fgr;
   1025 		uint32_t bork;
   1026 
   1027 		shift = addr & 0x1f;
   1028 		addr &= 0xffffe0;
   1029 		mask = 0xffffffff >> shift;
   1030 		maskr = (uint64_t)(0xffffffffUL <<
   1031 		    (32 - (ri->ri_font->fontwidth + shift - 32)));
   1032 		bg = 0x3000000000000000LL |
   1033 		    ((uint64_t)ri->ri_devcmap[(attr >> 16) & 0xff] &
   1034 		      0xff) << 32;
   1035 		bgr = bg | maskr;
   1036 		bg |= mask;
   1037 		temp = 0x3000000000000000LL |
   1038 		    ((uint64_t)ri->ri_devcmap[(attr >> 24) & 0xff] & 0xff) <<
   1039 		      32;
   1040 
   1041 		uc = c - ri->ri_font->firstchar;
   1042 		cdata = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale;
   1043 
   1044 		if (ri->ri_font->fontwidth < 9) {
   1045 			/* byte by byte */
   1046 			for (i = 0; i < ri->ri_font->fontheight; i++) {
   1047 				sc->sc_rstip[addr] = bg;
   1048 				sc->sc_rstip[addr + 32] = bgr;
   1049 				bork = *cdata;
   1050 				if (bork != 0) {
   1051 					fg = (uint64_t)bork >> (shift - 24);
   1052 					sc->sc_rstip[addr] = fg | temp;
   1053 					fgr = (uint64_t)(bork << (52 - shift));
   1054 					sc->sc_rstip[addr] = fgr | temp;
   1055 				}
   1056 				cdata++;
   1057 				addr += ri->ri_width;
   1058 			}
   1059 		} else if (ri->ri_font->fontwidth < 17) {
   1060 			/* short by short */
   1061 			wdata = (uint16_t *)cdata;
   1062 			for (i = 0; i < ri->ri_font->fontheight; i++) {
   1063 				sc->sc_rstip[addr] = bg;
   1064 				sc->sc_rstip[addr + 32] = bgr;
   1065 				bork = *wdata;
   1066 				if (bork != 0) {
   1067 					fg = (uint64_t)bork >> (shift - 16);
   1068 					sc->sc_rstip[addr] = fg | temp;
   1069 					fgr = (uint64_t)(bork << (48 - shift));
   1070 					sc->sc_rstip[addr + 32] = fgr | temp;
   1071 				}
   1072 				wdata++;
   1073 				addr += ri->ri_width;
   1074 			}
   1075 		}
   1076 
   1077 	}
   1078 }
   1079 
   1080