Home | History | Annotate | Line # | Download | only in sbus
zx.c revision 1.17.12.1
      1 /*	$NetBSD: zx.c,v 1.17.12.1 2009/04/15 20:48:11 snj Exp $	*/
      2 
      3 /*
      4  *  Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  *  All rights reserved.
      6  *
      7  *  This code is derived from software contributed to The NetBSD Foundation
      8  *  by Andrew Doran.
      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  *  3. All advertising materials mentioning features or use of this software
     19  *     must display the following acknowledgement:
     20  *         This product includes software developed by the NetBSD
     21  *         Foundation, Inc. and its contributors.
     22  *  4. Neither the name of The NetBSD Foundation nor the names of its
     23  *     contributors may be used to endorse or promote products derived
     24  *     from this software without specific prior written permission.
     25  *
     26  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  *  POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Driver for the Sun ZX display adapter.  This would be called 'leo', but
     41  * NetBSD/amiga already has a driver by that name.  The XFree86 and Linux
     42  * drivers were used as "living documentation" when writing this; thanks
     43  * to the authors.
     44  *
     45  * Issues (which can be solved with wscons, happily enough):
     46  *
     47  * o There is lots of unnecessary mucking about rasops in here, primarily
     48  *   to appease the sparc fb code.
     49  *
     50  * o RASTERCONSOLE is required.  X needs the board set up correctly, and
     51  *   that's difficult to reconcile with using the PROM for output.
     52  */
     53 
     54 #include <sys/cdefs.h>
     55 __KERNEL_RCSID(0, "$NetBSD: zx.c,v 1.17.12.1 2009/04/15 20:48:11 snj Exp $");
     56 
     57 #include <sys/param.h>
     58 #include <sys/systm.h>
     59 #include <sys/device.h>
     60 #include <sys/ioctl.h>
     61 #include <sys/malloc.h>
     62 #include <sys/mman.h>
     63 #include <sys/tty.h>
     64 #include <sys/conf.h>
     65 #include <sys/syslog.h>
     66 #include <sys/buf.h>
     67 
     68 #include <machine/bus.h>
     69 #include <machine/autoconf.h>
     70 
     71 #include <uvm/uvm_extern.h>
     72 
     73 #include <dev/sun/fbio.h>
     74 #include <dev/sun/fbvar.h>
     75 
     76 #include <dev/sbus/zxreg.h>
     77 #include <dev/sbus/zxvar.h>
     78 #include <dev/sbus/sbusvar.h>
     79 
     80 #include <dev/wscons/wsconsio.h>
     81 
     82 #ifndef RASTERCONSOLE
     83 #error Sorry, this driver needs the RASTERCONSOLE option
     84 #endif
     85 
     86 #define	ZX_STD_ROP	(ZX_ROP_NEW | ZX_ATTR_WE_ENABLE | \
     87     ZX_ATTR_OE_ENABLE | ZX_ATTR_FORCE_WID)
     88 
     89 void	zx_attach(struct device *, struct device *, void *);
     90 int	zx_match(struct device *, struct cfdata *, void *);
     91 
     92 void	zx_blank(struct device *);
     93 int	zx_cmap_put(struct zx_softc *);
     94 void	zx_copyrect(struct rasops_info *, int, int, int, int, int, int);
     95 int	zx_cross_loadwid(struct zx_softc *, u_int, u_int, u_int);
     96 int	zx_cross_wait(struct zx_softc *);
     97 void	zx_fillrect(struct rasops_info *, int, int, int, int, long, int);
     98 int	zx_intr(void *);
     99 void	zx_reset(struct zx_softc *);
    100 void	zx_unblank(struct device *);
    101 
    102 void	zx_cursor_blank(struct zx_softc *);
    103 void	zx_cursor_color(struct zx_softc *);
    104 void	zx_cursor_move(struct zx_softc *);
    105 void	zx_cursor_set(struct zx_softc *);
    106 void	zx_cursor_unblank(struct zx_softc *);
    107 
    108 void	zx_copycols(void *, int, int, int, int);
    109 void	zx_copyrows(void *, int, int, int);
    110 void	zx_cursor(void *, int, int, int);
    111 void	zx_do_cursor(struct rasops_info *);
    112 void	zx_erasecols(void *, int, int, int, long);
    113 void	zx_eraserows(void *, int, int, long);
    114 void	zx_putchar(void *, int, int, u_int, long);
    115 
    116 struct zx_mmo {
    117 	off_t	mo_va;
    118 	off_t	mo_pa;
    119 	off_t	mo_size;
    120 } static const zx_mmo[] = {
    121 	{ ZX_FB0_VOFF,		ZX_OFF_SS0,		0x00800000 },
    122 	{ ZX_LC0_VOFF,		ZX_OFF_LC_SS0_USR,	0x00001000 },
    123 	{ ZX_LD0_VOFF,		ZX_OFF_LD_SS0,		0x00001000 },
    124 	{ ZX_LX0_CURSOR_VOFF,	ZX_OFF_LX_CURSOR,	0x00001000 },
    125 	{ ZX_FB1_VOFF,		ZX_OFF_SS1,		0x00800000 },
    126 	{ ZX_LC1_VOFF,		ZX_OFF_LC_SS1_USR,	0x00001000 },
    127 	{ ZX_LD1_VOFF,		ZX_OFF_LD_SS1,		0x00001000 },
    128 	{ ZX_LX_KRN_VOFF,	ZX_OFF_LX_CROSS,	0x00001000 },
    129 	{ ZX_LC0_KRN_VOFF,	ZX_OFF_LC_SS0_KRN,	0x00001000 },
    130 	{ ZX_LC1_KRN_VOFF,	ZX_OFF_LC_SS1_KRN,	0x00001000 },
    131 	{ ZX_LD_GBL_VOFF,	ZX_OFF_LD_GBL,		0x00001000 },
    132 };
    133 
    134 CFATTACH_DECL(zx, sizeof(struct zx_softc),
    135     zx_match, zx_attach, NULL, NULL);
    136 
    137 extern struct cfdriver zx_cd;
    138 
    139 dev_type_open(zxopen);
    140 dev_type_close(zxclose);
    141 dev_type_ioctl(zxioctl);
    142 dev_type_mmap(zxmmap);
    143 
    144 static struct fbdriver zx_fbdriver = {
    145 	zx_unblank, zxopen, zxclose, zxioctl, nopoll, zxmmap
    146 };
    147 
    148 int
    149 zx_match(struct device *parent, struct cfdata *cf, void *aux)
    150 {
    151 	struct sbus_attach_args *sa;
    152 
    153 	sa = (struct sbus_attach_args *)aux;
    154 
    155 	return (strcmp(sa->sa_name, "SUNW,leo") == 0);
    156 }
    157 
    158 void
    159 zx_attach(struct device *parent, struct device *self, void *args)
    160 {
    161 	struct zx_softc *sc;
    162 	struct sbus_attach_args *sa;
    163 	bus_space_handle_t bh;
    164 	bus_space_tag_t bt;
    165 	struct fbdevice *fb;
    166 	struct rasops_info *ri;
    167 	int isconsole;
    168 
    169 	sc = (struct zx_softc *)self;
    170 	sa = args;
    171 	fb = &sc->sc_fb;
    172 	ri = &fb->fb_rinfo;
    173 	bt = sa->sa_bustag;
    174 	sc->sc_bt = bt;
    175 
    176 	sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
    177 
    178 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_SS0,
    179 	    0x800000, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    180 		printf("%s: can't map bits\n", self->dv_xname);
    181 		return;
    182 	}
    183 	fb->fb_pixels = (caddr_t)bus_space_vaddr(bt, bh);
    184 	sc->sc_pixels = (u_int32_t *)fb->fb_pixels;
    185 
    186 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LC_SS0_USR,
    187 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    188 		printf("%s: can't map zc\n", self->dv_xname);
    189 		return;
    190 	}
    191 	sc->sc_bhzc = bh;
    192 
    193 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS0,
    194 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    195 		printf("%s: can't map ld/ss0\n", self->dv_xname);
    196 		return;
    197 	}
    198 	sc->sc_bhzdss0 = bh;
    199 
    200 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS1,
    201 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    202 		printf("%s: can't map ld/ss1\n", self->dv_xname);
    203 		return;
    204 	}
    205 	sc->sc_bhzdss1 = bh;
    206 
    207 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CROSS,
    208 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    209 		printf("%s: can't map zx\n", self->dv_xname);
    210 		return;
    211 	}
    212 	sc->sc_bhzx = bh;
    213 
    214 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CURSOR,
    215 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    216 		printf("%s: can't map zcu\n", self->dv_xname);
    217 		return;
    218 	}
    219 	sc->sc_bhzcu = bh;
    220 
    221 	fb->fb_driver = &zx_fbdriver;
    222 	fb->fb_device = &sc->sc_dv;
    223 	fb->fb_flags = device_cfdata(&sc->sc_dv)->cf_flags & FB_USERMASK;
    224 	fb->fb_pfour = NULL;
    225 	fb->fb_linebytes = 8192;
    226 
    227 	fb_setsize_obp(fb, 32, 1280, 1024, sa->sa_node);
    228 
    229 	fb->fb_type.fb_cmsize = 256;
    230 	fb->fb_type.fb_depth = 32;
    231 	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
    232 	fb->fb_type.fb_type = FBTYPE_SUNLEO;
    233 
    234 	printf(": %d x %d", fb->fb_type.fb_width, fb->fb_type.fb_height);
    235 	isconsole = fb_is_console(sa->sa_node);
    236 	if (isconsole)
    237 		printf(" (console)");
    238 	printf("\n");
    239 
    240 	sbus_establish(&sc->sc_sd, &sc->sc_dv);
    241 	if (sa->sa_nintr != 0)
    242 		bus_intr_establish(bt, sa->sa_pri, IPL_NONE, zx_intr, sc);
    243 
    244 	sc->sc_cmap = malloc(768, M_DEVBUF, M_NOWAIT);
    245 	fb_attach(&sc->sc_fb, isconsole);
    246 	zx_reset(sc);
    247 
    248 	/*
    249 	 * Attach to rcons.  XXX At this point, rasops_do_cursor() will be
    250 	 * called before we get our hooks in place.  So, we mask off access
    251 	 * to the framebuffer until it's done.
    252 	 */
    253 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 1);
    254 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 0);
    255 
    256 	fbrcons_init(&sc->sc_fb);
    257 
    258 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0);
    259 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk, 0xffffffff);
    260 
    261 	ri->ri_hw = sc;
    262 	ri->ri_do_cursor = zx_do_cursor;
    263 	ri->ri_ops.copycols = zx_copycols;
    264 	ri->ri_ops.copyrows = zx_copyrows;
    265 	ri->ri_ops.erasecols = zx_erasecols;
    266 	ri->ri_ops.eraserows = zx_eraserows;
    267 	ri->ri_ops.putchar = zx_putchar;
    268 
    269 	sc->sc_fontw = ri->ri_font->fontwidth;
    270 	sc->sc_fonth = ri->ri_font->fontheight;
    271 }
    272 
    273 int
    274 zxopen(dev_t dev, int flags, int mode, struct lwp *l)
    275 {
    276 
    277 	if (device_lookup(&zx_cd, minor(dev)) == NULL)
    278 		return (ENXIO);
    279 	return (0);
    280 }
    281 
    282 int
    283 zxclose(dev_t dev, int flags, int mode, struct lwp *l)
    284 {
    285 	struct zx_softc *sc;
    286 
    287 	sc = (struct zx_softc *)device_lookup(&zx_cd, minor(dev));
    288 
    289 	zx_reset(sc);
    290 	zx_cursor_blank(sc);
    291 	return (0);
    292 }
    293 
    294 int
    295 zxioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct lwp *l)
    296 {
    297 	struct zx_softc *sc;
    298 	struct fbcmap *cm;
    299 	struct fbcursor *cu;
    300 	uint32_t curbits[2][32];
    301 	int rv, v, count, i;
    302 
    303 	sc = zx_cd.cd_devs[minor(dev)];
    304 
    305 	switch (cmd) {
    306 	case FBIOGTYPE:
    307 		*(struct fbtype *)data = sc->sc_fb.fb_type;
    308 		break;
    309 
    310 	case FBIOGATTR:
    311 #define fba ((struct fbgattr *)data)
    312 		fba->real_type = sc->sc_fb.fb_type.fb_type;
    313 		fba->owner = 0;		/* XXX ??? */
    314 		fba->fbtype = sc->sc_fb.fb_type;
    315 		fba->sattr.flags = 0;
    316 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
    317 		fba->sattr.dev_specific[0] = -1;
    318 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
    319 		fba->emu_types[1] = -1;
    320 		fba->emu_types[2] = -1;
    321 #undef fba
    322 		break;
    323 
    324 	case FBIOGVIDEO:
    325 		*(int *)data = ((sc->sc_flags & ZX_BLANKED) != 0);
    326 		break;
    327 
    328 	case FBIOSVIDEO:
    329 		if (*(int *)data)
    330 			zx_unblank(&sc->sc_dv);
    331 		else
    332 			zx_blank(&sc->sc_dv);
    333 		break;
    334 
    335 	case FBIOGETCMAP:
    336 		cm = (struct fbcmap *)data;
    337 		if (cm->index > 256 || cm->count > 256 - cm->index)
    338 			return (EINVAL);
    339 		rv = copyout(sc->sc_cmap + cm->index, cm->red, cm->count);
    340 		if (rv == 0)
    341 			rv = copyout(sc->sc_cmap + 256 + cm->index, cm->green,
    342 			    cm->count);
    343 		if (rv == 0)
    344 			rv = copyout(sc->sc_cmap + 512 + cm->index, cm->blue,
    345 			    cm->count);
    346 		return (rv);
    347 
    348 	case FBIOPUTCMAP:
    349 		cm = (struct fbcmap *)data;
    350 		if (cm->index > 256 || cm->count > 256 - cm->index)
    351 			return (EINVAL);
    352 		rv = copyin(cm->red, sc->sc_cmap + cm->index, cm->count);
    353 		if (rv == 0)
    354 			rv = copyin(cm->green, sc->sc_cmap + 256 + cm->index,
    355 			    cm->count);
    356 		if (rv == 0)
    357 			rv = copyin(cm->blue, sc->sc_cmap + 512 + cm->index,
    358 			    cm->count);
    359 		zx_cmap_put(sc);
    360 		return (rv);
    361 
    362 	case FBIOGCURPOS:
    363 		*(struct fbcurpos *)data = sc->sc_curpos;
    364 		break;
    365 
    366 	case FBIOSCURPOS:
    367 		sc->sc_curpos = *(struct fbcurpos *)data;
    368 		zx_cursor_move(sc);
    369 		break;
    370 
    371 	case FBIOGCURMAX:
    372 		((struct fbcurpos *)data)->x = 32;
    373 		((struct fbcurpos *)data)->y = 32;
    374 		break;
    375 
    376 	case FBIOSCURSOR:
    377 		cu = (struct fbcursor *)data;
    378 		v = cu->set;
    379 
    380 		if ((v & FB_CUR_SETSHAPE) != 0) {
    381 			if ((u_int)cu->size.x > 32 || (u_int)cu->size.y > 32)
    382 				return (EINVAL);
    383 			count = cu->size.y * 4;
    384 			rv = copyin(cu->mask, curbits[0], count);
    385 			if (rv)
    386 				return rv;
    387 			rv = copyin(cu->image, curbits[1], count);
    388 			if (rv)
    389 				return rv;
    390 		}
    391 		if ((v & FB_CUR_SETCUR) != 0) {
    392 			if (cu->enable)
    393 				zx_cursor_unblank(sc);
    394 			else
    395 				zx_cursor_blank(sc);
    396 		}
    397 		if ((v & (FB_CUR_SETPOS | FB_CUR_SETHOT)) != 0) {
    398 			if ((v & FB_CUR_SETPOS) != 0)
    399 				sc->sc_curpos = cu->pos;
    400 			if ((v & FB_CUR_SETHOT) != 0)
    401 				sc->sc_curhot = cu->hot;
    402 			zx_cursor_move(sc);
    403 		}
    404 		if ((v & FB_CUR_SETCMAP) != 0) {
    405 			if (cu->cmap.index > 2 ||
    406 			    cu->cmap.count > 2 - cu->cmap.index)
    407 				return (EINVAL);
    408 			for (i = 0; i < cu->cmap.count; i++) {
    409 				if ((v = fubyte(&cu->cmap.red[i])) < 0)
    410 					return (EFAULT);
    411 				sc->sc_curcmap[i + cu->cmap.index + 0] = v;
    412 				if ((v = fubyte(&cu->cmap.green[i])) < 0)
    413 					return (EFAULT);
    414 				sc->sc_curcmap[i + cu->cmap.index + 2] = v;
    415 				if ((v = fubyte(&cu->cmap.blue[i])) < 0)
    416 					return (EFAULT);
    417 				sc->sc_curcmap[i + cu->cmap.index + 4] = v;
    418 			}
    419 			zx_cursor_color(sc);
    420 		}
    421 		if ((v & FB_CUR_SETSHAPE) != 0) {
    422 			sc->sc_cursize = cu->size;
    423 			count = cu->size.y * 4;
    424 			memset(sc->sc_curbits, 0, sizeof(sc->sc_curbits));
    425 			memcpy(sc->sc_curbits[0], curbits[0], count);
    426 			memcpy(sc->sc_curbits[1], curbits[1], count);
    427 			zx_cursor_set(sc);
    428 		}
    429 		break;
    430 
    431 	case FBIOGCURSOR:
    432 		cu = (struct fbcursor *)data;
    433 
    434 		cu->set = FB_CUR_SETALL;
    435 		cu->enable = ((sc->sc_flags & ZX_CURSOR) != 0);
    436 		cu->pos = sc->sc_curpos;
    437 		cu->hot = sc->sc_curhot;
    438 		cu->size = sc->sc_cursize;
    439 
    440 		if (cu->image != NULL) {
    441 			count = sc->sc_cursize.y * 4;
    442 			rv = copyout(sc->sc_curbits[1], cu->image, count);
    443 			if (rv)
    444 				return (rv);
    445 			rv = copyout(sc->sc_curbits[0], cu->mask, count);
    446 			if (rv)
    447 				return (rv);
    448 		}
    449 		if (cu->cmap.red != NULL) {
    450 			if (cu->cmap.index > 2 ||
    451 			    cu->cmap.count > 2 - cu->cmap.index)
    452 				return (EINVAL);
    453 			for (i = 0; i < cu->cmap.count; i++) {
    454 				v = sc->sc_curcmap[i + cu->cmap.index + 0];
    455 				if (subyte(&cu->cmap.red[i], v))
    456 					return (EFAULT);
    457 				v = sc->sc_curcmap[i + cu->cmap.index + 2];
    458 				if (subyte(&cu->cmap.green[i], v))
    459 					return (EFAULT);
    460 				v = sc->sc_curcmap[i + cu->cmap.index + 4];
    461 				if (subyte(&cu->cmap.blue[i], v))
    462 					return (EFAULT);
    463 			}
    464 		} else {
    465 			cu->cmap.index = 0;
    466 			cu->cmap.count = 2;
    467 		}
    468 		break;
    469 
    470 	default:
    471 #ifdef DEBUG
    472 		log(LOG_NOTICE, "zxioctl(0x%lx) (%s[%d])\n", cmd,
    473 		    p->p_comm, p->p_pid);
    474 #endif
    475 		return (ENOTTY);
    476 	}
    477 
    478 	return (0);
    479 }
    480 
    481 int
    482 zx_intr(void *cookie)
    483 {
    484 
    485 	return (1);
    486 }
    487 
    488 void
    489 zx_reset(struct zx_softc *sc)
    490 {
    491 	struct fbtype *fbt;
    492 	u_int i;
    493 
    494 	fbt = &sc->sc_fb.fb_type;
    495 
    496 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 0, 0x2c0);
    497 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 1, 0x30);
    498 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 2, 0x20);
    499 	zx_cross_loadwid(sc, ZX_WID_DBL_24, 1, 0x30);
    500 
    501 	i = bus_space_read_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc);
    502 	i |= ZX_SS1_MISC_ENABLE;
    503 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc, i);
    504 
    505 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wid, 0xffffffff);
    506 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_widclip, 0);
    507 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wmask, 0xffff);
    508 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmin, 0);
    509 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmax,
    510 	    (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 16));
    511 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 0);
    512 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_planemask, 0xff000000);
    513 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
    514 
    515 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent,
    516 	    (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 11));
    517 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_addrspace,
    518 	    ZX_ADDRSPC_FONT_OBGR);
    519 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0);
    520 
    521 	for (i = 0; i < 256; i++) {
    522 		sc->sc_cmap[i] = rasops_cmap[i * 3];
    523 		sc->sc_cmap[i + 256] = rasops_cmap[i * 3 + 1];
    524 		sc->sc_cmap[i + 512] = rasops_cmap[i * 3 + 2];
    525 	}
    526 
    527 	zx_cmap_put(sc);
    528 }
    529 
    530 int
    531 zx_cross_wait(struct zx_softc *sc)
    532 {
    533 	int i;
    534 
    535 	for (i = 300000; i != 0; i--) {
    536 		if ((bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) &
    537 		    ZX_CROSS_CSR_PROGRESS) == 0)
    538 			break;
    539 		DELAY(1);
    540 	}
    541 
    542 	if (i == 0)
    543 		printf("zx_cross_wait: timed out\n");
    544 
    545 	return (i);
    546 }
    547 
    548 int
    549 zx_cross_loadwid(struct zx_softc *sc, u_int type, u_int index, u_int value)
    550 {
    551 	u_int tmp = 0;
    552 
    553 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID);
    554 
    555 	if (zx_cross_wait(sc))
    556 		return (1);
    557 
    558 	if (type == ZX_WID_DBL_8)
    559 		tmp = (index & 0x0f) + 0x40;
    560 	else if (type == ZX_WID_DBL_24)
    561 		tmp = index & 0x3f;
    562 
    563 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 0x5800 + tmp);
    564 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, value);
    565 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID);
    566 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
    567 	    ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2);
    568 
    569 	return (0);
    570 }
    571 
    572 int
    573 zx_cmap_put(struct zx_softc *sc)
    574 {
    575 	const u_char *b;
    576 	u_int i, t;
    577 
    578 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0);
    579 	if (zx_cross_wait(sc))
    580 		return (1);
    581 
    582 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type,
    583 	    ZX_CROSS_TYPE_CLUTDATA);
    584 
    585 	for (i = 0, b = sc->sc_cmap; i < 256; i++) {
    586 		t = b[i];
    587 		t |= b[i + 256] << 8;
    588 		t |= b[i + 512] << 16;
    589 		bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, t);
    590 	}
    591 
    592 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0);
    593 	i = bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr);
    594 	i = i | ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2;
    595 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, i);
    596 	return (0);
    597 }
    598 
    599 void
    600 zx_cursor_move(struct zx_softc *sc)
    601 {
    602 	int sx, sy, x, y;
    603 
    604 	x = sc->sc_curpos.x - sc->sc_curhot.x;
    605 	y = sc->sc_curpos.y - sc->sc_curhot.y;
    606 
    607 	if (x < 0) {
    608 		sx = min(-x, 32);
    609 		x = 0;
    610 	} else
    611 		sx = 0;
    612 
    613 	if (y < 0) {
    614 		sy = min(-y, 32);
    615 		y = 0;
    616 	} else
    617 		sy = 0;
    618 
    619 	if (sx != sc->sc_shiftx || sy != sc->sc_shifty) {
    620 		sc->sc_shiftx = sx;
    621 		sc->sc_shifty = sy;
    622 		zx_cursor_set(sc);
    623 	}
    624 
    625 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_sxy,
    626 	    ((y & 0x7ff) << 11) | (x & 0x7ff));
    627 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    628 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x30);
    629 
    630 	/* XXX Necessary? */
    631 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    632 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
    633 }
    634 
    635 void
    636 zx_cursor_set(struct zx_softc *sc)
    637 {
    638 	int i, j, data;
    639 
    640 	if ((sc->sc_flags & ZX_CURSOR) != 0)
    641 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    642 		    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) &
    643 		    ~0x80);
    644 
    645 	for (j = 0; j < 2; j++) {
    646 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x20 << j);
    647 
    648 		for (i = sc->sc_shifty; i < 32; i++) {
    649 			data = sc->sc_curbits[j][i];
    650 			bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data,
    651 			    data >> sc->sc_shiftx);
    652 		}
    653 		for (i = sc->sc_shifty; i != 0; i--)
    654 			bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 0);
    655 	}
    656 
    657 	if ((sc->sc_flags & ZX_CURSOR) != 0)
    658 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    659 		    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
    660 }
    661 
    662 void
    663 zx_cursor_blank(struct zx_softc *sc)
    664 {
    665 
    666 	sc->sc_flags &= ~ZX_CURSOR;
    667 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    668 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & ~0x80);
    669 }
    670 
    671 void
    672 zx_cursor_unblank(struct zx_softc *sc)
    673 {
    674 
    675 	sc->sc_flags |= ZX_CURSOR;
    676 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    677 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
    678 }
    679 
    680 void
    681 zx_cursor_color(struct zx_softc *sc)
    682 {
    683 	u_int8_t tmp;
    684 
    685 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x50);
    686 
    687 	tmp = sc->sc_curcmap[0] | (sc->sc_curcmap[2] << 8) |
    688 	    (sc->sc_curcmap[4] << 16);
    689 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp);
    690 
    691 	tmp = sc->sc_curcmap[1] | (sc->sc_curcmap[3] << 8) |
    692 	    (sc->sc_curcmap[5] << 16);
    693 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, sc->sc_curcmap[1]);
    694 
    695 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
    696 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x03);
    697 }
    698 
    699 void
    700 zx_blank(struct device *dv)
    701 {
    702 	struct zx_softc *sc;
    703 
    704 	sc = (struct zx_softc *)dv;
    705 
    706 	if ((sc->sc_flags & ZX_BLANKED) != 0)
    707 		return;
    708 	sc->sc_flags |= ZX_BLANKED;
    709 
    710 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO);
    711 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
    712 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) &
    713 	    ~ZX_CROSS_CSR_ENABLE);
    714 }
    715 
    716 void
    717 zx_unblank(struct device *dv)
    718 {
    719 	struct zx_softc *sc;
    720 
    721 	sc = (struct zx_softc *)dv;
    722 
    723 	if ((sc->sc_flags & ZX_BLANKED) == 0)
    724 		return;
    725 	sc->sc_flags &= ~ZX_BLANKED;
    726 
    727 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO);
    728 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
    729 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) |
    730 	    ZX_CROSS_CSR_ENABLE);
    731 }
    732 
    733 paddr_t
    734 zxmmap(dev_t dev, off_t off, int prot)
    735 {
    736 	struct zx_softc *sc;
    737 	const struct zx_mmo *mm, *mmmax;
    738 
    739 	sc = device_lookup(&zx_cd, minor(dev));
    740 	off = trunc_page(off);
    741 	mm = zx_mmo;
    742 	mmmax = mm + sizeof(zx_mmo) / sizeof(zx_mmo[0]);
    743 
    744 	for (; mm < mmmax; mm++)
    745 		if (off >= mm->mo_va && off < mm->mo_va + mm->mo_size) {
    746 			off = off - mm->mo_va + mm->mo_pa;
    747 			return (bus_space_mmap(sc->sc_bt, sc->sc_paddr,
    748 			    off, prot, BUS_SPACE_MAP_LINEAR));
    749 		}
    750 
    751 	return (-1);
    752 }
    753 
    754 void
    755 zx_fillrect(struct rasops_info *ri, int x, int y, int w, int h, long attr,
    756 	    int rop)
    757 {
    758 	struct zx_softc *sc;
    759 	int fg, bg;
    760 
    761 	sc = ri->ri_hw;
    762 
    763 	rasops_unpack_attr(attr, &fg, &bg, NULL);
    764 	x = x * sc->sc_fontw + ri->ri_xorigin;
    765 	y = y * sc->sc_fonth + ri->ri_yorigin;
    766 	w = sc->sc_fontw * w - 1;
    767 	h = sc->sc_fonth * h - 1;
    768 
    769 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
    770 	    ZX_CSR_BLT_BUSY) != 0)
    771 		;
    772 
    773 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, rop);
    774 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg,
    775 	    (bg & 7) ? 0x00000000 : 0xff000000);
    776 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent, w | (h << 11));
    777 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fill,
    778 	    x | (y << 11) | 0x80000000);
    779 }
    780 
    781 void
    782 zx_copyrect(struct rasops_info *ri, int sx, int sy, int dx, int dy, int w,
    783 	    int h)
    784 {
    785 	struct zx_softc *sc;
    786 	int dir;
    787 
    788 	sc = ri->ri_hw;
    789 
    790 	sx = sx * sc->sc_fontw + ri->ri_xorigin;
    791 	sy = sy * sc->sc_fonth + ri->ri_yorigin;
    792 	dx = dx * sc->sc_fontw + ri->ri_xorigin;
    793 	dy = dy * sc->sc_fonth + ri->ri_yorigin;
    794 	w = w * sc->sc_fontw - 1;
    795 	h = h * sc->sc_fonth - 1;
    796 
    797 	if (sy < dy || sx < dx) {
    798 		dir = 0x80000000;
    799 		sx += w;
    800 		sy += h;
    801 		dx += w;
    802 		dy += h;
    803 	} else
    804 		dir = 0;
    805 
    806 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
    807 	    ZX_CSR_BLT_BUSY) != 0)
    808 		;
    809 
    810 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
    811 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent,
    812 	    w | (h << 11) | dir);
    813 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_src, sx | (sy << 11));
    814 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_copy, dx | (dy << 11));
    815 }
    816 
    817 void
    818 zx_do_cursor(struct rasops_info *ri)
    819 {
    820 
    821 	zx_fillrect(ri, ri->ri_ccol, ri->ri_crow, 1, 1, 0,
    822 	    ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE |
    823 	    ZX_ATTR_FORCE_WID);
    824 }
    825 
    826 void
    827 zx_erasecols(void *cookie, int row, int col, int num, long attr)
    828 {
    829 	struct rasops_info *ri;
    830 
    831 	ri = (struct rasops_info *)cookie;
    832 
    833 	zx_fillrect(ri, col, row, num, 1, attr, ZX_STD_ROP);
    834 }
    835 
    836 void
    837 zx_eraserows(void *cookie, int row, int num, long attr)
    838 {
    839 	struct rasops_info *ri;
    840 
    841 	ri = (struct rasops_info *)cookie;
    842 
    843 	zx_fillrect(ri, 0, row, ri->ri_cols, num, attr, ZX_STD_ROP);
    844 }
    845 
    846 void
    847 zx_copyrows(void *cookie, int src, int dst, int num)
    848 {
    849 	struct rasops_info *ri;
    850 
    851 	ri = (struct rasops_info *)cookie;
    852 
    853 	zx_copyrect(ri, 0, src, 0, dst, ri->ri_cols, num);
    854 }
    855 
    856 void
    857 zx_copycols(void *cookie, int row, int src, int dst, int num)
    858 {
    859 	struct rasops_info *ri;
    860 
    861 	ri = (struct rasops_info *)cookie;
    862 
    863 	zx_copyrect(ri, src, row, dst, row, num, 1);
    864 }
    865 
    866 void
    867 zx_putchar(void *cookie, int row, int col, u_int uc, long attr)
    868 {
    869 	struct rasops_info *ri;
    870 	struct zx_softc *sc;
    871 	struct wsdisplay_font *font;
    872 	volatile u_int32_t *dp;
    873 	u_int8_t *fb;
    874 	int fs, i, fg, bg, ul;
    875 
    876 	ri = (struct rasops_info *)cookie;
    877 
    878 	if (uc == ' ') {
    879 		zx_fillrect(ri, col, row, 1, 1, attr, ZX_STD_ROP);
    880 		return;
    881 	}
    882 
    883 	sc = (struct zx_softc *)ri->ri_hw;
    884 	font = ri->ri_font;
    885 
    886 	dp = (volatile u_int32_t *)sc->sc_pixels +
    887 	    ((row * sc->sc_fonth + ri->ri_yorigin) << 11) +
    888 	    (col * sc->sc_fontw + ri->ri_xorigin);
    889 	fb = (u_int8_t *)font->data + (uc - font->firstchar) *
    890 	    ri->ri_fontscale;
    891 	fs = font->stride;
    892 	rasops_unpack_attr(attr, &fg, &bg, &ul);
    893 
    894 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
    895 	    ZX_CSR_BLT_BUSY) != 0)
    896 		;
    897 
    898 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
    899 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg,
    900 	    (fg & 7) ? 0x00000000 : 0xff000000);
    901 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_bg,
    902 	    (bg & 7) ? 0x00000000 : 0xff000000);
    903 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk,
    904 	    0xffffffff << (32 - sc->sc_fontw));
    905 
    906 	if (sc->sc_fontw <= 8) {
    907 		for (i = sc->sc_fonth; i != 0; i--, dp += 2048) {
    908 			*dp = *fb << 24;
    909 			fb += fs;
    910 		}
    911 	} else {
    912 		for (i = sc->sc_fonth; i != 0; i--, dp += 2048) {
    913 			*dp = *((u_int16_t *)fb) << 16;
    914 			fb += fs;
    915 		}
    916 	}
    917 
    918 	if (ul) {
    919 		dp -= 4096;
    920 		*dp = 0xffffffff;
    921 	}
    922 }
    923