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