Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.1
      1 /* $NetBSD: xcfb.c,v 1.1 1998/10/29 12:24:25 nisimura Exp $ */
      2 
      3 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
      4 
      5 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.1 1998/10/29 12:24:25 nisimura Exp $");
      6 
      7 #include <sys/param.h>
      8 #include <sys/systm.h>
      9 #include <sys/kernel.h>
     10 #include <sys/device.h>
     11 #include <sys/malloc.h>
     12 #include <sys/buf.h>
     13 #include <sys/ioctl.h>
     14 #include <vm/vm.h>
     15 
     16 #include <machine/bus.h>
     17 #include <machine/intr.h>
     18 
     19 #include <dev/rcons/raster.h>
     20 #include <dev/wscons/wsconsio.h>
     21 #include <dev/wscons/wscons_raster.h>
     22 #include <dev/wscons/wsdisplayvar.h>
     23 #include <machine/autoconf.h>
     24 
     25 #include <dev/tc/tcvar.h>
     26 #include <dev/ic/ims332reg.h>
     27 
     28 #include "opt_uvm.h"
     29 #if defined(UVM)
     30 #include <uvm/uvm_extern.h>
     31 #define useracc uvm_useracc
     32 #endif
     33 
     34 struct fb_devconfig {
     35 	vaddr_t dc_vaddr;		/* memory space virtual base address */
     36 	paddr_t dc_paddr;		/* memory space physical base address */
     37 	vsize_t dc_size;		/* size of slot memory */
     38 	int	dc_wid;			/* width of frame buffer */
     39 	int	dc_ht;			/* height of frame buffer */
     40 	int	dc_depth;		/* depth, bits per pixel */
     41 	int	dc_rowbytes;		/* bytes in a FB scan line */
     42 	vaddr_t dc_videobase;		/* base of flat frame buffer */
     43 	struct raster	dc_raster;	/* raster description */
     44 	struct rcons	dc_rcons;	/* raster blitter control info */
     45 	int	   dc_blanked;		/* currently has video disabled */
     46 };
     47 
     48 struct hwcmap {
     49 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
     50 	u_int8_t r[CMAP_SIZE];
     51 	u_int8_t g[CMAP_SIZE];
     52 	u_int8_t b[CMAP_SIZE];
     53 };
     54 
     55 struct hwcursor {
     56 	struct wsdisplay_curpos cc_pos;
     57 	struct wsdisplay_curpos cc_hot;
     58 	struct wsdisplay_curpos cc_size;
     59 #define	CURSOR_MAX_SIZE	64
     60 	u_int8_t cc_color[6];
     61 	u_int64_t cc_image[64 + 64];
     62 };
     63 
     64 struct xcfb_softc {
     65 	struct device sc_dev;
     66 	struct fb_devconfig *sc_dc;	/* device configuration */
     67 	struct hwcmap sc_cmap;		/* software copy of colormap */
     68 	struct hwcursor sc_cursor;	/* software copy of cursor */
     69 	/* no sc_change field because PMAG-DV does not emit interrupt */
     70 	/* XXX XXX real-ly !?  See MACH code XXX XXX */
     71 	int nscreens;
     72 };
     73 
     74 int  xcfbmatch __P((struct device *, struct cfdata *, void *));
     75 void xcfbattach __P((struct device *, struct device *, void *));
     76 
     77 struct cfattach xcfb_ca = {
     78 	sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
     79 };
     80 
     81 void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
     82 struct fb_devconfig xcfb_console_dc;
     83 tc_addr_t xcfb_consaddr;
     84 
     85 struct wsdisplay_emulops xcfb_emulops = {
     86 	rcons_cursor,
     87 	rcons_mapchar,
     88 	rcons_putchar,
     89 	rcons_copycols,
     90 	rcons_erasecols,
     91 	rcons_copyrows,
     92 	rcons_eraserows,
     93 	rcons_alloc_attr
     94 };
     95 
     96 struct wsscreen_descr xcfb_stdscreen = {
     97 	"std",
     98 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
     99 	&xcfb_emulops,
    100 	0, 0,
    101 	0
    102 };
    103 
    104 const struct wsscreen_descr *_xcfb_scrlist[] = {
    105 	&xcfb_stdscreen,
    106 };
    107 
    108 struct wsscreen_list xcfb_screenlist = {
    109 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
    110 };
    111 
    112 int	xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    113 int	xcfbmmap __P((void *, off_t, int));
    114 
    115 int	xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    116 				      void **, int *, int *, long *));
    117 void	xcfb_free_screen __P((void *, void *));
    118 void	xcfb_show_screen __P((void *, void *));
    119 int	xcfb_load_font __P((void *, void *, int, int, int, void *));
    120 
    121 struct wsdisplay_accessops xcfb_accessops = {
    122 	xcfbioctl,
    123 	xcfbmmap,
    124 	xcfb_alloc_screen,
    125 	xcfb_free_screen,
    126 	xcfb_show_screen,
    127 	xcfb_load_font
    128 };
    129 
    130 int  xcfb_cnattach __P((tc_addr_t));
    131 void xcfbinit __P((struct fb_devconfig *));
    132 void xcfb_blank __P((struct xcfb_softc *));
    133 void xcfb_unblank __P((struct xcfb_softc *));
    134 
    135 static int  set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    136 static int  get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    137 static int  set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    138 static int  get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    139 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
    140 void ims332_loadcmap __P((struct hwcmap *));
    141 void ims332_set_cursor __P((struct xcfb_softc *));
    142 void ims332_set_curpos __P((struct xcfb_softc *));
    143 void ims332_load_curcmap __P((struct xcfb_softc *));
    144 void ims332_load_curshape __P((struct xcfb_softc *));
    145 u_int32_t ims332_read_reg __P((int));
    146 void ims332_write_reg __P((int, u_int32_t));
    147 
    148 #define	XCFB_FB_OFFSET	0x2000000	/* from module's base */
    149 #define	XCFB_FB_SIZE	0x100000	/* frame buffer size */
    150 
    151 #define	IMS332_ADDRESS	0xbc140000
    152 #define	IMS332_RPTR	0xbc1c0000
    153 #define	IMS332_WPTR	0xbc1e0000
    154 
    155 int
    156 xcfbmatch(parent, match, aux)
    157 	struct device *parent;
    158 	struct cfdata *match;
    159 	void *aux;
    160 {
    161 	struct tc_attach_args *ta = aux;
    162 
    163 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
    164 		return (0);
    165 
    166 	return (1);
    167 }
    168 
    169 void
    170 xcfb_getdevconfig(dense_addr, dc)
    171 	tc_addr_t dense_addr;
    172 	struct fb_devconfig *dc;
    173 {
    174 	struct raster *rap;
    175 	struct rcons *rcp;
    176 	int i;
    177 
    178 	dc->dc_vaddr = dense_addr;
    179 	dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET);
    180 
    181 	dc->dc_wid = 1024;
    182 	dc->dc_ht = 768;
    183 	dc->dc_depth = 8;
    184 	dc->dc_rowbytes = 1024;
    185 	dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET;
    186 	dc->dc_blanked = 0;
    187 
    188 	/* initialize colormap and cursor resource */
    189 	xcfbinit(dc);
    190 
    191 	/* clear the screen */
    192 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    193 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
    194 
    195 	/* initialize the raster */
    196 	rap = &dc->dc_raster;
    197 	rap->width = dc->dc_wid;
    198 	rap->height = dc->dc_ht;
    199 	rap->depth = dc->dc_depth;
    200 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    201 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    202 
    203 	/* initialize the raster console blitter */
    204 	rcp = &dc->dc_rcons;
    205 	rcp->rc_sp = rap;
    206 	rcp->rc_crow = rcp->rc_ccol = -1;
    207 	rcp->rc_crowp = &rcp->rc_crow;
    208 	rcp->rc_ccolp = &rcp->rc_ccol;
    209 	rcons_init(rcp, 34, 80);
    210 
    211 	xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    212 	xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    213 }
    214 
    215 void
    216 xcfbattach(parent, self, aux)
    217 	struct device *parent, *self;
    218 	void *aux;
    219 {
    220 	struct xcfb_softc *sc = (struct xcfb_softc *)self;
    221 	struct tc_attach_args *ta = aux;
    222 	struct wsemuldisplaydev_attach_args waa;
    223 	struct hwcmap *cm;
    224 	int console, i;
    225 
    226 	console = (ta->ta_addr == xcfb_consaddr);
    227 	if (console) {
    228 		sc->sc_dc = &xcfb_console_dc;
    229 		sc->nscreens = 1;
    230 	}
    231 	else {
    232 		sc->sc_dc = (struct fb_devconfig *)
    233 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    234 		xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    235 	}
    236 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    237 	    sc->sc_dc->dc_depth);
    238 
    239 	cm = &sc->sc_cmap;
    240 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    241 	for (i = 1; i < CMAP_SIZE; i++) {
    242 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    243 	}
    244 
    245 	/* PMAG-DV emits no interrupt */
    246 
    247 	waa.console = console;
    248 	waa.scrdata = &xcfb_screenlist;
    249 	waa.accessops = &xcfb_accessops;
    250 	waa.accesscookie = sc;
    251 
    252 	config_found(self, &waa, wsemuldisplaydevprint);
    253 }
    254 
    255 int
    256 xcfbioctl(v, cmd, data, flag, p)
    257 	void *v;
    258 	u_long cmd;
    259 	caddr_t data;
    260 	int flag;
    261 	struct proc *p;
    262 {
    263 	struct xcfb_softc *sc = v;
    264 	struct fb_devconfig *dc = sc->sc_dc;
    265 	int error;
    266 
    267 	switch (cmd) {
    268 	case WSDISPLAYIO_GTYPE:
    269 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    270 		return (0);
    271 
    272 	case WSDISPLAYIO_GINFO:
    273 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    274 		wsd_fbip->height = sc->sc_dc->dc_ht;
    275 		wsd_fbip->width = sc->sc_dc->dc_wid;
    276 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    277 		wsd_fbip->cmsize = CMAP_SIZE;
    278 #undef fbt
    279 		return (0);
    280 
    281 	case WSDISPLAYIO_GETCMAP:
    282 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    283 
    284 	case WSDISPLAYIO_PUTCMAP:
    285 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    286 		if (error == 0)
    287 			ims332_loadcmap(&sc->sc_cmap);
    288 		return (error);
    289 
    290 	case WSDISPLAYIO_SVIDEO:
    291 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
    292 			xcfb_blank(sc);
    293 		else
    294 			xcfb_unblank(sc);
    295 		return (0);
    296 
    297 	case WSDISPLAYIO_GVIDEO:
    298 		*(u_int *)data = dc->dc_blanked ?
    299 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    300 		return (0);
    301 
    302 	case WSDISPLAYIO_GCURPOS:
    303 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    304 		return (0);
    305 
    306 	case WSDISPLAYIO_SCURPOS:
    307 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    308 		ims332_set_curpos(sc);
    309 		return (0);
    310 
    311 	case WSDISPLAYIO_GCURMAX:
    312 		((struct wsdisplay_curpos *)data)->x =
    313 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    314 		return (0);
    315 
    316 	case WSDISPLAYIO_GCURSOR:
    317 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    318 
    319 	case WSDISPLAYIO_SCURSOR:
    320 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    321 	}
    322 	return ENOTTY;
    323 }
    324 
    325 int
    326 xcfbmmap(v, offset, prot)
    327 	void *v;
    328 	off_t offset;
    329 	int prot;
    330 {
    331 	struct xcfb_softc *sc = v;
    332 
    333 	if (offset > XCFB_FB_SIZE)
    334 		return -1;
    335 	return mips_btop(sc->sc_dc->dc_paddr + offset);
    336 }
    337 
    338 int
    339 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    340 	void *v;
    341 	const struct wsscreen_descr *type;
    342 	void **cookiep;
    343 	int *curxp, *curyp;
    344 	long *attrp;
    345 {
    346 	struct xcfb_softc *sc = v;
    347 	long defattr;
    348 
    349 	if (sc->nscreens > 0)
    350 		return (ENOMEM);
    351 
    352 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    353 	*curxp = 0;
    354 	*curyp = 0;
    355 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    356 	*attrp = defattr;
    357 	sc->nscreens++;
    358 	return (0);
    359 }
    360 
    361 void
    362 xcfb_free_screen(v, cookie)
    363 	void *v;
    364 	void *cookie;
    365 {
    366 	struct xcfb_softc *sc = v;
    367 
    368 	if (sc->sc_dc == &xcfb_console_dc)
    369 		panic("xcfb_free_screen: console");
    370 
    371 	sc->nscreens--;
    372 }
    373 
    374 void
    375 xcfb_show_screen(v, cookie)
    376 	void *v;
    377 	void *cookie;
    378 {
    379 }
    380 
    381 int
    382 xcfb_load_font(v, cookie, first, num, stride, data)
    383 	void *v;
    384 	void *cookie;
    385 	int first, num, stride;
    386 	void *data;
    387 {
    388 	return (EINVAL);
    389 }
    390 
    391 int
    392 xcfb_cnattach(addr)
    393         tc_addr_t addr;
    394 {
    395         struct fb_devconfig *dcp = &xcfb_console_dc;
    396         long defattr;
    397 
    398         xcfb_getdevconfig(addr, dcp);
    399 
    400         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    401 
    402         wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
    403                            0, 0, defattr);
    404         xcfb_consaddr = addr;
    405         return(0);
    406 }
    407 
    408 void
    409 xcfbinit(dc)
    410 	struct fb_devconfig *dc;
    411 {
    412 	u_int32_t csr;
    413 	int i;
    414 
    415 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    416 	for (i = 1; i < CMAP_SIZE; i++)
    417 		ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
    418 
    419 	csr = IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE
    420 		| IMS332_CSR_A_VTG_ENABLE | IMS332_CSR_A_DISABLE_CURSOR;
    421 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    422 
    423 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    424 }
    425 
    426 void
    427 xcfb_blank(sc)
    428 	struct xcfb_softc *sc;
    429 {
    430 	struct fb_devconfig *dc = sc->sc_dc;
    431 
    432 	if (dc->dc_blanked)
    433 		return;
    434 	dc->dc_blanked = 1;
    435 
    436 	/* blank screen */
    437 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    438 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0);
    439 #if 0
    440 	/* turnoff hardware cursor */
    441 	csr = ims332_read_reg(IMS332_REG_CSR_A);
    442 	csr |= IMS332_CSR_A_DISABLE_CURSOR;
    443 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    444 #endif	/* pratically unnecessary */
    445 }
    446 
    447 void
    448 xcfb_unblank(sc)
    449 	struct xcfb_softc *sc;
    450 {
    451 	struct fb_devconfig *dc = sc->sc_dc;
    452 
    453 	if (!dc->dc_blanked)
    454 		return;
    455 	dc->dc_blanked = 0;
    456 
    457 	/* restore current colormap */
    458 	ims332_loadcmap(&sc->sc_cmap);
    459 #if 0
    460 	/* turnon hardware cursor */
    461 	csr = ims332_read_reg(IMS332_REG_CSR_A);
    462 	csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    463 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    464 #endif	/* pratically unnecessary */
    465 }
    466 
    467 static int
    468 get_cmap(sc, p)
    469 	struct xcfb_softc *sc;
    470 	struct wsdisplay_cmap *p;
    471 {
    472 	u_int index = p->index, count = p->count;
    473 
    474 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    475 		return (EINVAL);
    476 
    477 	if (!useracc(p->red, count, B_WRITE) ||
    478 	    !useracc(p->green, count, B_WRITE) ||
    479 	    !useracc(p->blue, count, B_WRITE))
    480 		return (EFAULT);
    481 
    482 	copyout(&sc->sc_cmap.r[index], p->red, count);
    483 	copyout(&sc->sc_cmap.g[index], p->green, count);
    484 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    485 
    486 	return (0);
    487 }
    488 
    489 static int
    490 set_cmap(sc, p)
    491 	struct xcfb_softc *sc;
    492 	struct wsdisplay_cmap *p;
    493 {
    494 	u_int index = p->index, count = p->count;
    495 
    496 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    497 		return (EINVAL);
    498 
    499 	if (!useracc(p->red, count, B_READ) ||
    500 	    !useracc(p->green, count, B_READ) ||
    501 	    !useracc(p->blue, count, B_READ))
    502 		return (EFAULT);
    503 
    504 	copyin(p->red, &sc->sc_cmap.r[index], count);
    505 	copyin(p->green, &sc->sc_cmap.g[index], count);
    506 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    507 
    508 	return (0);
    509 }
    510 
    511 static int
    512 set_cursor(sc, p)
    513 	struct xcfb_softc *sc;
    514 	struct wsdisplay_cursor *p;
    515 {
    516 #define	cc (&sc->sc_cursor)
    517 	int v, index, count;
    518 	u_int32_t csr;
    519 
    520 	v = p->which;
    521 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    522 		index = p->cmap.index;
    523 		count = p->cmap.count;
    524 
    525 		if (index >= 2 || index + count > 2)
    526 			return (EINVAL);
    527 		if (!useracc(p->cmap.red, count, B_READ) ||
    528 		    !useracc(p->cmap.green, count, B_READ) ||
    529 		    !useracc(p->cmap.blue, count, B_READ))
    530 			return (EFAULT);
    531 
    532 		copyin(p->cmap.red, &cc->cc_color[index], count);
    533 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    534 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    535 
    536 		ims332_load_curcmap(sc);
    537 	}
    538 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    539 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    540 			return (EINVAL);
    541 		count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
    542 		if (!useracc(p->image, count, B_READ) ||
    543 		    !useracc(p->mask, count, B_READ))
    544 			return (EFAULT);
    545 		cc->cc_size = p->size;
    546 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    547 		copyin(p->image, cc->cc_image, count);
    548 		copyin(p->mask, &cc->cc_image[CURSOR_MAX_SIZE], count);
    549 
    550 		ims332_load_curshape(sc);
    551 	}
    552 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    553 		cc->cc_hot = p->hot;
    554 		csr = ims332_read_reg(IMS332_REG_CSR_A);
    555 		if (p->enable)
    556 			csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    557 		else
    558 			csr |= IMS332_CSR_A_DISABLE_CURSOR;
    559 		ims332_write_reg(IMS332_REG_CSR_A, csr);
    560 	}
    561 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    562 		set_curpos(sc, &p->pos);
    563 		ims332_set_curpos(sc);
    564 	}
    565 
    566 	return (0);
    567 #undef cc
    568 }
    569 
    570 static int
    571 get_cursor(sc, p)
    572 	struct xcfb_softc *sc;
    573 	struct wsdisplay_cursor *p;
    574 {
    575 	return (ENOTTY); /* XXX */
    576 }
    577 
    578 static void
    579 set_curpos(sc, curpos)
    580 	struct xcfb_softc *sc;
    581 	struct wsdisplay_curpos *curpos;
    582 {
    583 	struct fb_devconfig *dc = sc->sc_dc;
    584 	int x = curpos->x, y = curpos->y;
    585 
    586 	if (y < 0)
    587 		y = 0;
    588 	else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
    589 		y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
    590 	if (x < 0)
    591 		x = 0;
    592 	else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
    593 		x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
    594 	sc->sc_cursor.cc_pos.x = x;
    595 	sc->sc_cursor.cc_pos.y = y;
    596 }
    597 
    598 void
    599 ims332_loadcmap(cm)
    600 	struct hwcmap *cm;
    601 {
    602 	int i;
    603 	u_int32_t rgb;
    604 
    605 	for (i = 0; i < CMAP_SIZE; i++) {
    606 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    607 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    608 	}
    609 }
    610 
    611 void
    612 ims332_set_curpos(sc)
    613 	struct xcfb_softc *sc;
    614 {
    615 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    616 	u_int32_t pos;
    617 
    618 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    619 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    620 }
    621 
    622 void
    623 ims332_load_curcmap(sc)
    624 	struct xcfb_softc *sc;
    625 {
    626 	u_int8_t *cp = sc->sc_cursor.cc_color;
    627 	u_int32_t rgb;
    628 
    629 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    630 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, rgb);
    631 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    632 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    633 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    634 }
    635 
    636 void
    637 ims332_load_curshape(sc)
    638 	struct xcfb_softc *sc;
    639 {
    640 	int i;
    641 	u_int16_t *word;
    642 
    643 	word = (u_int16_t *)sc->sc_cursor.cc_image;
    644 	for (i = 0; i < sizeof(sc->sc_cursor.cc_image)/sizeof(u_int16_t); i++)
    645 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, *word++);
    646 }
    647 
    648 u_int32_t
    649 ims332_read_reg(regno)
    650 	int regno;
    651 {
    652 	caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
    653 	caddr_t rptr = (caddr_t)IMS332_RPTR + (regno << 4);
    654 	u_int v0, v1;
    655 
    656 	v1 = *(volatile u_int32_t *)imsreg;
    657 	v0 = *(volatile u_int16_t *)rptr;
    658 	return (v1 & 0xff00) << 8 | v0;
    659 }
    660 
    661 void
    662 ims332_write_reg(regno, val)
    663 	int regno;
    664 	u_int32_t val;
    665 {
    666 	caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
    667 	caddr_t wptr = (caddr_t)IMS332_WPTR + (regno << 4);
    668 
    669 	*(volatile u_int32_t *)imsreg = (val & 0xff0000) >> 8;
    670 	*(volatile u_int16_t *)wptr = val;
    671 }
    672