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