Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.54
      1 /* $NetBSD: cfb.c,v 1.54 2008/05/26 10:31:22 nisimura 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.54 2008/05/26 10:31:22 nisimura 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  *			u_int8_t u0;
     72  *			u_int8_t u1;
     73  *			u_int8_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  *		   u_int32_t	   bt_lo;
     80  *		   u_int32_t	   bt_hi;
     81  *		   u_int32_t	   bt_reg;
     82  *		   u_int32_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 u_int32_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 	u_int8_t r[CMAP_SIZE];
    103 	u_int8_t g[CMAP_SIZE];
    104 	u_int8_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 	u_int8_t cc_color[6];
    114 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    115 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
    116 };
    117 
    118 struct cfb_softc {
    119 	struct device sc_dev;
    120 	vaddr_t sc_vaddr;
    121 	size_t sc_size;
    122 	struct rasops_info *sc_ri;
    123 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    124 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    125 	int sc_blanked;
    126 	int sc_curenb;			/* cursor sprite enabled */
    127 	int sc_changed;			/* need update of hardware */
    128 #define	WSDISPLAY_CMAP_DOLUT	0x20
    129 	int nscreens;
    130 };
    131 
    132 #define	CX_MAGIC_X	220
    133 #define	CX_MAGIC_Y 	35
    134 
    135 #define	CX_FB_OFFSET	0x000000
    136 #define	CX_FB_SIZE	0x100000
    137 #define	CX_BT459_OFFSET	0x200000
    138 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
    139 
    140 static int  cfbmatch(struct device *, struct cfdata *, void *);
    141 static void cfbattach(struct device *, struct device *, void *);
    142 
    143 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
    144     cfbmatch, cfbattach, NULL, NULL);
    145 
    146 static void cfb_common_init(struct rasops_info *);
    147 static struct rasops_info cfb_console_ri;
    148 static tc_addr_t cfb_consaddr;
    149 
    150 static struct wsscreen_descr cfb_stdscreen = {
    151 	"std", 0, 0,
    152 	0, /* textops */
    153 	0, 0,
    154 	WSSCREEN_REVERSE
    155 };
    156 
    157 static const struct wsscreen_descr *_cfb_scrlist[] = {
    158 	&cfb_stdscreen,
    159 };
    160 
    161 static const struct wsscreen_list cfb_screenlist = {
    162 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    163 };
    164 
    165 static int	cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
    166 static paddr_t	cfbmmap(void *, void *, off_t, int);
    167 
    168 static int	cfb_alloc_screen(void *, const struct wsscreen_descr *,
    169 				      void **, int *, int *, long *);
    170 static void	cfb_free_screen(void *, void *);
    171 static int	cfb_show_screen(void *, void *, int,
    172 				     void (*) (void *, int, int), void *);
    173 
    174 static const struct wsdisplay_accessops cfb_accessops = {
    175 	cfbioctl,
    176 	cfbmmap,
    177 	cfb_alloc_screen,
    178 	cfb_free_screen,
    179 	cfb_show_screen,
    180 	0 /* load_font */
    181 };
    182 
    183 int  cfb_cnattach(tc_addr_t);
    184 static int  cfbintr(void *);
    185 static void cfbhwinit(void *);
    186 static void cfb_cmap_init(struct cfb_softc *);
    187 
    188 static int  get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
    189 static int  set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
    190 static int  set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
    191 static int  get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
    192 static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *);
    193 
    194 /*
    195  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    196  *   M M M M I I I I		M I M I M I M I
    197  *	[ before ]		   [ after ]
    198  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    199  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    200  */
    201 static const u_int8_t shuffle[256] = {
    202 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    203 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    204 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    205 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    206 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    207 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    208 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    209 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    210 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    211 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    212 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    213 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    214 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    215 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    216 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    217 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    218 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    219 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    220 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    221 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    222 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    223 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    224 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    225 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    226 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    227 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    228 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    229 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    230 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    231 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    232 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    233 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    234 };
    235 
    236 static int
    237 cfbmatch(struct device *parent, struct cfdata *match, void *aux)
    238 {
    239 	struct tc_attach_args *ta = aux;
    240 
    241 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    242 		return (0);
    243 
    244 	return (1);
    245 }
    246 
    247 static void
    248 cfbattach(struct device *parent, struct device *self, void *aux)
    249 {
    250 	struct cfb_softc *sc = device_private(self);
    251 	struct tc_attach_args *ta = aux;
    252 	struct rasops_info *ri;
    253 	struct wsemuldisplaydev_attach_args waa;
    254 	int console;
    255 
    256 	console = (ta->ta_addr == cfb_consaddr);
    257 	if (console) {
    258 		sc->sc_ri = ri = &cfb_console_ri;
    259 		sc->nscreens = 1;
    260 	}
    261 	else {
    262 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    263 			M_DEVBUF, M_NOWAIT);
    264 		if (ri == NULL) {
    265 			printf(": can't alloc memory\n");
    266 			return;
    267 		}
    268 		memset(ri, 0, sizeof(struct rasops_info));
    269 
    270 		ri->ri_hw = (void *)ta->ta_addr;
    271 		cfb_common_init(ri);
    272 		sc->sc_ri = ri;
    273 	}
    274 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    275 
    276 	cfb_cmap_init(sc);
    277 
    278 	sc->sc_vaddr = ta->ta_addr;
    279 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
    280 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
    281 	sc->sc_blanked = sc->sc_curenb = 0;
    282 
    283 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
    284 
    285 	/* clear any pending interrupts */
    286 	*(volatile u_int8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
    287 
    288 	waa.console = console;
    289 	waa.scrdata = &cfb_screenlist;
    290 	waa.accessops = &cfb_accessops;
    291 	waa.accesscookie = sc;
    292 
    293 	config_found(self, &waa, wsemuldisplaydevprint);
    294 }
    295 
    296 static void
    297 cfb_cmap_init(struct cfb_softc *sc)
    298 {
    299 	struct hwcmap256 *cm;
    300 	const u_int8_t *p;
    301 	int index;
    302 
    303 	cm = &sc->sc_cmap;
    304 	p = rasops_cmap;
    305 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    306 		cm->r[index] = p[0];
    307 		cm->g[index] = p[1];
    308 		cm->b[index] = p[2];
    309 	}
    310 }
    311 
    312 static void
    313 cfb_common_init(struct rasops_info *ri)
    314 {
    315 	char *base;
    316 	int cookie;
    317 
    318 	base = (void *)ri->ri_hw;
    319 
    320 	/* initialize colormap and cursor hardware */
    321 	cfbhwinit(base);
    322 
    323 	ri->ri_flg = RI_CENTER;
    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 	*(u_int8_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 		u_int8_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 		u_int8_t *ip, *mp, img, msk;
    548 		u_int8_t u;
    549 		int bcnt;
    550 
    551 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    552 		mp = (u_int8_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 u_int8_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