Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.9
      1 /* $NetBSD: xcfb.c,v 1.9 1999/04/30 00:44:11 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1998 Tohru Nishimura.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Tohru Nishimura
     17  *	for the NetBSD Project.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     34 
     35 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.9 1999/04/30 00:44:11 nisimura Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/kernel.h>
     40 #include <sys/device.h>
     41 #include <sys/malloc.h>
     42 #include <sys/buf.h>
     43 #include <sys/ioctl.h>
     44 #include <vm/vm.h>
     45 
     46 #include <machine/bus.h>
     47 #include <machine/intr.h>
     48 
     49 #include <dev/rcons/raster.h>
     50 #include <dev/wscons/wsconsio.h>
     51 #include <dev/wscons/wscons_raster.h>
     52 #include <dev/wscons/wsdisplayvar.h>
     53 
     54 #include <dev/tc/tcvar.h>
     55 #include <dev/tc/ioasicreg.h>
     56 #include <dev/ic/ims332reg.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 struct fb_devconfig {
     61 	vaddr_t dc_vaddr;		/* memory space virtual base address */
     62 	paddr_t dc_paddr;		/* memory space physical base address */
     63 	vsize_t dc_size;		/* size of slot memory */
     64 	int	dc_wid;			/* width of frame buffer */
     65 	int	dc_ht;			/* height of frame buffer */
     66 	int	dc_depth;		/* depth, bits per pixel */
     67 	int	dc_rowbytes;		/* bytes in a FB scan line */
     68 	vaddr_t dc_videobase;		/* base of flat frame buffer */
     69 	struct raster	dc_raster;	/* raster description */
     70 	struct rcons	dc_rcons;	/* raster blitter control info */
     71 	int	   dc_blanked;		/* currently has video disabled */
     72 };
     73 
     74 struct hwcmap {
     75 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
     76 	u_int8_t r[CMAP_SIZE];
     77 	u_int8_t g[CMAP_SIZE];
     78 	u_int8_t b[CMAP_SIZE];
     79 };
     80 
     81 struct hwcursor {
     82 	struct wsdisplay_curpos cc_pos;
     83 	struct wsdisplay_curpos cc_hot;
     84 	struct wsdisplay_curpos cc_size;
     85 #define	CURSOR_MAX_SIZE	64
     86 	u_int8_t cc_color[6];
     87 	u_int64_t cc_image[64 + 64];
     88 };
     89 
     90 #define	XCFB_FB_OFFSET	0x2000000	/* from module's base */
     91 #define	XCFB_FB_SIZE	 0x100000	/* frame buffer size */
     92 
     93 #define	IMS332_HIGH	(IOASIC_SLOT_5_START)
     94 #define	IMS332_RLOW	(IOASIC_SLOT_7_START)
     95 #define	IMS332_WLOW	(IOASIC_SLOT_7_START + 0x20000)
     96 
     97 struct xcfb_softc {
     98 	struct device sc_dev;
     99 	struct fb_devconfig *sc_dc;	/* device configuration */
    100 	struct hwcmap sc_cmap;		/* software copy of colormap */
    101 	struct hwcursor sc_cursor;	/* software copy of cursor */
    102 	/* XXX MAXINE can take PMAG-DV virtical retrace interrupt XXX */
    103 	int nscreens;
    104 	/* cursor coordiate is located at upper-left corner */
    105 	int sc_csr;			/* software copy of IMS332 CSR A */
    106 };
    107 
    108 int  xcfbmatch __P((struct device *, struct cfdata *, void *));
    109 void xcfbattach __P((struct device *, struct device *, void *));
    110 
    111 struct cfattach xcfb_ca = {
    112 	sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
    113 };
    114 
    115 void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    116 struct fb_devconfig xcfb_console_dc;
    117 tc_addr_t xcfb_consaddr;
    118 
    119 
    120 struct wsdisplay_emulops xcfb_emulops = {
    121 	rcons_cursor,
    122 	rcons_mapchar,
    123 	rcons_putchar,
    124 	rcons_copycols,
    125 	rcons_erasecols,
    126 	rcons_copyrows,
    127 	rcons_eraserows,
    128 	rcons_alloc_attr
    129 };
    130 
    131 struct wsscreen_descr xcfb_stdscreen = {
    132 	"std",
    133 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
    134 	&xcfb_emulops,
    135 	0, 0,
    136 	0
    137 };
    138 
    139 const struct wsscreen_descr *_xcfb_scrlist[] = {
    140 	&xcfb_stdscreen,
    141 };
    142 
    143 struct wsscreen_list xcfb_screenlist = {
    144 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
    145 };
    146 
    147 int	xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    148 int	xcfbmmap __P((void *, off_t, int));
    149 
    150 int	xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    151 				      void **, int *, int *, long *));
    152 void	xcfb_free_screen __P((void *, void *));
    153 void	xcfb_show_screen __P((void *, void *));
    154 
    155 struct wsdisplay_accessops xcfb_accessops = {
    156 	xcfbioctl,
    157 	xcfbmmap,
    158 	xcfb_alloc_screen,
    159 	xcfb_free_screen,
    160 	xcfb_show_screen,
    161 	0 /* load_font */
    162 };
    163 
    164 int  xcfb_cnattach __P((tc_addr_t));
    165 int  xcfbintr __P((void *));
    166 void xcfbinit __P((struct fb_devconfig *));
    167 void xcfb_screenblank __P((struct xcfb_softc *));
    168 
    169 static int  set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    170 static int  get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    171 static int  set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    172 static int  get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    173 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
    174 void ims332_loadcmap __P((struct hwcmap *));
    175 void ims332_set_cursor __P((struct xcfb_softc *));
    176 void ims332_set_curpos __P((struct xcfb_softc *));
    177 void ims332_load_curcmap __P((struct xcfb_softc *));
    178 void ims332_load_curshape __P((struct xcfb_softc *));
    179 u_int32_t ims332_read_reg __P((int));
    180 void ims332_write_reg __P((int, u_int32_t));
    181 
    182 extern long ioasic_base;	/* XXX */
    183 
    184 /*
    185  * Compose 2 bit/pixel cursor image.
    186  *   M M M M I I I I		M I M I M I M I
    187  *	[ before ]		   [ after ]
    188  *   3 2 1 0 3 2 1 0		3 3 2 2 1 1 0 0
    189  *   7 6 5 4 7 6 5 4		7 7 6 6 5 5 4 4
    190  */
    191 const static u_int8_t shuffle[256] = {
    192 	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
    193 	0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
    194 	0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
    195 	0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
    196 	0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
    197 	0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
    198 	0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
    199 	0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
    200 	0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
    201 	0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
    202 	0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
    203 	0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
    204 	0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
    205 	0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
    206 	0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
    207 	0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
    208 	0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
    209 	0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
    210 	0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
    211 	0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
    212 	0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
    213 	0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
    214 	0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
    215 	0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
    216 	0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
    217 	0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
    218 	0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
    219 	0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
    220 	0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
    221 	0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
    222 	0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
    223 	0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
    224 };
    225 
    226 int
    227 xcfbmatch(parent, match, aux)
    228 	struct device *parent;
    229 	struct cfdata *match;
    230 	void *aux;
    231 {
    232 	struct tc_attach_args *ta = aux;
    233 
    234 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
    235 		return (0);
    236 
    237 	return (1);
    238 }
    239 
    240 void
    241 xcfb_getdevconfig(dense_addr, dc)
    242 	tc_addr_t dense_addr;
    243 	struct fb_devconfig *dc;
    244 {
    245 	struct raster *rap;
    246 	struct rcons *rcp;
    247 	int i;
    248 
    249 	dc->dc_vaddr = dense_addr;
    250 	dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET);
    251 
    252 	dc->dc_wid = 1024;
    253 	dc->dc_ht = 768;
    254 	dc->dc_depth = 8;
    255 	dc->dc_rowbytes = 1024;
    256 	dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET;
    257 	dc->dc_blanked = 0;
    258 
    259 	/* initialize colormap and cursor resource */
    260 	xcfbinit(dc);
    261 
    262 	/* clear the screen */
    263 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    264 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
    265 
    266 	/* initialize the raster */
    267 	rap = &dc->dc_raster;
    268 	rap->width = dc->dc_wid;
    269 	rap->height = dc->dc_ht;
    270 	rap->depth = dc->dc_depth;
    271 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    272 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    273 
    274 	/* initialize the raster console blitter */
    275 	rcp = &dc->dc_rcons;
    276 	rcp->rc_sp = rap;
    277 	rcp->rc_crow = rcp->rc_ccol = -1;
    278 	rcp->rc_crowp = &rcp->rc_crow;
    279 	rcp->rc_ccolp = &rcp->rc_ccol;
    280 	rcons_init(rcp, 34, 80);
    281 
    282 	xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    283 	xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    284 }
    285 
    286 void
    287 xcfbattach(parent, self, aux)
    288 	struct device *parent, *self;
    289 	void *aux;
    290 {
    291 	struct xcfb_softc *sc = (struct xcfb_softc *)self;
    292 	struct tc_attach_args *ta = aux;
    293 	struct wsemuldisplaydev_attach_args waa;
    294 #if 1
    295 	struct hwcmap *cm;
    296 	int console;
    297 #else
    298 	struct hwcmap *cm;
    299 	int console, i;
    300 #endif
    301 
    302 	console = (ta->ta_addr == xcfb_consaddr);
    303 	if (console) {
    304 		sc->sc_dc = &xcfb_console_dc;
    305 		sc->nscreens = 1;
    306 	}
    307 	else {
    308 		sc->sc_dc = (struct fb_devconfig *)
    309 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    310 		xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    311 	}
    312 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    313 	    sc->sc_dc->dc_depth);
    314 
    315 #if 1
    316 	cm = &sc->sc_cmap;
    317 	memset(cm, 255, sizeof(struct hwcmap));		/* XXX */
    318 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    319 #else
    320 	cm = &sc->sc_cmap;
    321 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    322 	for (i = 1; i < CMAP_SIZE; i++) {
    323 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    324 	}
    325 #endif
    326 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
    327 
    328         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, xcfbintr, sc);
    329 
    330 	waa.console = console;
    331 	waa.scrdata = &xcfb_screenlist;
    332 	waa.accessops = &xcfb_accessops;
    333 	waa.accesscookie = sc;
    334 
    335 	config_found(self, &waa, wsemuldisplaydevprint);
    336 }
    337 
    338 int
    339 xcfbioctl(v, cmd, data, flag, p)
    340 	void *v;
    341 	u_long cmd;
    342 	caddr_t data;
    343 	int flag;
    344 	struct proc *p;
    345 {
    346 	struct xcfb_softc *sc = v;
    347 	struct fb_devconfig *dc = sc->sc_dc;
    348 	int turnoff, error;
    349 
    350 	switch (cmd) {
    351 	case WSDISPLAYIO_GTYPE:
    352 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    353 		return (0);
    354 
    355 	case WSDISPLAYIO_GINFO:
    356 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    357 		wsd_fbip->height = sc->sc_dc->dc_ht;
    358 		wsd_fbip->width = sc->sc_dc->dc_wid;
    359 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    360 		wsd_fbip->cmsize = CMAP_SIZE;
    361 #undef fbt
    362 		return (0);
    363 
    364 	case WSDISPLAYIO_GETCMAP:
    365 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    366 
    367 	case WSDISPLAYIO_PUTCMAP:
    368 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    369 		if (error == 0)
    370 			ims332_loadcmap(&sc->sc_cmap);
    371 		return (error);
    372 
    373 	case WSDISPLAYIO_SVIDEO:
    374 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    375 		if ((dc->dc_blanked == 0) ^ turnoff) {
    376 			dc->dc_blanked = turnoff;
    377 			xcfb_screenblank(sc);
    378 		}
    379 		return (0);
    380 
    381 	case WSDISPLAYIO_GVIDEO:
    382 		*(u_int *)data = dc->dc_blanked ?
    383 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    384 		return (0);
    385 
    386 	case WSDISPLAYIO_GCURPOS:
    387 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    388 		return (0);
    389 
    390 	case WSDISPLAYIO_SCURPOS:
    391 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    392 		ims332_set_curpos(sc);
    393 		return (0);
    394 
    395 	case WSDISPLAYIO_GCURMAX:
    396 		((struct wsdisplay_curpos *)data)->x =
    397 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    398 		return (0);
    399 
    400 	case WSDISPLAYIO_GCURSOR:
    401 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    402 
    403 	case WSDISPLAYIO_SCURSOR:
    404 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    405 	}
    406 	return ENOTTY;
    407 }
    408 
    409 int
    410 xcfbmmap(v, offset, prot)
    411 	void *v;
    412 	off_t offset;
    413 	int prot;
    414 {
    415 	struct xcfb_softc *sc = v;
    416 
    417 	if (offset >= XCFB_FB_SIZE || offset < 0)
    418 		return -1;
    419 	return mips_btop(sc->sc_dc->dc_paddr + offset);
    420 }
    421 
    422 int
    423 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    424 	void *v;
    425 	const struct wsscreen_descr *type;
    426 	void **cookiep;
    427 	int *curxp, *curyp;
    428 	long *attrp;
    429 {
    430 	struct xcfb_softc *sc = v;
    431 	long defattr;
    432 
    433 	if (sc->nscreens > 0)
    434 		return (ENOMEM);
    435 
    436 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    437 	*curxp = 0;
    438 	*curyp = 0;
    439 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    440 	*attrp = defattr;
    441 	sc->nscreens++;
    442 	return (0);
    443 }
    444 
    445 void
    446 xcfb_free_screen(v, cookie)
    447 	void *v;
    448 	void *cookie;
    449 {
    450 	struct xcfb_softc *sc = v;
    451 
    452 	if (sc->sc_dc == &xcfb_console_dc)
    453 		panic("xcfb_free_screen: console");
    454 
    455 	sc->nscreens--;
    456 }
    457 
    458 void
    459 xcfb_show_screen(v, cookie)
    460 	void *v;
    461 	void *cookie;
    462 {
    463 }
    464 
    465 int
    466 xcfb_cnattach(addr)
    467         tc_addr_t addr;
    468 {
    469         struct fb_devconfig *dcp = &xcfb_console_dc;
    470         long defattr;
    471 
    472         xcfb_getdevconfig(addr, dcp);
    473 
    474         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    475 
    476         wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
    477                            0, 0, defattr);
    478         xcfb_consaddr = addr;
    479         return (0);
    480 }
    481 
    482 int
    483 xcfbintr(v)
    484 	void *v;
    485 {
    486 	int intr;
    487 
    488 	intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
    489 	intr &= ~XINE_INTR_VINT;
    490 	*(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
    491 	return 1;
    492 }
    493 
    494 void
    495 xcfbinit(dc)
    496 	struct fb_devconfig *dc;
    497 {
    498 	u_int32_t csr;
    499 	int i;
    500 
    501 	csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
    502 	csr &= ~XINE_CSR_VDAC_ENABLE;
    503 	*(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
    504 	DELAY(50);
    505 	csr |= XINE_CSR_VDAC_ENABLE;
    506 	*(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
    507 	DELAY(50);
    508 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
    509 	ims332_write_reg(IMS332_REG_CSR_A,
    510 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
    511 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
    512 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
    513 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
    514 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
    515 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
    516 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
    517 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
    518 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
    519 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
    520 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
    521 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
    522 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
    523 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
    524 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    525 	ims332_write_reg(IMS332_REG_CSR_A,
    526 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
    527 
    528 	/* build sane colormap */
    529 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    530 	for (i = 1; i < CMAP_SIZE; i++)
    531 		ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
    532 
    533 	/* clear out cursor image */
    534 	for (i = 0; i < 512; i++)
    535 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    536 
    537 	/*
    538 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    539 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
    540 	 * image color.  LUT_0 will be never used.
    541 	 */
    542 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
    543 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
    544 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
    545 }
    546 
    547 void
    548 xcfb_screenblank(sc)
    549 	struct xcfb_softc *sc;
    550 {
    551 	if (sc->sc_dc->dc_blanked)
    552 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
    553 	else
    554 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
    555 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    556 }
    557 
    558 static int
    559 get_cmap(sc, p)
    560 	struct xcfb_softc *sc;
    561 	struct wsdisplay_cmap *p;
    562 {
    563 	u_int index = p->index, count = p->count;
    564 
    565 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    566 		return (EINVAL);
    567 
    568 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    569 	    !uvm_useracc(p->green, count, B_WRITE) ||
    570 	    !uvm_useracc(p->blue, count, B_WRITE))
    571 		return (EFAULT);
    572 
    573 	copyout(&sc->sc_cmap.r[index], p->red, count);
    574 	copyout(&sc->sc_cmap.g[index], p->green, count);
    575 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    576 
    577 	return (0);
    578 }
    579 
    580 static int
    581 set_cmap(sc, p)
    582 	struct xcfb_softc *sc;
    583 	struct wsdisplay_cmap *p;
    584 {
    585 	u_int index = p->index, count = p->count;
    586 
    587 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    588 		return (EINVAL);
    589 
    590 	if (!uvm_useracc(p->red, count, B_READ) ||
    591 	    !uvm_useracc(p->green, count, B_READ) ||
    592 	    !uvm_useracc(p->blue, count, B_READ))
    593 		return (EFAULT);
    594 
    595 	copyin(p->red, &sc->sc_cmap.r[index], count);
    596 	copyin(p->green, &sc->sc_cmap.g[index], count);
    597 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    598 
    599 	return (0);
    600 }
    601 
    602 static int
    603 set_cursor(sc, p)
    604 	struct xcfb_softc *sc;
    605 	struct wsdisplay_cursor *p;
    606 {
    607 #define	cc (&sc->sc_cursor)
    608 	int v, index, count;
    609 
    610 	v = p->which;
    611 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    612 		index = p->cmap.index;
    613 		count = p->cmap.count;
    614 
    615 		if (index >= 2 || index + count > 2)
    616 			return (EINVAL);
    617 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    618 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    619 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    620 			return (EFAULT);
    621 
    622 		copyin(p->cmap.red, &cc->cc_color[index], count);
    623 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    624 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    625 		ims332_load_curcmap(sc);
    626 	}
    627 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    628 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    629 			return (EINVAL);
    630 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    631 		if (!uvm_useracc(p->image, count, B_READ) ||
    632 		    !uvm_useracc(p->mask, count, B_READ))
    633 			return (EFAULT);
    634 		cc->cc_size = p->size;
    635 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    636 		copyin(p->image, cc->cc_image, count);
    637 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
    638 		ims332_load_curshape(sc);
    639 	}
    640 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    641 		cc->cc_hot = p->hot;
    642 		if (p->enable)
    643 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    644 		else
    645 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    646 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    647 	}
    648 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    649 		set_curpos(sc, &p->pos);
    650 		ims332_set_curpos(sc);
    651 	}
    652 
    653 	return (0);
    654 #undef cc
    655 }
    656 
    657 static int
    658 get_cursor(sc, p)
    659 	struct xcfb_softc *sc;
    660 	struct wsdisplay_cursor *p;
    661 {
    662 	return (ENOTTY); /* XXX */
    663 }
    664 
    665 static void
    666 set_curpos(sc, curpos)
    667 	struct xcfb_softc *sc;
    668 	struct wsdisplay_curpos *curpos;
    669 {
    670 	struct fb_devconfig *dc = sc->sc_dc;
    671 	int x = curpos->x, y = curpos->y;
    672 
    673 	if (y < 0)
    674 		y = 0;
    675 	else if (y > dc->dc_ht)
    676 		y = dc->dc_ht;
    677 	if (x < 0)
    678 		x = 0;
    679 	else if (x > dc->dc_wid)
    680 		x = dc->dc_wid;
    681 	sc->sc_cursor.cc_pos.x = x;
    682 	sc->sc_cursor.cc_pos.y = y;
    683 }
    684 
    685 void
    686 ims332_loadcmap(cm)
    687 	struct hwcmap *cm;
    688 {
    689 	int i;
    690 	u_int32_t rgb;
    691 
    692 	for (i = 0; i < CMAP_SIZE; i++) {
    693 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    694 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    695 	}
    696 }
    697 
    698 void
    699 ims332_set_curpos(sc)
    700 	struct xcfb_softc *sc;
    701 {
    702 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    703 	u_int32_t pos;
    704 	int s;
    705 
    706 	s = spltty();
    707 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    708 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    709 	splx(s);
    710 }
    711 
    712 void
    713 ims332_load_curcmap(sc)
    714 	struct xcfb_softc *sc;
    715 {
    716 	u_int8_t *cp = sc->sc_cursor.cc_color;
    717 	u_int32_t rgb;
    718 
    719 	/* cursor background */
    720 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    721 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    722 
    723 	/* cursor foreground */
    724 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    725 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    726 }
    727 
    728 void
    729 ims332_load_curshape(sc)
    730 	struct xcfb_softc *sc;
    731 {
    732 	unsigned i, img, msk, bits;
    733 	u_int8_t u, *ip, *mp;
    734 
    735 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
    736 	mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
    737 
    738 	i = 0;
    739 	/* 64 pixel scan line is consisted with 8 halfward cursor ram */
    740 	while (i < sc->sc_cursor.cc_size.y * 8) {
    741 		/* pad right half 32 pixel when smaller than 33 */
    742 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
    743 			bits = 0;
    744 		else {
    745 			img = *ip++;
    746 			msk = *mp++;
    747 			img &= msk;	/* cookie off image */
    748 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    749 			bits = shuffle[u];
    750 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    751 			bits = (shuffle[u] << 8) | bits;
    752 		}
    753 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
    754 		i += 1;
    755 	}
    756 	/* pad unoccupied scan lines */
    757 	while (i < CURSOR_MAX_SIZE * 8) {
    758 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    759 		i += 1;
    760 	}
    761 }
    762 
    763 u_int32_t
    764 ims332_read_reg(regno)
    765 	int regno;
    766 {
    767 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    768 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
    769 	u_int v0, v1;
    770 
    771 	v1 = *(volatile u_int16_t *)high8;
    772 	v0 = *(volatile u_int16_t *)low16;
    773 	return (v1 & 0xff00) << 8 | v0;
    774 }
    775 
    776 void
    777 ims332_write_reg(regno, val)
    778 	int regno;
    779 	u_int32_t val;
    780 {
    781 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    782 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
    783 
    784 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
    785 	*(volatile u_int16_t *)low16 = val;
    786 }
    787