Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.10
      1 /* $NetBSD: xcfb.c,v 1.10 1999/04/30 09:43:23 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.10 1999/04/30 09:43:23 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 	struct hwcmap *cm;
    295 	int console;
    296 
    297 	console = (ta->ta_addr == xcfb_consaddr);
    298 	if (console) {
    299 		sc->sc_dc = &xcfb_console_dc;
    300 		sc->nscreens = 1;
    301 	}
    302 	else {
    303 		sc->sc_dc = (struct fb_devconfig *)
    304 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    305 		xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    306 	}
    307 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    308 	    sc->sc_dc->dc_depth);
    309 
    310 	cm = &sc->sc_cmap;
    311 	memset(cm, 255, sizeof(struct hwcmap));		/* XXX */
    312 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    313 
    314 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
    315 
    316         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, xcfbintr, sc);
    317 
    318 	waa.console = console;
    319 	waa.scrdata = &xcfb_screenlist;
    320 	waa.accessops = &xcfb_accessops;
    321 	waa.accesscookie = sc;
    322 
    323 	config_found(self, &waa, wsemuldisplaydevprint);
    324 }
    325 
    326 int
    327 xcfbioctl(v, cmd, data, flag, p)
    328 	void *v;
    329 	u_long cmd;
    330 	caddr_t data;
    331 	int flag;
    332 	struct proc *p;
    333 {
    334 	struct xcfb_softc *sc = v;
    335 	struct fb_devconfig *dc = sc->sc_dc;
    336 	int turnoff, error;
    337 
    338 	switch (cmd) {
    339 	case WSDISPLAYIO_GTYPE:
    340 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    341 		return (0);
    342 
    343 	case WSDISPLAYIO_GINFO:
    344 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    345 		wsd_fbip->height = sc->sc_dc->dc_ht;
    346 		wsd_fbip->width = sc->sc_dc->dc_wid;
    347 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    348 		wsd_fbip->cmsize = CMAP_SIZE;
    349 #undef fbt
    350 		return (0);
    351 
    352 	case WSDISPLAYIO_GETCMAP:
    353 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    354 
    355 	case WSDISPLAYIO_PUTCMAP:
    356 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    357 		if (error == 0)
    358 			ims332_loadcmap(&sc->sc_cmap);
    359 		return (error);
    360 
    361 	case WSDISPLAYIO_SVIDEO:
    362 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    363 		if ((dc->dc_blanked == 0) ^ turnoff) {
    364 			dc->dc_blanked = turnoff;
    365 			xcfb_screenblank(sc);
    366 		}
    367 		return (0);
    368 
    369 	case WSDISPLAYIO_GVIDEO:
    370 		*(u_int *)data = dc->dc_blanked ?
    371 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    372 		return (0);
    373 
    374 	case WSDISPLAYIO_GCURPOS:
    375 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    376 		return (0);
    377 
    378 	case WSDISPLAYIO_SCURPOS:
    379 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    380 		ims332_set_curpos(sc);
    381 		return (0);
    382 
    383 	case WSDISPLAYIO_GCURMAX:
    384 		((struct wsdisplay_curpos *)data)->x =
    385 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    386 		return (0);
    387 
    388 	case WSDISPLAYIO_GCURSOR:
    389 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    390 
    391 	case WSDISPLAYIO_SCURSOR:
    392 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    393 	}
    394 	return ENOTTY;
    395 }
    396 
    397 int
    398 xcfbmmap(v, offset, prot)
    399 	void *v;
    400 	off_t offset;
    401 	int prot;
    402 {
    403 	struct xcfb_softc *sc = v;
    404 
    405 	if (offset >= XCFB_FB_SIZE || offset < 0)
    406 		return -1;
    407 	return mips_btop(sc->sc_dc->dc_paddr + offset);
    408 }
    409 
    410 int
    411 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    412 	void *v;
    413 	const struct wsscreen_descr *type;
    414 	void **cookiep;
    415 	int *curxp, *curyp;
    416 	long *attrp;
    417 {
    418 	struct xcfb_softc *sc = v;
    419 	long defattr;
    420 
    421 	if (sc->nscreens > 0)
    422 		return (ENOMEM);
    423 
    424 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    425 	*curxp = 0;
    426 	*curyp = 0;
    427 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    428 	*attrp = defattr;
    429 	sc->nscreens++;
    430 	return (0);
    431 }
    432 
    433 void
    434 xcfb_free_screen(v, cookie)
    435 	void *v;
    436 	void *cookie;
    437 {
    438 	struct xcfb_softc *sc = v;
    439 
    440 	if (sc->sc_dc == &xcfb_console_dc)
    441 		panic("xcfb_free_screen: console");
    442 
    443 	sc->nscreens--;
    444 }
    445 
    446 void
    447 xcfb_show_screen(v, cookie)
    448 	void *v;
    449 	void *cookie;
    450 {
    451 }
    452 
    453 int
    454 xcfb_cnattach(addr)
    455         tc_addr_t addr;
    456 {
    457         struct fb_devconfig *dcp = &xcfb_console_dc;
    458         long defattr;
    459 
    460         xcfb_getdevconfig(addr, dcp);
    461 
    462         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    463 
    464         wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
    465                            0, 0, defattr);
    466         xcfb_consaddr = addr;
    467         return (0);
    468 }
    469 
    470 int
    471 xcfbintr(v)
    472 	void *v;
    473 {
    474 	int intr;
    475 
    476 	intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
    477 	intr &= ~XINE_INTR_VINT;
    478 	*(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
    479 	return 1;
    480 }
    481 
    482 void
    483 xcfbinit(dc)
    484 	struct fb_devconfig *dc;
    485 {
    486 	u_int32_t csr;
    487 	int i;
    488 
    489 	csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
    490 	csr &= ~XINE_CSR_VDAC_ENABLE;
    491 	*(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
    492 	DELAY(50);
    493 	csr |= XINE_CSR_VDAC_ENABLE;
    494 	*(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
    495 	DELAY(50);
    496 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
    497 	ims332_write_reg(IMS332_REG_CSR_A,
    498 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
    499 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
    500 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
    501 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
    502 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
    503 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
    504 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
    505 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
    506 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
    507 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
    508 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
    509 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
    510 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
    511 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
    512 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    513 	ims332_write_reg(IMS332_REG_CSR_A,
    514 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
    515 
    516 	/* build sane colormap */
    517 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    518 	for (i = 1; i < CMAP_SIZE; i++)
    519 		ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
    520 
    521 	/* clear out cursor image */
    522 	for (i = 0; i < 512; i++)
    523 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    524 
    525 	/*
    526 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    527 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
    528 	 * image color.  LUT_0 will be never used.
    529 	 */
    530 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
    531 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
    532 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
    533 }
    534 
    535 void
    536 xcfb_screenblank(sc)
    537 	struct xcfb_softc *sc;
    538 {
    539 	if (sc->sc_dc->dc_blanked)
    540 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
    541 	else
    542 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
    543 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    544 }
    545 
    546 static int
    547 get_cmap(sc, p)
    548 	struct xcfb_softc *sc;
    549 	struct wsdisplay_cmap *p;
    550 {
    551 	u_int index = p->index, count = p->count;
    552 
    553 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    554 		return (EINVAL);
    555 
    556 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    557 	    !uvm_useracc(p->green, count, B_WRITE) ||
    558 	    !uvm_useracc(p->blue, count, B_WRITE))
    559 		return (EFAULT);
    560 
    561 	copyout(&sc->sc_cmap.r[index], p->red, count);
    562 	copyout(&sc->sc_cmap.g[index], p->green, count);
    563 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    564 
    565 	return (0);
    566 }
    567 
    568 static int
    569 set_cmap(sc, p)
    570 	struct xcfb_softc *sc;
    571 	struct wsdisplay_cmap *p;
    572 {
    573 	u_int index = p->index, count = p->count;
    574 
    575 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    576 		return (EINVAL);
    577 
    578 	if (!uvm_useracc(p->red, count, B_READ) ||
    579 	    !uvm_useracc(p->green, count, B_READ) ||
    580 	    !uvm_useracc(p->blue, count, B_READ))
    581 		return (EFAULT);
    582 
    583 	copyin(p->red, &sc->sc_cmap.r[index], count);
    584 	copyin(p->green, &sc->sc_cmap.g[index], count);
    585 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    586 
    587 	return (0);
    588 }
    589 
    590 static int
    591 set_cursor(sc, p)
    592 	struct xcfb_softc *sc;
    593 	struct wsdisplay_cursor *p;
    594 {
    595 #define	cc (&sc->sc_cursor)
    596 	int v, index, count;
    597 
    598 	v = p->which;
    599 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    600 		index = p->cmap.index;
    601 		count = p->cmap.count;
    602 
    603 		if (index >= 2 || index + count > 2)
    604 			return (EINVAL);
    605 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    606 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    607 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    608 			return (EFAULT);
    609 
    610 		copyin(p->cmap.red, &cc->cc_color[index], count);
    611 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    612 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    613 		ims332_load_curcmap(sc);
    614 	}
    615 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    616 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    617 			return (EINVAL);
    618 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    619 		if (!uvm_useracc(p->image, count, B_READ) ||
    620 		    !uvm_useracc(p->mask, count, B_READ))
    621 			return (EFAULT);
    622 		cc->cc_size = p->size;
    623 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    624 		copyin(p->image, cc->cc_image, count);
    625 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
    626 		ims332_load_curshape(sc);
    627 	}
    628 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    629 		cc->cc_hot = p->hot;
    630 		if (p->enable)
    631 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    632 		else
    633 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    634 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    635 	}
    636 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    637 		set_curpos(sc, &p->pos);
    638 		ims332_set_curpos(sc);
    639 	}
    640 
    641 	return (0);
    642 #undef cc
    643 }
    644 
    645 static int
    646 get_cursor(sc, p)
    647 	struct xcfb_softc *sc;
    648 	struct wsdisplay_cursor *p;
    649 {
    650 	return (ENOTTY); /* XXX */
    651 }
    652 
    653 static void
    654 set_curpos(sc, curpos)
    655 	struct xcfb_softc *sc;
    656 	struct wsdisplay_curpos *curpos;
    657 {
    658 	struct fb_devconfig *dc = sc->sc_dc;
    659 	int x = curpos->x, y = curpos->y;
    660 
    661 	if (y < 0)
    662 		y = 0;
    663 	else if (y > dc->dc_ht)
    664 		y = dc->dc_ht;
    665 	if (x < 0)
    666 		x = 0;
    667 	else if (x > dc->dc_wid)
    668 		x = dc->dc_wid;
    669 	sc->sc_cursor.cc_pos.x = x;
    670 	sc->sc_cursor.cc_pos.y = y;
    671 }
    672 
    673 void
    674 ims332_loadcmap(cm)
    675 	struct hwcmap *cm;
    676 {
    677 	int i;
    678 	u_int32_t rgb;
    679 
    680 	for (i = 0; i < CMAP_SIZE; i++) {
    681 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    682 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    683 	}
    684 }
    685 
    686 void
    687 ims332_set_curpos(sc)
    688 	struct xcfb_softc *sc;
    689 {
    690 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    691 	u_int32_t pos;
    692 	int s;
    693 
    694 	s = spltty();
    695 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    696 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    697 	splx(s);
    698 }
    699 
    700 void
    701 ims332_load_curcmap(sc)
    702 	struct xcfb_softc *sc;
    703 {
    704 	u_int8_t *cp = sc->sc_cursor.cc_color;
    705 	u_int32_t rgb;
    706 
    707 	/* cursor background */
    708 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    709 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    710 
    711 	/* cursor foreground */
    712 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    713 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    714 }
    715 
    716 void
    717 ims332_load_curshape(sc)
    718 	struct xcfb_softc *sc;
    719 {
    720 	unsigned i, img, msk, bits;
    721 	u_int8_t u, *ip, *mp;
    722 
    723 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
    724 	mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
    725 
    726 	i = 0;
    727 	/* 64 pixel scan line is consisted with 8 halfward cursor ram */
    728 	while (i < sc->sc_cursor.cc_size.y * 8) {
    729 		/* pad right half 32 pixel when smaller than 33 */
    730 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
    731 			bits = 0;
    732 		else {
    733 			img = *ip++;
    734 			msk = *mp++;
    735 			img &= msk;	/* cookie off image */
    736 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    737 			bits = shuffle[u];
    738 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    739 			bits = (shuffle[u] << 8) | bits;
    740 		}
    741 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
    742 		i += 1;
    743 	}
    744 	/* pad unoccupied scan lines */
    745 	while (i < CURSOR_MAX_SIZE * 8) {
    746 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    747 		i += 1;
    748 	}
    749 }
    750 
    751 u_int32_t
    752 ims332_read_reg(regno)
    753 	int regno;
    754 {
    755 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    756 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
    757 	u_int v0, v1;
    758 
    759 	v1 = *(volatile u_int16_t *)high8;
    760 	v0 = *(volatile u_int16_t *)low16;
    761 	return (v1 & 0xff00) << 8 | v0;
    762 }
    763 
    764 void
    765 ims332_write_reg(regno, val)
    766 	int regno;
    767 	u_int32_t val;
    768 {
    769 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    770 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
    771 
    772 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
    773 	*(volatile u_int16_t *)low16 = val;
    774 }
    775