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