Home | History | Annotate | Line # | Download | only in tc
sfbplus.c revision 1.1
      1 /* $NetBSD: sfbplus.c,v 1.1 1999/12/03 09:50:53 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1999 Tohru Nishimura.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Tohru Nishimura
     17  *	for the NetBSD Project.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     34 
     35 __KERNEL_RCSID(0, "$NetBSD: sfbplus.c,v 1.1 1999/12/03 09:50:53 nisimura Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/kernel.h>
     40 #include <sys/device.h>
     41 #include <sys/malloc.h>
     42 #include <sys/buf.h>
     43 #include <sys/ioctl.h>
     44 #include <vm/vm.h>
     45 
     46 #include <machine/bus.h>
     47 #include <machine/intr.h>
     48 
     49 #include <dev/rcons/raster.h>
     50 #include <dev/wscons/wsconsio.h>
     51 #include <dev/wscons/wscons_raster.h>
     52 #include <dev/wscons/wsdisplayvar.h>
     53 
     54 #include <dev/tc/tcvar.h>
     55 #include <dev/ic/bt459reg.h>
     56 #include <dev/ic/bt463reg.h>
     57 #include <dev/tc/sfbreg.h>
     58 #include <dev/pci/tgareg.h>
     59 
     60 #include <uvm/uvm_extern.h>
     61 
     62 #if defined(pmax)
     63 #define	machine_btop(x) mips_btop(x)
     64 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     65 #endif
     66 
     67 #if defined(__alpha__) || defined(alpha)
     68 #define machine_btop(x) alpha_btop(x)
     69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     70 #endif
     71 
     72 /* Bt459/Bt463 hardware registers */
     73 #define bt_lo	0
     74 #define bt_hi	1
     75 #define bt_reg	2
     76 #define bt_cmap 3
     77 
     78 #define REG(base, index)	*((u_int32_t *)(base) + (index))
     79 #define SELECT(vdac, regno) do {			\
     80 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
     81 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
     82 	tc_wmb();					\
     83    } while (0)
     84 
     85 struct fb_devconfig {
     86 	vaddr_t dc_vaddr;		/* memory space virtual base address */
     87 	paddr_t dc_paddr;		/* memory space physical base address */
     88 	vsize_t dc_size;		/* size of slot memory */
     89 	int	dc_wid;			/* width of frame buffer */
     90 	int	dc_ht;			/* height of frame buffer */
     91 	int	dc_depth;		/* depth, bits per pixel */
     92 	int	dc_rowbytes;		/* bytes in a FB scan line */
     93 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
     94 	struct raster	dc_raster;	/* raster description */
     95 	struct rcons	dc_rcons;	/* raster blitter control info */
     96 	int	    dc_blanked;		/* currently has video disabled */
     97 };
     98 
     99 struct hwcmap256 {
    100 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    101 	u_int8_t r[CMAP_SIZE];
    102 	u_int8_t g[CMAP_SIZE];
    103 	u_int8_t b[CMAP_SIZE];
    104 };
    105 
    106 struct hwcursor64 {
    107 	struct wsdisplay_curpos cc_pos;
    108 	struct wsdisplay_curpos cc_hot;
    109 	struct wsdisplay_curpos cc_size;
    110 	struct wsdisplay_curpos cc_magic;
    111 #define	CURSOR_MAX_SIZE	64
    112 	u_int8_t cc_color[6];
    113 	u_int64_t cc_image[64 + 64];
    114 };
    115 
    116 struct hwops {
    117 	void (*setlut) __P((void *, struct hwcmap256 *));
    118 	void (*getlut) __P((void *, struct hwcmap256 *));
    119 	void (*visible) __P((void *, int));
    120 	void (*locate) __P((void *, int, int));
    121 	void (*shape) __P((void *, struct wsdisplay_curpos *, u_int64_t *));
    122 	void (*color) __P((void *, u_int8_t *));
    123 };
    124 
    125 struct sfb_softc {
    126 	struct device sc_dev;
    127 	struct fb_devconfig *sc_dc;	/* device configuration */
    128 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    129 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    130 	int sc_curenb;			/* cursor sprite enabled */
    131 	int sc_changed;			/* need update of colormap */
    132 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    133 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    134 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    135 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    136 #define	DATA_ALL_CHANGED	0x0f
    137 	int nscreens;
    138 	struct hwops sc_hwops;
    139 	void *sc_hw0, *sc_hw1;
    140 };
    141 
    142 #define	HX_MAGIC_X 368
    143 #define	HX_MAGIC_Y 38
    144 
    145 static int  sfbpmatch __P((struct device *, struct cfdata *, void *));
    146 static void sfbpattach __P((struct device *, struct device *, void *));
    147 
    148 struct cfattach sfbp_ca = {
    149 	sizeof(struct sfb_softc), sfbpmatch, sfbpattach,
    150 };
    151 
    152 static void sfbp_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    153 static struct fb_devconfig sfbp_console_dc;
    154 static tc_addr_t sfbp_consaddr;
    155 
    156 extern const struct wsdisplay_emulops sfbp_emulops, sfbp_emulops32;
    157 
    158 static struct wsscreen_descr sfb_stdscreen = {
    159 	"std", 0, 0,
    160 	NULL, /* textops */
    161 	0, 0,
    162 	WSSCREEN_REVERSE
    163 };
    164 
    165 static const struct wsscreen_descr *_sfb_scrlist[] = {
    166 	&sfb_stdscreen,
    167 };
    168 
    169 static const struct wsscreen_list sfb_screenlist = {
    170 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
    171 };
    172 
    173 static int  sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    174 static int  sfbmmap __P((void *, off_t, int));
    175 
    176 static int  sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    177 				      void **, int *, int *, long *));
    178 static void sfb_free_screen __P((void *, void *));
    179 static void sfb_show_screen __P((void *, void *));
    180 /* EXPORT */ int  sfb_alloc_attr __P((void *, int, int, int, long *));
    181 
    182 static const struct wsdisplay_accessops sfb_accessops = {
    183 	sfbioctl,
    184 	sfbmmap,
    185 	sfb_alloc_screen,
    186 	sfb_free_screen,
    187 	sfb_show_screen,
    188 	0 /* load_font */
    189 };
    190 
    191 static void bt459visible __P((void *, int));
    192 static void bt459locate __P((void *, int, int));
    193 static void bt459shape __P((void *, struct wsdisplay_curpos *, u_int64_t *));
    194 static void bt459color __P((void *, u_int8_t *));
    195 static void bt459setlut __P((void *, struct hwcmap256 *));
    196 
    197 static void sfbpvisible __P((void *, int));
    198 static void sfbplocate __P((void *, int, int));
    199 static void sfbpshape __P((void *, struct wsdisplay_curpos *, u_int64_t *));
    200 static void bt463color __P((void *, u_int8_t *));
    201 static void noplut __P((void *, struct hwcmap256 *));
    202 
    203 
    204 /* EXPORT */ int sfbp_cnattach __P((tc_addr_t));
    205 static int  sfbpintr __P((void *));
    206 static void sfbpinit __P((struct fb_devconfig *));
    207 
    208 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    209 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    210 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    211 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    212 
    213 
    214 /*
    215  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    216  *   M M M M I I I I		M I M I M I M I
    217  *	[ before ]		   [ after ]
    218  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    219  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    220  */
    221 static const u_int8_t shuffle[256] = {
    222 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    223 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    224 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    225 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    226 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    227 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    228 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    229 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    230 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    231 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    232 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    233 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    234 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    235 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    236 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    237 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    238 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    239 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    240 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    241 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    242 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    243 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    244 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    245 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    246 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    247 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    248 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    249 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    250 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    251 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    252 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    253 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    254 };
    255 
    256 static int
    257 sfbpmatch(parent, match, aux)
    258 	struct device *parent;
    259 	struct cfdata *match;
    260 	void *aux;
    261 {
    262 	struct tc_attach_args *ta = aux;
    263 
    264 	if (strncmp("PMAGD", ta->ta_modname, 5) != 0)
    265 		return (0);
    266 
    267 	return (1);
    268 }
    269 
    270 static void
    271 sfbp_getdevconfig(dense_addr, dc)
    272 	tc_addr_t dense_addr;
    273 	struct fb_devconfig *dc;
    274 {
    275 	struct raster *rap;
    276 	struct rcons *rcp;
    277 	caddr_t sfbasic;
    278 	int i, hsetup, vsetup, vbase;
    279 
    280 	dc->dc_vaddr = dense_addr;
    281 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    282 
    283 	sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    284 	hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
    285 	vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
    286 	i = *(u_int32_t *)(sfbasic + SFB_ASIC_DEEP);
    287 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
    288 
    289 	dc->dc_wid = (hsetup & 0x1ff) << 2;
    290 	dc->dc_ht = (vsetup & 0x7ff);
    291 	dc->dc_depth = (i & 1) ? 32 : 8;
    292 	dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
    293 	dc->dc_videobase = dc->dc_vaddr + 0x800000 + vbase * 4096; /* XXX */
    294 	dc->dc_blanked = 0;
    295 
    296 	/* initialize colormap and cursor resource */
    297 	sfbpinit(dc);
    298 
    299 	/* clear the screen */
    300 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    301 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    302 
    303 	/* initialize the raster */
    304 	rap = &dc->dc_raster;
    305 	rap->width = dc->dc_wid;
    306 	rap->height = dc->dc_ht;
    307 	rap->depth = dc->dc_depth;
    308 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    309 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    310 	rap->data = sfbasic;
    311 
    312 	/* initialize the raster console blitter */
    313 	rcp = &dc->dc_rcons;
    314 	rcp->rc_sp = rap;
    315 	rcp->rc_crow = rcp->rc_ccol = -1;
    316 	rcp->rc_crowp = &rcp->rc_crow;
    317 	rcp->rc_ccolp = &rcp->rc_ccol;
    318 	rcons_init(rcp, 34, 80);
    319 
    320 	sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    321 	sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    322 	sfb_stdscreen.textops
    323 	    = (dc->dc_depth == 8) ? &sfbp_emulops : &sfbp_emulops32;
    324 }
    325 
    326 static void
    327 sfbpattach(parent, self, aux)
    328 	struct device *parent, *self;
    329 	void *aux;
    330 {
    331 	struct sfb_softc *sc = (struct sfb_softc *)self;
    332 	struct tc_attach_args *ta = aux;
    333 	struct wsemuldisplaydev_attach_args waa;
    334 	struct hwcmap256 *cm;
    335 	caddr_t sfbasic;
    336 	int console;
    337 
    338 	console = (ta->ta_addr == sfbp_consaddr);
    339 	if (console) {
    340 		sc->sc_dc = &sfbp_console_dc;
    341 		sc->nscreens = 1;
    342 	}
    343 	else {
    344 		sc->sc_dc = (struct fb_devconfig *)
    345 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    346 		sfbp_getdevconfig(ta->ta_addr, sc->sc_dc);
    347 	}
    348 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    349 	    sc->sc_dc->dc_depth);
    350 
    351 	cm = &sc->sc_cmap;
    352 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
    353 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    354 
    355 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
    356 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
    357 
    358 	if (sc->sc_dc->dc_depth == 8) {
    359 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
    360 		sc->sc_hw1 = sc->sc_hw0;
    361 		sc->sc_hwops.visible = bt459visible;
    362 		sc->sc_hwops.locate = bt459locate;
    363 		sc->sc_hwops.shape = bt459shape;
    364 		sc->sc_hwops.color = bt459color;
    365 		sc->sc_hwops.setlut = bt459setlut;
    366 		sc->sc_hwops.getlut = noplut;
    367 	}
    368 	else {
    369 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_ASIC_OFFSET;
    370 		sc->sc_hw1 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
    371 		sc->sc_hwops.visible = sfbpvisible;
    372 		sc->sc_hwops.locate = sfbplocate;
    373 		sc->sc_hwops.shape = sfbpshape;
    374 		sc->sc_hwops.color = bt463color;
    375 		sc->sc_hwops.setlut = noplut;
    376 		sc->sc_hwops.getlut = noplut;
    377 	}
    378 
    379         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
    380 
    381 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
    382 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;	tc_wmb();
    383 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;	tc_wmb();
    384 
    385 	waa.console = console;
    386 	waa.scrdata = &sfb_screenlist;
    387 	waa.accessops = &sfb_accessops;
    388 	waa.accesscookie = sc;
    389 
    390 	config_found(self, &waa, wsemuldisplaydevprint);
    391 }
    392 
    393 static int
    394 sfbioctl(v, cmd, data, flag, p)
    395 	void *v;
    396 	u_long cmd;
    397 	caddr_t data;
    398 	int flag;
    399 	struct proc *p;
    400 {
    401 	struct sfb_softc *sc = v;
    402 	struct fb_devconfig *dc = sc->sc_dc;
    403 	int turnoff;
    404 
    405 	switch (cmd) {
    406 	case WSDISPLAYIO_GTYPE:
    407 		*(u_int *)data = WSDISPLAY_TYPE_SFB; /* XXX SFBP XXX */
    408 		return (0);
    409 
    410 	case WSDISPLAYIO_GINFO:
    411 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    412 		wsd_fbip->height = sc->sc_dc->dc_ht;
    413 		wsd_fbip->width = sc->sc_dc->dc_wid;
    414 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    415 		wsd_fbip->cmsize = CMAP_SIZE;
    416 #undef fbt
    417 		return (0);
    418 
    419 	case WSDISPLAYIO_GETCMAP:
    420 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    421 
    422 	case WSDISPLAYIO_PUTCMAP:
    423 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    424 
    425 	case WSDISPLAYIO_SVIDEO:
    426 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    427 		if ((dc->dc_blanked == 0) ^ turnoff) {
    428 			dc->dc_blanked = turnoff;
    429 #if 0 /* XXX later XXX */
    430 	Low order 3bit control visibilities of screen and builtin cursor.
    431 #endif	/* XXX XXX XXX */
    432 		}
    433 		return (0);
    434 
    435 	case WSDISPLAYIO_GVIDEO:
    436 		*(u_int *)data = dc->dc_blanked ?
    437 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    438 		return (0);
    439 
    440 	case WSDISPLAYIO_GCURPOS:
    441 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    442 		return (0);
    443 
    444 	case WSDISPLAYIO_SCURPOS: {
    445 		struct wsdisplay_curpos *pos = (void *)data;
    446 		int x, y;
    447 
    448 		x = pos->x;
    449 		y = pos->y;
    450 		if (y < 0)
    451 			y = 0;
    452 		else if (y > dc->dc_ht)
    453 			y = dc->dc_ht;
    454 		if (x < 0)
    455 			x = 0;
    456 		else if (x > dc->dc_wid)
    457 			x = dc->dc_wid;
    458 		sc->sc_cursor.cc_pos.x = x;
    459 		sc->sc_cursor.cc_pos.y = y;
    460 		x -= sc->sc_cursor.cc_hot.x;
    461 		y -= sc->sc_cursor.cc_hot.y;
    462 		x += sc->sc_cursor.cc_magic.x;
    463 		y += sc->sc_cursor.cc_magic.y;
    464 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
    465 		return (0);
    466 		}
    467 
    468 	case WSDISPLAYIO_GCURMAX:
    469 		((struct wsdisplay_curpos *)data)->x =
    470 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    471 		return (0);
    472 
    473 	case WSDISPLAYIO_GCURSOR:
    474 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    475 
    476 	case WSDISPLAYIO_SCURSOR:
    477 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    478 	}
    479 	return ENOTTY;
    480 }
    481 
    482 int
    483 sfbmmap(v, offset, prot)
    484 	void *v;
    485 	off_t offset;
    486 	int prot;
    487 {
    488 	struct sfb_softc *sc = v;
    489 
    490 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
    491 		return (-1);
    492 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    493 }
    494 
    495 static int
    496 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    497 	void *v;
    498 	const struct wsscreen_descr *type;
    499 	void **cookiep;
    500 	int *curxp, *curyp;
    501 	long *attrp;
    502 {
    503 	struct sfb_softc *sc = v;
    504 	long defattr;
    505 
    506 	if (sc->nscreens > 0)
    507 		return (ENOMEM);
    508 
    509 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    510 	*curxp = 0;
    511 	*curyp = 0;
    512 	sfb_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    513 	*attrp = defattr;
    514 	sc->nscreens++;
    515 	return (0);
    516 }
    517 
    518 void
    519 sfb_free_screen(v, cookie)
    520 	void *v;
    521 	void *cookie;
    522 {
    523 	struct sfb_softc *sc = v;
    524 
    525 	if (sc->sc_dc == &sfbp_console_dc)
    526 		panic("sfb_free_screen: console");
    527 
    528 	sc->nscreens--;
    529 }
    530 
    531 static void
    532 sfb_show_screen(v, cookie)
    533 	void *v;
    534 	void *cookie;
    535 {
    536 }
    537 
    538 int
    539 sfbp_cnattach(addr)
    540         tc_addr_t addr;
    541 {
    542         struct fb_devconfig *dcp = &sfbp_console_dc;
    543         long defattr;
    544 
    545         sfbp_getdevconfig(addr, dcp);
    546 
    547         sfb_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    548 
    549         wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
    550                            0, 0, defattr);
    551         sfbp_consaddr = addr;
    552         return(0);
    553 }
    554 
    555 static int
    556 sfbpintr(arg)
    557 	void *arg;
    558 {
    559 	struct sfb_softc *sc = arg;
    560 	caddr_t sfbasic = (caddr_t)sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET;
    561 	int v;
    562 	u_int32_t sisr;
    563 
    564 #define	cc (&sc->sc_cursor)
    565 	sisr = *((u_int32_t *)sfbasic + TGA_REG_SISR);
    566 
    567 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    568 
    569 	if (sc->sc_changed == 0)
    570 		goto finish;
    571 
    572 	v = sc->sc_changed;
    573 	sc->sc_changed = 0;
    574 
    575 	if (v & DATA_ENB_CHANGED)
    576 		(*sc->sc_hwops.visible)(sc->sc_hw0, sc->sc_curenb);
    577 	if (v & DATA_CURCMAP_CHANGED)
    578 		(*sc->sc_hwops.color)(sc->sc_hw1, cc->cc_color);
    579 	if (v & DATA_CURSHAPE_CHANGED)
    580 		(*sc->sc_hwops.shape)(sc->sc_hw0, &cc->cc_size, cc->cc_image);
    581 	if (v & DATA_CMAP_CHANGED)
    582 		(*sc->sc_hwops.setlut)(sc->sc_hw1, &sc->sc_cmap);
    583 
    584 finish:
    585 	*((u_int32_t *)sfbasic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
    586 	return (1);
    587 #undef cc
    588 }
    589 
    590 static void
    591 sfbpinit(dc)
    592 	struct fb_devconfig *dc;
    593 {
    594 	caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    595 	caddr_t vdac = (caddr_t)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
    596 	int i;
    597 
    598 	*(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
    599 	*(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
    600 	*(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0; /* MODE_SIMPLE */
    601 	*(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3;  /* ROP_COPY */
    602 
    603     if (dc->dc_depth == 8) {
    604 	*(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
    605 
    606 	SELECT(vdac, BT459_REG_COMMAND_0);
    607 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    608 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    609 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    610 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    611 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    612 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    613 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    614 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    615 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    616 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    617 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    618 
    619 	SELECT(vdac, BT459_REG_CCR);
    620 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    621 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    622 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    623 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    624 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    625 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    626 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    627 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    628 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    629 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    630 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    631 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    632 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    633 
    634 	/* build sane colormap */
    635 	SELECT(vdac, 0);
    636 	REG(vdac, bt_cmap) = 0;	tc_wmb();
    637 	REG(vdac, bt_cmap) = 0;	tc_wmb();
    638 	REG(vdac, bt_cmap) = 0;	tc_wmb();
    639 	for (i = 1; i < CMAP_SIZE; i++) {
    640 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    641 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    642 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    643 	}
    644 
    645 	/* clear out cursor image */
    646 	SELECT(vdac, BT459_REG_CRAM_BASE);
    647 	for (i = 0; i < 1024; i++)
    648 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    649 
    650 	/*
    651 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    652 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    653 	 * image color.  CCOLOR_1 will be never used.
    654 	 */
    655 	SELECT(vdac, BT459_REG_CCOLOR_1);
    656 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    657 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    658 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    659 
    660 	REG(vdac, bt_reg) = 0;		tc_wmb();
    661 	REG(vdac, bt_reg) = 0;		tc_wmb();
    662 	REG(vdac, bt_reg) = 0;		tc_wmb();
    663 
    664 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    665 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    666 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    667     } else {
    668 	SELECT(vdac, BT463_IREG_COMMAND_0);
    669 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
    670 	REG(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
    671 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
    672 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
    673 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
    674 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
    675 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
    676 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
    677 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
    678 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
    679 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
    680 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
    681 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
    682 
    683 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    684   {
    685 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    686 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    687 	};
    688 
    689 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    690 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    691 		REG(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    692 		REG(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    693 		REG(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    694 	}
    695   }
    696 #endif
    697 
    698 	SELECT(vdac, BT463_IREG_CPALETTE_RAM);
    699 	REG(vdac, bt_cmap) = 0;		tc_wmb();
    700 	REG(vdac, bt_cmap) = 0;		tc_wmb();
    701 	REG(vdac, bt_cmap) = 0;		tc_wmb();
    702 	for (i = 1; i < 256; i++) {
    703 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    704 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    705 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
    706 	}
    707 
    708 	/* !? Eeeh !? */
    709 	SELECT(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    710 	for (i = 0; i < 256; i++) {
    711 		REG(vdac, bt_cmap) = i;	tc_wmb();
    712 		REG(vdac, bt_cmap) = i;	tc_wmb();
    713 		REG(vdac, bt_cmap) = i;	tc_wmb();
    714 	}
    715     }
    716 }
    717 
    718 static int
    719 get_cmap(sc, p)
    720 	struct sfb_softc *sc;
    721 	struct wsdisplay_cmap *p;
    722 {
    723 	u_int index = p->index, count = p->count;
    724 
    725 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    726 		return (EINVAL);
    727 
    728 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    729 	    !uvm_useracc(p->green, count, B_WRITE) ||
    730 	    !uvm_useracc(p->blue, count, B_WRITE))
    731 		return (EFAULT);
    732 
    733 	copyout(&sc->sc_cmap.r[index], p->red, count);
    734 	copyout(&sc->sc_cmap.g[index], p->green, count);
    735 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    736 
    737 	return (0);
    738 }
    739 
    740 static int
    741 set_cmap(sc, p)
    742 	struct sfb_softc *sc;
    743 	struct wsdisplay_cmap *p;
    744 {
    745 	u_int index = p->index, count = p->count;
    746 
    747 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    748 		return (EINVAL);
    749 
    750 	if (!uvm_useracc(p->red, count, B_READ) ||
    751 	    !uvm_useracc(p->green, count, B_READ) ||
    752 	    !uvm_useracc(p->blue, count, B_READ))
    753 		return (EFAULT);
    754 
    755 	copyin(p->red, &sc->sc_cmap.r[index], count);
    756 	copyin(p->green, &sc->sc_cmap.g[index], count);
    757 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    758 
    759 	sc->sc_changed |= DATA_CMAP_CHANGED;
    760 
    761 	return (0);
    762 }
    763 
    764 
    765 static int
    766 set_cursor(sc, p)
    767 	struct sfb_softc *sc;
    768 	struct wsdisplay_cursor *p;
    769 {
    770 #define	cc (&sc->sc_cursor)
    771 	int v, index, count, icount, x, y;
    772 
    773 	v = p->which;
    774 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    775 		index = p->cmap.index;
    776 		count = p->cmap.count;
    777 		if (index >= 2 || (index + count) > 2)
    778 			return (EINVAL);
    779 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    780 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    781 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    782 			return (EFAULT);
    783 	}
    784 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    785 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    786 			return (EINVAL);
    787 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    788 		if (!uvm_useracc(p->image, icount, B_READ) ||
    789 		    !uvm_useracc(p->mask, icount, B_READ))
    790 			return (EFAULT);
    791 	}
    792 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    793 		if (v & WSDISPLAY_CURSOR_DOCUR)
    794 			cc->cc_hot = p->hot;
    795 		if (v & WSDISPLAY_CURSOR_DOPOS) {
    796 			struct fb_devconfig *dc = sc->sc_dc;
    797 
    798 			x = p->pos.x;
    799 			y = p->pos.y;
    800 			if (y < 0)
    801 				y = 0;
    802 			else if (y > dc->dc_ht)
    803 				y = dc->dc_ht;
    804 			if (x < 0)
    805 				x = 0;
    806 			else if (x > dc->dc_wid)
    807 				x = dc->dc_wid;
    808 			sc->sc_cursor.cc_pos.x = x;
    809 			sc->sc_cursor.cc_pos.y = y;
    810 		}
    811 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    812 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    813 		x += sc->sc_cursor.cc_magic.x;
    814 		y += sc->sc_cursor.cc_magic.y;
    815 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
    816 	}
    817 
    818 	sc->sc_changed = 0;
    819 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    820 		sc->sc_curenb = p->enable;
    821 		sc->sc_changed |= DATA_ENB_CHANGED;
    822 	}
    823 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    824 		copyin(p->cmap.red, &cc->cc_color[index], count);
    825 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    826 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    827 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    828 	}
    829 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    830 		cc->cc_size = p->size;
    831 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    832 		copyin(p->image, cc->cc_image, icount);
    833 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    834 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    835 	}
    836 
    837 	return (0);
    838 #undef cc
    839 }
    840 
    841 static int
    842 get_cursor(sc, p)
    843 	struct sfb_softc *sc;
    844 	struct wsdisplay_cursor *p;
    845 {
    846 	return (ENOTTY); /* XXX */
    847 }
    848 
    849 int
    850 sfb_alloc_attr(id, fg, bg, flags, attrp)
    851 	void *id;
    852 	int fg, bg, flags;
    853 	long *attrp;
    854 {
    855 	if (flags & (WSATTR_HILIT | WSATTR_BLINK |
    856 		     WSATTR_UNDERLINE | WSATTR_WSCOLORS))
    857 		return (EINVAL);
    858 	if (flags & WSATTR_REVERSE)
    859 		*attrp = 1;
    860 	else
    861 		*attrp = 0;
    862 	return (0);
    863 }
    864 
    865 static void
    866 bt459visible(hw, on)
    867 	void *hw;
    868 	int on;
    869 {
    870 	SELECT(hw, BT459_REG_CCR);
    871 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
    872 	tc_wmb();
    873 }
    874 
    875 static void
    876 sfbpvisible(hw, on)
    877 	void *hw;
    878 	int on;
    879 {
    880 }
    881 
    882 static void
    883 bt459locate(hw, x, y)
    884 	void *hw;
    885 	int x, y;
    886 {
    887 	int s;
    888 
    889 	s = spltty();
    890 	SELECT(hw, BT459_REG_CURSOR_X_LOW);
    891 	REG(hw, bt_reg) = x;		tc_wmb();
    892 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
    893 	REG(hw, bt_reg) = y;		tc_wmb();
    894 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
    895 	splx(s);
    896 }
    897 
    898 static void
    899 sfbplocate(hw, x, y)
    900 	void *hw;
    901 	int x, y;
    902 {
    903 	*((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
    904 	tc_wmb();
    905 }
    906 
    907 static void
    908 bt459color(hw, cp)
    909 	void *hw;
    910 	u_int8_t *cp;
    911 {
    912 	SELECT(hw, BT459_REG_CCOLOR_2);
    913 	REG(hw, bt_reg) = cp[1]; tc_wmb();
    914 	REG(hw, bt_reg) = cp[3]; tc_wmb();
    915 	REG(hw, bt_reg) = cp[5]; tc_wmb();
    916 
    917 	REG(hw, bt_reg) = cp[0]; tc_wmb();
    918 	REG(hw, bt_reg) = cp[2]; tc_wmb();
    919 	REG(hw, bt_reg) = cp[4]; tc_wmb();
    920 }
    921 
    922 static void
    923 bt463color(hw, cp)
    924 	void *hw;
    925 	u_int8_t *cp;
    926 {
    927 }
    928 
    929 static void
    930 bt459shape(hw, size, image)
    931 	void *hw;
    932 	struct wsdisplay_curpos *size;
    933 	u_int64_t *image;
    934 {
    935 	u_int8_t *ip, *mp, img, msk;
    936 	u_int8_t u;
    937 	int bcnt;
    938 
    939 	ip = (u_int8_t *)image;
    940 	mp = (u_int8_t *)(image + CURSOR_MAX_SIZE);
    941 
    942 	bcnt = 0;
    943 	SELECT(hw, BT459_REG_CRAM_BASE+0);
    944 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
    945 	while (bcnt < size->y * 16) {
    946 		/* pad right half 32 pixel when smaller than 33 */
    947 		if ((bcnt & 0x8) && size->x < 33) {
    948 			REG(hw, bt_reg) = 0; tc_wmb();
    949 			REG(hw, bt_reg) = 0; tc_wmb();
    950 		}
    951 		else {
    952 			img = *ip++;
    953 			msk = *mp++;
    954 			img &= msk;	/* cookie off image */
    955 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    956 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
    957 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    958 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
    959 		}
    960 		bcnt += 2;
    961 	}
    962 	/* pad unoccupied scan lines */
    963 	while (bcnt < CURSOR_MAX_SIZE * 16) {
    964 		REG(hw, bt_reg) = 0; tc_wmb();
    965 		REG(hw, bt_reg) = 0; tc_wmb();
    966 		bcnt += 2;
    967 	}
    968 }
    969 
    970 static void
    971 sfbpshape(hw, size, image)
    972 	void *hw;
    973 	struct wsdisplay_curpos *size;
    974 	u_int64_t *image;
    975 {
    976 }
    977 
    978 static void
    979 bt459setlut(hw, cm)
    980 	void *hw;
    981 	struct hwcmap256 *cm;
    982 {
    983 	int index;
    984 
    985 	SELECT(hw, 0);
    986 	for (index = 0; index < CMAP_SIZE; index++) {
    987 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
    988 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
    989 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
    990 	}
    991 }
    992 
    993 static void
    994 noplut(hw, cm)
    995 	void *hw;
    996 	struct hwcmap256 *cm;
    997 {
    998 }
    999