Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.9
      1 /* $NetBSD: sfb.c,v 1.9 1999/02/19 03:42:42 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1998 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: sfb.c,v 1.9 1999/02/19 03:42:42 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 #include <machine/autoconf.h>
     54 
     55 #include <dev/tc/tcvar.h>
     56 #include <dev/ic/bt459reg.h>
     57 #include <dev/tc/sfbreg.h>
     58 
     59 #include "opt_uvm.h"
     60 #if defined(UVM)
     61 #include <uvm/uvm_extern.h>
     62 #define useracc uvm_useracc
     63 #endif
     64 
     65 /* XXX BUS'IFYING XXX */
     66 
     67 #if defined(pmax)
     68 #define	machine_btop(x) mips_btop(x)
     69 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     70 #endif
     71 
     72 #if defined(__alpha__) || defined(alpha)
     73 #define machine_btop(x) alpha_btop(x)
     74 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     75 #endif
     76 
     77 /*
     78  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     79  * obscure register layout such as 2nd and 3rd Bt459 registers are
     80  * adjacent each other in a word, i.e.,
     81  *	struct bt459triplet {
     82  * 		struct {
     83  *			u_int8_t u0;
     84  *			u_int8_t u1;
     85  *			u_int8_t u2;
     86  *			unsigned :8;
     87  *		} bt_lo;
     88  *		...
     89  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
     90  */
     91 struct bt459reg {
     92         u_int32_t       bt_lo;
     93         u_int32_t       bt_hi;
     94         u_int32_t       bt_reg;
     95         u_int32_t       bt_cmap;
     96 };
     97 
     98 /* XXX XXX XXX */
     99 
    100 struct fb_devconfig {
    101 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    102 	paddr_t dc_paddr;		/* memory space physical base address */
    103 	vsize_t dc_size;		/* size of slot memory */
    104 	int	dc_wid;			/* width of frame buffer */
    105 	int	dc_ht;			/* height of frame buffer */
    106 	int	dc_depth;		/* depth, bits per pixel */
    107 	int	dc_rowbytes;		/* bytes in a FB scan line */
    108 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
    109 	struct raster	dc_raster;	/* raster description */
    110 	struct rcons	dc_rcons;	/* raster blitter control info */
    111 	int	    dc_blanked;		/* currently has video disabled */
    112 };
    113 
    114 struct hwcmap {
    115 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    116 	u_int8_t r[CMAP_SIZE];
    117 	u_int8_t g[CMAP_SIZE];
    118 	u_int8_t b[CMAP_SIZE];
    119 };
    120 
    121 struct hwcursor {
    122 	struct wsdisplay_curpos cc_pos;
    123 	struct wsdisplay_curpos cc_hot;
    124 	struct wsdisplay_curpos cc_size;
    125 #define	CURSOR_MAX_SIZE	64
    126 	u_int8_t cc_color[6];
    127 	u_int64_t cc_image[64 + 64];
    128 };
    129 
    130 struct sfb_softc {
    131 	struct device sc_dev;
    132 	struct fb_devconfig *sc_dc;	/* device configuration */
    133 	struct hwcmap sc_cmap;		/* software copy of colormap */
    134 	struct hwcursor sc_cursor;	/* software copy of cursor */
    135 	int sc_curenb;			/* cursor sprite enabled */
    136 	int sc_changed;			/* need update of colormap */
    137 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    138 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    139 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    140 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    141 #define	DATA_ALL_CHANGED	0x0f
    142 	int nscreens;
    143 	short magic_x, magic_y;		/* HX cursor location offset */
    144 #define	HX_MAGIC_X 368
    145 #define	HX_MAGIC_Y 38
    146 };
    147 
    148 int  sfbmatch __P((struct device *, struct cfdata *, void *));
    149 void sfbattach __P((struct device *, struct device *, void *));
    150 
    151 struct cfattach sfb_ca = {
    152 	sizeof(struct sfb_softc), sfbmatch, sfbattach,
    153 };
    154 
    155 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    156 struct fb_devconfig sfb_console_dc;
    157 tc_addr_t sfb_consaddr;
    158 
    159 struct wsdisplay_emulops sfb_emulops = {
    160 	rcons_cursor,			/* could use hardware cursor; punt */
    161 	rcons_mapchar,
    162 	rcons_putchar,
    163 	rcons_copycols,
    164 	rcons_erasecols,
    165 	rcons_copyrows,
    166 	rcons_eraserows,
    167 	rcons_alloc_attr
    168 };
    169 
    170 struct wsscreen_descr sfb_stdscreen = {
    171 	"std", 0, 0,
    172 	&sfb_emulops,
    173 	0, 0,
    174 	0
    175 };
    176 
    177 const struct wsscreen_descr *_sfb_scrlist[] = {
    178 	&sfb_stdscreen,
    179 };
    180 
    181 struct wsscreen_list sfb_screenlist = {
    182 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
    183 };
    184 
    185 int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    186 int	sfbmmap __P((void *, off_t, int));
    187 
    188 int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    189 				      void **, int *, int *, long *));
    190 void	sfb_free_screen __P((void *, void *));
    191 void	sfb_show_screen __P((void *, void *));
    192 
    193 struct wsdisplay_accessops sfb_accessops = {
    194 	sfbioctl,
    195 	sfbmmap,
    196 	sfb_alloc_screen,
    197 	sfb_free_screen,
    198 	sfb_show_screen,
    199 	0 /* load_font */
    200 };
    201 
    202 int  sfb_cnattach __P((tc_addr_t));
    203 int  sfbintr __P((void *));
    204 void sfbinit __P((struct fb_devconfig *));
    205 
    206 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    207 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    208 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    209 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    210 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
    211 static void bt459_set_curpos __P((struct sfb_softc *));
    212 
    213 /* XXX XXX XXX */
    214 #define	BT459_SELECT(vdac, regno) do {		\
    215 	vdac->bt_lo = (regno) & 0x00ff;		\
    216 	vdac->bt_hi = ((regno)& 0x0f00) >> 8;	\
    217 	tc_wmb();				\
    218    } while (0)
    219 /* XXX XXX XXX */
    220 
    221 /*
    222  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    223  *   M M M M I I I I		M I M I M I M I
    224  *	[ before ]		   [ after ]
    225  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    226  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    227  */
    228 const static u_int8_t shuffle[256] = {
    229 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    230 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    231 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    232 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    233 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    234 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    235 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    236 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    237 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    238 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    239 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    240 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    241 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    242 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    243 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    244 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    245 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    246 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    247 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    248 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    249 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    250 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    251 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    252 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    253 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    254 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    255 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    256 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    257 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    258 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    259 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    260 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    261 };
    262 
    263 int
    264 sfbmatch(parent, match, aux)
    265 	struct device *parent;
    266 	struct cfdata *match;
    267 	void *aux;
    268 {
    269 	struct tc_attach_args *ta = aux;
    270 
    271 	if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
    272 		return (0);
    273 
    274 	return (1);
    275 }
    276 
    277 void
    278 sfb_getdevconfig(dense_addr, dc)
    279 	tc_addr_t dense_addr;
    280 	struct fb_devconfig *dc;
    281 {
    282 	struct raster *rap;
    283 	struct rcons *rcp;
    284 	caddr_t sfbasic;
    285 	int i, hsetup, vsetup, vbase;
    286 
    287 	dc->dc_vaddr = dense_addr;
    288 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    289 
    290 	sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    291 	hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
    292 	vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
    293 	vbase  = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
    294 
    295 	dc->dc_wid = (hsetup & 0x1ff) << 2;
    296 	dc->dc_ht = (vsetup & 0x7ff);
    297 	dc->dc_depth = 8;
    298 	dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
    299 	dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
    300 	dc->dc_blanked = 0;
    301 
    302 	/* initialize colormap and cursor resource */
    303 	sfbinit(dc);
    304 
    305 	/* clear the screen */
    306 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    307 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    308 
    309 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
    310 
    311 	/* initialize the raster */
    312 	rap = &dc->dc_raster;
    313 	rap->width = dc->dc_wid;
    314 	rap->height = dc->dc_ht;
    315 	rap->depth = dc->dc_depth;
    316 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    317 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    318 
    319 	/* initialize the raster console blitter */
    320 	rcp = &dc->dc_rcons;
    321 	rcp->rc_sp = rap;
    322 	rcp->rc_crow = rcp->rc_ccol = -1;
    323 	rcp->rc_crowp = &rcp->rc_crow;
    324 	rcp->rc_ccolp = &rcp->rc_ccol;
    325 	rcons_init(rcp, 34, 80);
    326 
    327 	sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    328 	sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    329 
    330 }
    331 
    332 void
    333 sfbattach(parent, self, aux)
    334 	struct device *parent, *self;
    335 	void *aux;
    336 {
    337 	struct sfb_softc *sc = (struct sfb_softc *)self;
    338 	struct tc_attach_args *ta = aux;
    339 	struct wsemuldisplaydev_attach_args waa;
    340 	struct hwcmap *cm;
    341 	caddr_t sfbasic;
    342 	int console, i;
    343 
    344 	console = (ta->ta_addr == sfb_consaddr);
    345 	if (console) {
    346 		sc->sc_dc = &sfb_console_dc;
    347 		sc->nscreens = 1;
    348 	}
    349 	else {
    350 		sc->sc_dc = (struct fb_devconfig *)
    351 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    352 		sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    353 	}
    354 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    355 	    sc->sc_dc->dc_depth);
    356 
    357 	cm = &sc->sc_cmap;
    358 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    359 	for (i = 1; i < CMAP_SIZE; i++) {
    360 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    361 	}
    362 	sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
    363 
    364         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
    365 
    366 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
    367 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    368 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
    369 
    370 	waa.console = console;
    371 	waa.scrdata = &sfb_screenlist;
    372 	waa.accessops = &sfb_accessops;
    373 	waa.accesscookie = sc;
    374 
    375 	config_found(self, &waa, wsemuldisplaydevprint);
    376 }
    377 
    378 int
    379 sfbioctl(v, cmd, data, flag, p)
    380 	void *v;
    381 	u_long cmd;
    382 	caddr_t data;
    383 	int flag;
    384 	struct proc *p;
    385 {
    386 	struct sfb_softc *sc = v;
    387 	struct fb_devconfig *dc = sc->sc_dc;
    388 	int turnoff;
    389 
    390 	switch (cmd) {
    391 	case WSDISPLAYIO_GTYPE:
    392 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
    393 		return (0);
    394 
    395 	case WSDISPLAYIO_GINFO:
    396 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    397 		wsd_fbip->height = sc->sc_dc->dc_ht;
    398 		wsd_fbip->width = sc->sc_dc->dc_wid;
    399 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    400 		wsd_fbip->cmsize = CMAP_SIZE;
    401 #undef fbt
    402 		return (0);
    403 
    404 	case WSDISPLAYIO_GETCMAP:
    405 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    406 
    407 	case WSDISPLAYIO_PUTCMAP:
    408 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    409 
    410 	case WSDISPLAYIO_SVIDEO:
    411 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    412 		if ((dc->dc_blanked == 0) ^ turnoff) {
    413 			dc->dc_blanked = turnoff;
    414 			/* XXX later XXX */
    415 		}
    416 		return (0);
    417 
    418 	case WSDISPLAYIO_GVIDEO:
    419 		*(u_int *)data = dc->dc_blanked ?
    420 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    421 		return (0);
    422 
    423 	case WSDISPLAYIO_GCURPOS:
    424 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    425 		return (0);
    426 
    427 	case WSDISPLAYIO_SCURPOS:
    428 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    429 		bt459_set_curpos(sc);
    430 		return (0);
    431 
    432 	case WSDISPLAYIO_GCURMAX:
    433 		((struct wsdisplay_curpos *)data)->x =
    434 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    435 		return (0);
    436 
    437 	case WSDISPLAYIO_GCURSOR:
    438 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    439 
    440 	case WSDISPLAYIO_SCURSOR:
    441 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    442 	}
    443 	return ENOTTY;
    444 }
    445 
    446 int
    447 sfbmmap(v, offset, prot)
    448 	void *v;
    449 	off_t offset;
    450 	int prot;
    451 {
    452 	struct sfb_softc *sc = v;
    453 
    454 	if (offset >= 0x1000000 || offset < 0)
    455 		return (-1);
    456 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    457 }
    458 
    459 int
    460 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    461 	void *v;
    462 	const struct wsscreen_descr *type;
    463 	void **cookiep;
    464 	int *curxp, *curyp;
    465 	long *attrp;
    466 {
    467 	struct sfb_softc *sc = v;
    468 	long defattr;
    469 
    470 	if (sc->nscreens > 0)
    471 		return (ENOMEM);
    472 
    473 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    474 	*curxp = 0;
    475 	*curyp = 0;
    476 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    477 	*attrp = defattr;
    478 	sc->nscreens++;
    479 	return (0);
    480 }
    481 
    482 void
    483 sfb_free_screen(v, cookie)
    484 	void *v;
    485 	void *cookie;
    486 {
    487 	struct sfb_softc *sc = v;
    488 
    489 	if (sc->sc_dc == &sfb_console_dc)
    490 		panic("sfb_free_screen: console");
    491 
    492 	sc->nscreens--;
    493 }
    494 
    495 void
    496 sfb_show_screen(v, cookie)
    497 	void *v;
    498 	void *cookie;
    499 {
    500 }
    501 
    502 int
    503 sfb_cnattach(addr)
    504         tc_addr_t addr;
    505 {
    506         struct fb_devconfig *dcp = &sfb_console_dc;
    507         long defattr;
    508 
    509         sfb_getdevconfig(addr, dcp);
    510 
    511         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    512 
    513         wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
    514                            0, 0, defattr);
    515         sfb_consaddr = addr;
    516         return(0);
    517 }
    518 
    519 int
    520 sfbintr(arg)
    521 	void *arg;
    522 {
    523 	struct sfb_softc *sc = arg;
    524 	caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    525 	caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
    526 	struct bt459reg *vdac;
    527 	int v;
    528 
    529 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    530 	/* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
    531 
    532 	if (sc->sc_changed == 0)
    533 		return (1);
    534 
    535 	vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
    536 	v = sc->sc_changed;
    537 	sc->sc_changed = 0;
    538 
    539 	if (v & DATA_ENB_CHANGED) {
    540 		BT459_SELECT(vdac, BT459_REG_CCR);
    541 		vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
    542 	}
    543 	if (v & DATA_CURCMAP_CHANGED) {
    544 		u_int8_t *cp = sc->sc_cursor.cc_color;
    545 
    546 		BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
    547 		vdac->bt_reg = cp[1];	tc_wmb();
    548 		vdac->bt_reg = cp[3];	tc_wmb();
    549 		vdac->bt_reg = cp[5];	tc_wmb();
    550 
    551 		vdac->bt_reg = cp[0];	tc_wmb();
    552 		vdac->bt_reg = cp[2];	tc_wmb();
    553 		vdac->bt_reg = cp[4];	tc_wmb();
    554 	}
    555 	if (v & DATA_CURSHAPE_CHANGED) {
    556 		u_int8_t *ip, *mp, img, msk;
    557 		u_int8_t u;
    558 		int bcnt;
    559 
    560 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    561 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    562 
    563 		bcnt = 0;
    564 		BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
    565 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    566 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    567 			/* pad right half 32 pixel when smaller than 33 */
    568 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    569 				vdac->bt_reg = 0; tc_wmb();
    570 				vdac->bt_reg = 0; tc_wmb();
    571 			}
    572 			else {
    573 				img = *ip++;
    574 				msk = *mp++;
    575 				img &= msk;	/* cookie off image */
    576 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    577 				vdac->bt_reg = shuffle[u];	tc_wmb();
    578 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    579 				vdac->bt_reg = shuffle[u];	tc_wmb();
    580 			}
    581 			bcnt += 2;
    582 		}
    583 		/* pad unoccupied scan lines */
    584 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    585 			vdac->bt_reg = 0; tc_wmb();
    586 			vdac->bt_reg = 0; tc_wmb();
    587 			bcnt += 2;
    588 		}
    589 	}
    590 	if (v & DATA_CMAP_CHANGED) {
    591 		struct hwcmap *cm = &sc->sc_cmap;
    592 		int index;
    593 
    594 		BT459_SELECT(vdac, 0);
    595 		for (index = 0; index < CMAP_SIZE; index++) {
    596 			vdac->bt_cmap = cm->r[index];	tc_wmb();
    597 			vdac->bt_cmap = cm->g[index];	tc_wmb();
    598 			vdac->bt_cmap = cm->b[index];	tc_wmb();
    599 		}
    600 	}
    601 	return (1);
    602 }
    603 
    604 void
    605 sfbinit(dc)
    606 	struct fb_devconfig *dc;
    607 {
    608 	caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    609 	struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
    610 	int i;
    611 
    612 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 0;
    613 	*(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
    614 	*(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
    615 	*(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
    616 	*(u_int32_t *)(sfbasic + SFB_ASCI_ROP) = 3;
    617 
    618 	*(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
    619 
    620 	BT459_SELECT(vdac, BT459_REG_COMMAND_0);
    621 	vdac->bt_reg = 0x40; /* CMD0 */	tc_wmb();
    622 	vdac->bt_reg = 0x0;  /* CMD1 */	tc_wmb();
    623 	vdac->bt_reg = 0xc0; /* CMD2 */	tc_wmb();
    624 	vdac->bt_reg = 0xff; /* PRM */	tc_wmb();
    625 	vdac->bt_reg = 0;    /* 205 */	tc_wmb();
    626 	vdac->bt_reg = 0x0;  /* PBM */	tc_wmb();
    627 	vdac->bt_reg = 0;    /* 207 */	tc_wmb();
    628 	vdac->bt_reg = 0x0;  /* ORM */	tc_wmb();
    629 	vdac->bt_reg = 0x0;  /* OBM */	tc_wmb();
    630 	vdac->bt_reg = 0x0;  /* ILV */	tc_wmb();
    631 	vdac->bt_reg = 0x0;  /* TEST */	tc_wmb();
    632 
    633 	BT459_SELECT(vdac, BT459_REG_CCR);
    634 	vdac->bt_reg = 0x0;	tc_wmb();
    635 	vdac->bt_reg = 0x0;	tc_wmb();
    636 	vdac->bt_reg = 0x0;	tc_wmb();
    637 	vdac->bt_reg = 0x0;	tc_wmb();
    638 	vdac->bt_reg = 0x0;	tc_wmb();
    639 	vdac->bt_reg = 0x0;	tc_wmb();
    640 	vdac->bt_reg = 0x0;	tc_wmb();
    641 	vdac->bt_reg = 0x0;	tc_wmb();
    642 	vdac->bt_reg = 0x0;	tc_wmb();
    643 	vdac->bt_reg = 0x0;	tc_wmb();
    644 	vdac->bt_reg = 0x0;	tc_wmb();
    645 	vdac->bt_reg = 0x0;	tc_wmb();
    646 	vdac->bt_reg = 0x0;	tc_wmb();
    647 
    648 	/* build sane colormap */
    649 	BT459_SELECT(vdac, 0);
    650 	vdac->bt_cmap = 0;	tc_wmb();
    651 	vdac->bt_cmap = 0;	tc_wmb();
    652 	vdac->bt_cmap = 0;	tc_wmb();
    653 	for (i = 1; i < CMAP_SIZE; i++) {
    654 		vdac->bt_cmap = 0xff;	tc_wmb();
    655 		vdac->bt_cmap = 0xff;	tc_wmb();
    656 		vdac->bt_cmap = 0xff;	tc_wmb();
    657 	}
    658 
    659 	/* clear out cursor image */
    660 	BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
    661 	for (i = 0; i < 1024; i++)
    662 		vdac->bt_reg = 0xff;	tc_wmb();
    663 
    664 	/*
    665 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    666 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    667 	 * image color.  CCOLOR_1 will be never used.
    668 	 */
    669 	BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
    670 	vdac->bt_reg = 0xff;	tc_wmb();
    671 	vdac->bt_reg = 0xff;	tc_wmb();
    672 	vdac->bt_reg = 0xff;	tc_wmb();
    673 
    674 	vdac->bt_reg = 0;	tc_wmb();
    675 	vdac->bt_reg = 0;	tc_wmb();
    676 	vdac->bt_reg = 0;	tc_wmb();
    677 
    678 	vdac->bt_reg = 0xff;	tc_wmb();
    679 	vdac->bt_reg = 0xff;	tc_wmb();
    680 	vdac->bt_reg = 0xff;	tc_wmb();
    681 }
    682 
    683 static int
    684 get_cmap(sc, p)
    685 	struct sfb_softc *sc;
    686 	struct wsdisplay_cmap *p;
    687 {
    688 	u_int index = p->index, count = p->count;
    689 
    690 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    691 		return (EINVAL);
    692 
    693 	if (!useracc(p->red, count, B_WRITE) ||
    694 	    !useracc(p->green, count, B_WRITE) ||
    695 	    !useracc(p->blue, count, B_WRITE))
    696 		return (EFAULT);
    697 
    698 	copyout(&sc->sc_cmap.r[index], p->red, count);
    699 	copyout(&sc->sc_cmap.g[index], p->green, count);
    700 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    701 
    702 	return (0);
    703 }
    704 
    705 static int
    706 set_cmap(sc, p)
    707 	struct sfb_softc *sc;
    708 	struct wsdisplay_cmap *p;
    709 {
    710 	u_int index = p->index, count = p->count;
    711 
    712 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    713 		return (EINVAL);
    714 
    715 	if (!useracc(p->red, count, B_READ) ||
    716 	    !useracc(p->green, count, B_READ) ||
    717 	    !useracc(p->blue, count, B_READ))
    718 		return (EFAULT);
    719 
    720 	copyin(p->red, &sc->sc_cmap.r[index], count);
    721 	copyin(p->green, &sc->sc_cmap.g[index], count);
    722 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    723 
    724 	sc->sc_changed |= DATA_CMAP_CHANGED;
    725 
    726 	return (0);
    727 }
    728 
    729 
    730 static int
    731 set_cursor(sc, p)
    732 	struct sfb_softc *sc;
    733 	struct wsdisplay_cursor *p;
    734 {
    735 #define	cc (&sc->sc_cursor)
    736 	int v, index, count, icount;
    737 
    738 	v = p->which;
    739 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    740 		index = p->cmap.index;
    741 		count = p->cmap.count;
    742 		if (index >= 2 || (index + count) > 2)
    743 			return (EINVAL);
    744 		if (!useracc(p->cmap.red, count, B_READ) ||
    745 		    !useracc(p->cmap.green, count, B_READ) ||
    746 		    !useracc(p->cmap.blue, count, B_READ))
    747 			return (EFAULT);
    748 	}
    749 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    750 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    751 			return (EINVAL);
    752 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    753 		if (!useracc(p->image, count, B_READ) ||
    754 		    !useracc(p->mask, count, B_READ))
    755 			return (EFAULT);
    756 	}
    757 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    758 		if (v & WSDISPLAY_CURSOR_DOCUR)
    759 			cc->cc_hot = p->hot;
    760 		if (v & WSDISPLAY_CURSOR_DOPOS)
    761 			set_curpos(sc, &p->pos);
    762 		bt459_set_curpos(sc);
    763 	}
    764 
    765 	sc->sc_changed = 0;
    766 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    767 		sc->sc_curenb = p->enable;
    768 		sc->sc_changed |= DATA_ENB_CHANGED;
    769 	}
    770 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    771 		copyin(p->cmap.red, &cc->cc_color[index], count);
    772 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    773 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    774 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    775 	}
    776 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    777 		cc->cc_size = p->size;
    778 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    779 		copyin(p->image, cc->cc_image, icount);
    780 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    781 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    782 	}
    783 
    784 	return (0);
    785 #undef cc
    786 }
    787 
    788 static int
    789 get_cursor(sc, p)
    790 	struct sfb_softc *sc;
    791 	struct wsdisplay_cursor *p;
    792 {
    793 	return (ENOTTY); /* XXX */
    794 }
    795 
    796 static void
    797 set_curpos(sc, curpos)
    798 	struct sfb_softc *sc;
    799 	struct wsdisplay_curpos *curpos;
    800 {
    801 	struct fb_devconfig *dc = sc->sc_dc;
    802 	int x = curpos->x, y = curpos->y;
    803 
    804 	if (y < 0)
    805 		y = 0;
    806 	else if (y > dc->dc_ht)
    807 		y = dc->dc_ht;
    808 	if (x < 0)
    809 		x = 0;
    810 	else if (x > dc->dc_wid)
    811 		x = dc->dc_wid;
    812 	sc->sc_cursor.cc_pos.x = x;
    813 	sc->sc_cursor.cc_pos.y = y;
    814 }
    815 
    816 static void
    817 bt459_set_curpos(sc)
    818 	struct sfb_softc *sc;
    819 {
    820 	caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    821 	struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
    822 	int x, y, s;
    823 
    824 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    825 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    826 	x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
    827 
    828 	s = spltty();
    829 
    830 	BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
    831 	vdac->bt_reg = x;	tc_wmb();
    832 	vdac->bt_reg = x >> 8;	tc_wmb();
    833 	vdac->bt_reg = y;	tc_wmb();
    834 	vdac->bt_reg = y >> 8;	tc_wmb();
    835 
    836 	splx(s);
    837 }
    838