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