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