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