xref: /netbsd-src/sys/dev/sbus/zx.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: zx.c,v 1.47 2021/08/07 16:19:15 thorpej Exp $	*/
2ca0ac2c7Sad 
3ca0ac2c7Sad /*
4ca0ac2c7Sad  *  Copyright (c) 2002 The NetBSD Foundation, Inc.
5ca0ac2c7Sad  *  All rights reserved.
6ca0ac2c7Sad  *
7ca0ac2c7Sad  *  This code is derived from software contributed to The NetBSD Foundation
8ca0ac2c7Sad  *  by Andrew Doran.
9ca0ac2c7Sad  *
10ca0ac2c7Sad  *  Redistribution and use in source and binary forms, with or without
11ca0ac2c7Sad  *  modification, are permitted provided that the following conditions
12ca0ac2c7Sad  *  are met:
13ca0ac2c7Sad  *  1. Redistributions of source code must retain the above copyright
14ca0ac2c7Sad  *     notice, this list of conditions and the following disclaimer.
15ca0ac2c7Sad  *  2. Redistributions in binary form must reproduce the above copyright
16ca0ac2c7Sad  *     notice, this list of conditions and the following disclaimer in the
17ca0ac2c7Sad  *     documentation and/or other materials provided with the distribution.
18ca0ac2c7Sad  *
19ca0ac2c7Sad  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20ca0ac2c7Sad  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21ca0ac2c7Sad  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ca0ac2c7Sad  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23ca0ac2c7Sad  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ca0ac2c7Sad  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ca0ac2c7Sad  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ca0ac2c7Sad  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ca0ac2c7Sad  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ca0ac2c7Sad  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ca0ac2c7Sad  *  POSSIBILITY OF SUCH DAMAGE.
30ca0ac2c7Sad  */
31ca0ac2c7Sad 
32ca0ac2c7Sad /*
33ca0ac2c7Sad  * Driver for the Sun ZX display adapter.  This would be called 'leo', but
34ca0ac2c7Sad  * NetBSD/amiga already has a driver by that name.  The XFree86 and Linux
35ca0ac2c7Sad  * drivers were used as "living documentation" when writing this; thanks
36ca0ac2c7Sad  * to the authors.
37ca0ac2c7Sad  *
38ca0ac2c7Sad  * Issues (which can be solved with wscons, happily enough):
39ca0ac2c7Sad  *
40ca0ac2c7Sad  * o There is lots of unnecessary mucking about rasops in here, primarily
41ca0ac2c7Sad  *   to appease the sparc fb code.
42ca0ac2c7Sad  */
43ca0ac2c7Sad 
44ca0ac2c7Sad #include <sys/cdefs.h>
45*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: zx.c,v 1.47 2021/08/07 16:19:15 thorpej Exp $");
46ca0ac2c7Sad 
47ca0ac2c7Sad #include <sys/param.h>
48ca0ac2c7Sad #include <sys/systm.h>
49ca0ac2c7Sad #include <sys/device.h>
50ca0ac2c7Sad #include <sys/ioctl.h>
51ca0ac2c7Sad #include <sys/malloc.h>
52ca0ac2c7Sad #include <sys/mman.h>
53ca0ac2c7Sad #include <sys/tty.h>
54ca0ac2c7Sad #include <sys/conf.h>
55ca0ac2c7Sad #include <sys/syslog.h>
56ca0ac2c7Sad #include <sys/buf.h>
57a7e80793Suebayasi #ifdef DEBUG
58a7e80793Suebayasi /* for log(9) in zxioctl() */
59a7e80793Suebayasi #include <sys/lwp.h>
60a7e80793Suebayasi #include <sys/proc.h>
61a7e80793Suebayasi #endif
62ca0ac2c7Sad 
63a2a38285Sad #include <sys/bus.h>
64ca0ac2c7Sad #include <machine/autoconf.h>
65ca0ac2c7Sad 
66ca0ac2c7Sad #include <dev/sun/fbio.h>
67ca0ac2c7Sad #include <dev/sun/fbvar.h>
68ca0ac2c7Sad 
69c7d8ba24Smacallan #include "wsdisplay.h"
70c7d8ba24Smacallan #include <dev/wscons/wsconsio.h>
71c7d8ba24Smacallan #include <dev/wsfont/wsfont.h>
72c7d8ba24Smacallan #include <dev/rasops/rasops.h>
73c7d8ba24Smacallan #include <dev/wscons/wsdisplay_vconsvar.h>
74c7d8ba24Smacallan 
75c7d8ba24Smacallan #include "opt_wsemul.h"
76c7d8ba24Smacallan 
77ca0ac2c7Sad #include <dev/sbus/zxreg.h>
78ca0ac2c7Sad #include <dev/sbus/zxvar.h>
79ca0ac2c7Sad #include <dev/sbus/sbusvar.h>
80ca0ac2c7Sad 
81ca0ac2c7Sad #include <dev/wscons/wsconsio.h>
82ca0ac2c7Sad 
8308c90221Stsutsui #include "ioconf.h"
8408c90221Stsutsui 
85ca0ac2c7Sad #define	ZX_STD_ROP	(ZX_ROP_NEW | ZX_ATTR_WE_ENABLE | \
86ca0ac2c7Sad     ZX_ATTR_OE_ENABLE | ZX_ATTR_FORCE_WID)
87ca0ac2c7Sad 
88c7d8ba24Smacallan static void	zx_attach(device_t, device_t, void *);
89d16a259fScegger static int	zx_match(device_t, cfdata_t, void *);
90ca0ac2c7Sad 
91c7d8ba24Smacallan static void	zx_blank(device_t);
92c7d8ba24Smacallan static int	zx_cmap_put(struct zx_softc *);
93c7d8ba24Smacallan static void	zx_copyrect(struct zx_softc *, int, int, int, int, int, int);
94c7d8ba24Smacallan static int	zx_cross_loadwid(struct zx_softc *, u_int, u_int, u_int);
95c7d8ba24Smacallan static int	zx_cross_wait(struct zx_softc *);
96c7d8ba24Smacallan static void	zx_fillrect(struct zx_softc *, int, int, int, int, uint32_t, int);
97c7d8ba24Smacallan static int	zx_intr(void *);
98c7d8ba24Smacallan static void	zx_reset(struct zx_softc *);
99c7d8ba24Smacallan static void	zx_unblank(device_t);
100ca0ac2c7Sad 
101c7d8ba24Smacallan static void	zx_cursor_blank(struct zx_softc *);
102c7d8ba24Smacallan static void	zx_cursor_color(struct zx_softc *);
103c7d8ba24Smacallan static void	zx_cursor_move(struct zx_softc *);
104c7d8ba24Smacallan static void	zx_cursor_set(struct zx_softc *);
105c7d8ba24Smacallan static void	zx_cursor_unblank(struct zx_softc *);
106ca0ac2c7Sad 
107c7d8ba24Smacallan static void	zx_copycols(void *, int, int, int, int);
108c7d8ba24Smacallan static void	zx_copyrows(void *, int, int, int);
109c7d8ba24Smacallan static void	zx_do_cursor(void *, int, int, int);
110c7d8ba24Smacallan static void	zx_erasecols(void *, int, int, int, long);
111c7d8ba24Smacallan static void	zx_eraserows(void *, int, int, long);
112c7d8ba24Smacallan static void	zx_putchar(void *, int, int, u_int, long);
113ca0ac2c7Sad 
114ca0ac2c7Sad struct zx_mmo {
115ca0ac2c7Sad 	off_t	mo_va;
116ca0ac2c7Sad 	off_t	mo_pa;
117ca0ac2c7Sad 	off_t	mo_size;
118ca0ac2c7Sad } static const zx_mmo[] = {
119ca0ac2c7Sad 	{ ZX_FB0_VOFF,		ZX_OFF_SS0,		0x00800000 },
120ca0ac2c7Sad 	{ ZX_LC0_VOFF,		ZX_OFF_LC_SS0_USR,	0x00001000 },
121ca0ac2c7Sad 	{ ZX_LD0_VOFF,		ZX_OFF_LD_SS0,		0x00001000 },
122ca0ac2c7Sad 	{ ZX_LX0_CURSOR_VOFF,	ZX_OFF_LX_CURSOR,	0x00001000 },
123ca0ac2c7Sad 	{ ZX_FB1_VOFF,		ZX_OFF_SS1,		0x00800000 },
124ca0ac2c7Sad 	{ ZX_LC1_VOFF,		ZX_OFF_LC_SS1_USR,	0x00001000 },
125ca0ac2c7Sad 	{ ZX_LD1_VOFF,		ZX_OFF_LD_SS1,		0x00001000 },
126ca0ac2c7Sad 	{ ZX_LX_KRN_VOFF,	ZX_OFF_LX_CROSS,	0x00001000 },
127ca0ac2c7Sad 	{ ZX_LC0_KRN_VOFF,	ZX_OFF_LC_SS0_KRN,	0x00001000 },
128ca0ac2c7Sad 	{ ZX_LC1_KRN_VOFF,	ZX_OFF_LC_SS1_KRN,	0x00001000 },
129ca0ac2c7Sad 	{ ZX_LD_GBL_VOFF,	ZX_OFF_LD_GBL,		0x00001000 },
130ca0ac2c7Sad };
131ca0ac2c7Sad 
132c7d8ba24Smacallan CFATTACH_DECL_NEW(zx, sizeof(struct zx_softc),
133b75a007dSthorpej     zx_match, zx_attach, NULL, NULL);
134ca0ac2c7Sad 
135c7d8ba24Smacallan static dev_type_open(zxopen);
136c7d8ba24Smacallan static dev_type_close(zxclose);
137c7d8ba24Smacallan static dev_type_ioctl(zxioctl);
138c7d8ba24Smacallan static dev_type_mmap(zxmmap);
139ca0ac2c7Sad 
140ca0ac2c7Sad static struct fbdriver zx_fbdriver = {
141ca0ac2c7Sad 	zx_unblank, zxopen, zxclose, zxioctl, nopoll, zxmmap
142ca0ac2c7Sad };
143ca0ac2c7Sad 
144c7d8ba24Smacallan struct wsscreen_descr zx_defaultscreen = {
145c7d8ba24Smacallan 	"std",
146c7d8ba24Smacallan 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
147c7d8ba24Smacallan 		/* doesn't matter - you can't really have more than one leo */
148c7d8ba24Smacallan 	NULL,		/* textops */
149c7d8ba24Smacallan 	8, 16,	/* font width/height */
150c7d8ba24Smacallan 	WSSCREEN_WSCOLORS,	/* capabilities */
151c7d8ba24Smacallan 	NULL	/* modecookie */
152c7d8ba24Smacallan };
153c7d8ba24Smacallan 
154c7d8ba24Smacallan static int 	zx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
155c7d8ba24Smacallan static paddr_t	zx_mmap(void *, void *, off_t, int);
156c7d8ba24Smacallan static void	zx_init_screen(void *, struct vcons_screen *, int, long *);
157c7d8ba24Smacallan 
158c7d8ba24Smacallan static int	zx_putcmap(struct zx_softc *, struct wsdisplay_cmap *);
159c7d8ba24Smacallan static int	zx_getcmap(struct zx_softc *, struct wsdisplay_cmap *);
160c7d8ba24Smacallan 
161c7d8ba24Smacallan struct wsdisplay_accessops zx_accessops = {
162c7d8ba24Smacallan 	zx_ioctl,
163c7d8ba24Smacallan 	zx_mmap,
164c7d8ba24Smacallan 	NULL,	/* alloc_screen */
165c7d8ba24Smacallan 	NULL,	/* free_screen */
166c7d8ba24Smacallan 	NULL,	/* show_screen */
167c7d8ba24Smacallan 	NULL, 	/* load_font */
168c7d8ba24Smacallan 	NULL,	/* pollc */
169c7d8ba24Smacallan 	NULL	/* scroll */
170c7d8ba24Smacallan };
171c7d8ba24Smacallan 
172c7d8ba24Smacallan const struct wsscreen_descr *_zx_scrlist[] = {
173c7d8ba24Smacallan 	&zx_defaultscreen
174c7d8ba24Smacallan };
175c7d8ba24Smacallan 
176c7d8ba24Smacallan struct wsscreen_list zx_screenlist = {
177c7d8ba24Smacallan 	sizeof(_zx_scrlist) / sizeof(struct wsscreen_descr *),
178c7d8ba24Smacallan 	_zx_scrlist
179c7d8ba24Smacallan };
180c7d8ba24Smacallan 
181c7d8ba24Smacallan 
182c7d8ba24Smacallan extern const u_char rasops_cmap[768];
183c7d8ba24Smacallan 
184c7d8ba24Smacallan static struct vcons_screen zx_console_screen;
185c7d8ba24Smacallan 
186c7d8ba24Smacallan static int
zx_match(device_t parent,cfdata_t cf,void * aux)187d16a259fScegger zx_match(device_t parent, cfdata_t cf, void *aux)
188ca0ac2c7Sad {
189ca0ac2c7Sad 	struct sbus_attach_args *sa;
190ca0ac2c7Sad 
191ca0ac2c7Sad 	sa = (struct sbus_attach_args *)aux;
192ca0ac2c7Sad 
193ca0ac2c7Sad 	return (strcmp(sa->sa_name, "SUNW,leo") == 0);
194ca0ac2c7Sad }
195ca0ac2c7Sad 
196c7d8ba24Smacallan static void
zx_attach(device_t parent,device_t self,void * args)197c7d8ba24Smacallan zx_attach(device_t parent, device_t self, void *args)
198ca0ac2c7Sad {
199ca0ac2c7Sad 	struct zx_softc *sc;
200ca0ac2c7Sad 	struct sbus_attach_args *sa;
201ca0ac2c7Sad 	bus_space_handle_t bh;
202ca0ac2c7Sad 	bus_space_tag_t bt;
203ca0ac2c7Sad 	struct fbdevice *fb;
204c7d8ba24Smacallan 	struct wsemuldisplaydev_attach_args aa;
205c7d8ba24Smacallan 	struct rasops_info *ri = &zx_console_screen.scr_ri;
206c7d8ba24Smacallan 	unsigned long defattr;
20708f5b97bSmacallan 	int isconsole, width, height;
208ca0ac2c7Sad 
2091a9e64b4Sdrochner 	sc = device_private(self);
210c7d8ba24Smacallan 	sc->sc_dv = self;
211c7d8ba24Smacallan 
212ca0ac2c7Sad 	sa = args;
213ca0ac2c7Sad 	fb = &sc->sc_fb;
214ca0ac2c7Sad 	bt = sa->sa_bustag;
215ca0ac2c7Sad 	sc->sc_bt = bt;
216ca0ac2c7Sad 	sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
217ca0ac2c7Sad 
2180483b5b9Smacallan 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_SS0,
2190483b5b9Smacallan 	    0x800000, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, &bh) != 0) {
2204c5fa20dScegger 		aprint_error_dev(self, "can't map bits\n");
221ca0ac2c7Sad 		return;
222ca0ac2c7Sad 	}
22353524e44Schristos 	fb->fb_pixels = (void *)bus_space_vaddr(bt, bh);
224579b9cbdStsutsui 	sc->sc_pixels = (uint32_t *)fb->fb_pixels;
225ca0ac2c7Sad 
226ca0ac2c7Sad 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LC_SS0_USR,
227ca0ac2c7Sad 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
2284c5fa20dScegger 		aprint_error_dev(self, "can't map zc\n");
229ca0ac2c7Sad 		return;
230ca0ac2c7Sad 	}
231c7d8ba24Smacallan 
232f8fb75a4Stsutsui 	sc->sc_bhzc = bh;
233ca0ac2c7Sad 
234ca0ac2c7Sad 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS0,
235ca0ac2c7Sad 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
2364c5fa20dScegger 		aprint_error_dev(self, "can't map ld/ss0\n");
237ca0ac2c7Sad 		return;
238ca0ac2c7Sad 	}
239f8fb75a4Stsutsui 	sc->sc_bhzdss0 = bh;
240ca0ac2c7Sad 
241ca0ac2c7Sad 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LD_SS1,
242ca0ac2c7Sad 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
2434c5fa20dScegger 		aprint_error_dev(self, "can't map ld/ss1\n");
244ca0ac2c7Sad 		return;
245ca0ac2c7Sad 	}
246f8fb75a4Stsutsui 	sc->sc_bhzdss1 = bh;
247ca0ac2c7Sad 
248ca0ac2c7Sad 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CROSS,
249ca0ac2c7Sad 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
2504c5fa20dScegger 		aprint_error_dev(self, "can't map zx\n");
251ca0ac2c7Sad 		return;
252ca0ac2c7Sad 	}
253f8fb75a4Stsutsui 	sc->sc_bhzx = bh;
254ca0ac2c7Sad 
255ca0ac2c7Sad 	if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + ZX_OFF_LX_CURSOR,
256ca0ac2c7Sad 	    PAGE_SIZE, BUS_SPACE_MAP_LINEAR, &bh) != 0) {
2574c5fa20dScegger 		aprint_error_dev(self, "can't map zcu\n");
258ca0ac2c7Sad 		return;
259ca0ac2c7Sad 	}
260f8fb75a4Stsutsui 	sc->sc_bhzcu = bh;
261ca0ac2c7Sad 
262ca0ac2c7Sad 	fb->fb_driver = &zx_fbdriver;
263c7d8ba24Smacallan 	fb->fb_device = sc->sc_dv;
264c7d8ba24Smacallan 	fb->fb_flags = device_cfdata(sc->sc_dv)->cf_flags & FB_USERMASK;
265ca0ac2c7Sad 	fb->fb_pfour = NULL;
266768601d6Stsutsui 	fb->fb_linebytes = prom_getpropint(sa->sa_node, "linebytes", 8192);
267ca0ac2c7Sad 
268768601d6Stsutsui 	width = prom_getpropint(sa->sa_node, "width", 1280);
269768601d6Stsutsui 	height = prom_getpropint(sa->sa_node, "height", 1024);
270768601d6Stsutsui 	fb_setsize_obp(fb, 32, width, height, sa->sa_node);
271ca0ac2c7Sad 
272ca0ac2c7Sad 	fb->fb_type.fb_cmsize = 256;
273ca0ac2c7Sad 	fb->fb_type.fb_depth = 32;
274ca0ac2c7Sad 	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
275ca0ac2c7Sad 	fb->fb_type.fb_type = FBTYPE_SUNLEO;
276ca0ac2c7Sad 
277ca0ac2c7Sad 	printf(": %d x %d", fb->fb_type.fb_width, fb->fb_type.fb_height);
278ca0ac2c7Sad 	isconsole = fb_is_console(sa->sa_node);
279ca0ac2c7Sad 	if (isconsole)
280ca0ac2c7Sad 		printf(" (console)");
281ca0ac2c7Sad 	printf("\n");
282ca0ac2c7Sad 
283ca0ac2c7Sad 	if (sa->sa_nintr != 0)
284725a6aebSpk 		bus_intr_establish(bt, sa->sa_pri, IPL_NONE, zx_intr, sc);
285ca0ac2c7Sad 
286d47bcd29Schs 	sc->sc_cmap = malloc(768, M_DEVBUF, M_WAITOK);
287ca0ac2c7Sad 	zx_reset(sc);
288ca0ac2c7Sad 
289c7d8ba24Smacallan 	sc->sc_width = fb->fb_type.fb_width;
290c7d8ba24Smacallan 	sc->sc_stride = 8192; /* 32 bit */
291c7d8ba24Smacallan 	sc->sc_height = fb->fb_type.fb_height;
292c7d8ba24Smacallan 
293c7d8ba24Smacallan 	/* setup rasops and so on for wsdisplay */
294c7d8ba24Smacallan 	wsfont_init();
295c7d8ba24Smacallan 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
296c7d8ba24Smacallan 	sc->sc_bg = WS_DEFAULT_BG;
297c7d8ba24Smacallan 
298c7d8ba24Smacallan 	vcons_init(&sc->vd, sc, &zx_defaultscreen, &zx_accessops);
299c7d8ba24Smacallan 	sc->vd.init_screen = zx_init_screen;
300c7d8ba24Smacallan 
301c7d8ba24Smacallan 	if (isconsole) {
302c7d8ba24Smacallan 		/* we mess with zx_console_screen only once */
303c7d8ba24Smacallan 		vcons_init_screen(&sc->vd, &zx_console_screen, 1,
304c7d8ba24Smacallan 		    &defattr);
305c7d8ba24Smacallan 		zx_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
306c7d8ba24Smacallan 
307c7d8ba24Smacallan 		zx_defaultscreen.textops = &ri->ri_ops;
308c7d8ba24Smacallan 		zx_defaultscreen.capabilities = WSSCREEN_WSCOLORS;
309c7d8ba24Smacallan 		zx_defaultscreen.nrows = ri->ri_rows;
310c7d8ba24Smacallan 		zx_defaultscreen.ncols = ri->ri_cols;
31108f5b97bSmacallan 		zx_fillrect(sc, 0, 0, width, height,
31208f5b97bSmacallan 		     ri->ri_devcmap[defattr >> 16], ZX_STD_ROP);
313c7d8ba24Smacallan 		wsdisplay_cnattach(&zx_defaultscreen, ri, 0, 0, defattr);
314647d0c59Smacallan 		vcons_replay_msgbuf(&zx_console_screen);
315c7d8ba24Smacallan 	} else {
316ca0ac2c7Sad 		/*
317c7d8ba24Smacallan 		 * we're not the console so we just clear the screen and don't
318c7d8ba24Smacallan 		 * set up any sort of text display
319ca0ac2c7Sad 		 */
320c7d8ba24Smacallan 		if (zx_defaultscreen.textops == NULL) {
321c7d8ba24Smacallan 			/*
322c7d8ba24Smacallan 			 * ugly, but...
323c7d8ba24Smacallan 			 * we want the console settings to win, so we only
324c7d8ba24Smacallan 			 * touch anything when we find an untouched screen
325c7d8ba24Smacallan 			 * definition. In this case we fill it from fb to
326c7d8ba24Smacallan 			 * avoid problems in case no zx is the console
327c7d8ba24Smacallan 			 */
328c7d8ba24Smacallan 			zx_defaultscreen.textops = &ri->ri_ops;
329c7d8ba24Smacallan 			zx_defaultscreen.capabilities = ri->ri_caps;
330c7d8ba24Smacallan 			zx_defaultscreen.nrows = ri->ri_rows;
331c7d8ba24Smacallan 			zx_defaultscreen.ncols = ri->ri_cols;
332c7d8ba24Smacallan 		}
333ca0ac2c7Sad 	}
334ca0ac2c7Sad 
335c7d8ba24Smacallan 	aa.scrdata = &zx_screenlist;
336c7d8ba24Smacallan 	aa.console = isconsole;
337c7d8ba24Smacallan 	aa.accessops = &zx_accessops;
338c7d8ba24Smacallan 	aa.accesscookie = &sc->vd;
339*c7fb772bSthorpej 	config_found(sc->sc_dv, &aa, wsemuldisplaydevprint, CFARGS_NONE);
340c7d8ba24Smacallan 	fb_attach(&sc->sc_fb, isconsole);
341c7d8ba24Smacallan }
342c7d8ba24Smacallan 
343c7d8ba24Smacallan static int
zxopen(dev_t dev,int flags,int mode,struct lwp * l)34495e1ffb1Schristos zxopen(dev_t dev, int flags, int mode, struct lwp *l)
345ca0ac2c7Sad {
346ca0ac2c7Sad 
347ca0ac2c7Sad 	if (device_lookup(&zx_cd, minor(dev)) == NULL)
348ca0ac2c7Sad 		return (ENXIO);
349ca0ac2c7Sad 	return (0);
350ca0ac2c7Sad }
351ca0ac2c7Sad 
352c7d8ba24Smacallan static int
zxclose(dev_t dev,int flags,int mode,struct lwp * l)35395e1ffb1Schristos zxclose(dev_t dev, int flags, int mode, struct lwp *l)
354ca0ac2c7Sad {
355ca0ac2c7Sad 	struct zx_softc *sc;
356ca0ac2c7Sad 
35796434039Scegger 	sc = device_lookup_private(&zx_cd, minor(dev));
358ca0ac2c7Sad 
359ca0ac2c7Sad 	zx_reset(sc);
360ca0ac2c7Sad 	zx_cursor_blank(sc);
361ca0ac2c7Sad 	return (0);
362ca0ac2c7Sad }
363ca0ac2c7Sad 
364c7d8ba24Smacallan static int
zxioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)36553524e44Schristos zxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
366ca0ac2c7Sad {
367ca0ac2c7Sad 	struct zx_softc *sc;
368ca0ac2c7Sad 	struct fbcmap *cm;
369ca0ac2c7Sad 	struct fbcursor *cu;
370e07f0b93Schs 	uint32_t curbits[2][32];
371bfad2cbbSchristos 	int rv, v, count, i, error;
372ca0ac2c7Sad 
37396434039Scegger 	sc = device_lookup_private(&zx_cd, minor(dev));
374ca0ac2c7Sad 
375ca0ac2c7Sad 	switch (cmd) {
376ca0ac2c7Sad 	case FBIOGTYPE:
377ca0ac2c7Sad 		*(struct fbtype *)data = sc->sc_fb.fb_type;
378ca0ac2c7Sad 		break;
379ca0ac2c7Sad 
380ca0ac2c7Sad 	case FBIOGATTR:
381ca0ac2c7Sad #define fba ((struct fbgattr *)data)
382ca0ac2c7Sad 		fba->real_type = sc->sc_fb.fb_type.fb_type;
383ca0ac2c7Sad 		fba->owner = 0;		/* XXX ??? */
384ca0ac2c7Sad 		fba->fbtype = sc->sc_fb.fb_type;
385ca0ac2c7Sad 		fba->sattr.flags = 0;
386ca0ac2c7Sad 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
387ca0ac2c7Sad 		fba->sattr.dev_specific[0] = -1;
388ca0ac2c7Sad 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
389ca0ac2c7Sad 		fba->emu_types[1] = -1;
390ca0ac2c7Sad 		fba->emu_types[2] = -1;
391ca0ac2c7Sad #undef fba
392ca0ac2c7Sad 		break;
393ca0ac2c7Sad 
394ca0ac2c7Sad 	case FBIOGVIDEO:
395ca0ac2c7Sad 		*(int *)data = ((sc->sc_flags & ZX_BLANKED) != 0);
396ca0ac2c7Sad 		break;
397ca0ac2c7Sad 
398ca0ac2c7Sad 	case FBIOSVIDEO:
399ca0ac2c7Sad 		if (*(int *)data)
400c7d8ba24Smacallan 			zx_unblank(sc->sc_dv);
401ca0ac2c7Sad 		else
402c7d8ba24Smacallan 			zx_blank(sc->sc_dv);
403ca0ac2c7Sad 		break;
404ca0ac2c7Sad 
405ca0ac2c7Sad 	case FBIOGETCMAP:
406ca0ac2c7Sad 		cm = (struct fbcmap *)data;
407ca0ac2c7Sad 		if (cm->index > 256 || cm->count > 256 - cm->index)
408ca0ac2c7Sad 			return (EINVAL);
409ca0ac2c7Sad 		rv = copyout(sc->sc_cmap + cm->index, cm->red, cm->count);
41060c69eb3Sad 		if (rv == 0)
411ca0ac2c7Sad 			rv = copyout(sc->sc_cmap + 256 + cm->index, cm->green,
412ca0ac2c7Sad 			    cm->count);
41360c69eb3Sad 		if (rv == 0)
414ca0ac2c7Sad 			rv = copyout(sc->sc_cmap + 512 + cm->index, cm->blue,
415ca0ac2c7Sad 			    cm->count);
416ca0ac2c7Sad 		return (rv);
417ca0ac2c7Sad 
418ca0ac2c7Sad 	case FBIOPUTCMAP:
419ca0ac2c7Sad 		cm = (struct fbcmap *)data;
420ca0ac2c7Sad 		if (cm->index > 256 || cm->count > 256 - cm->index)
421ca0ac2c7Sad 			return (EINVAL);
422ca0ac2c7Sad 		rv = copyin(cm->red, sc->sc_cmap + cm->index, cm->count);
42360c69eb3Sad 		if (rv == 0)
424ca0ac2c7Sad 			rv = copyin(cm->green, sc->sc_cmap + 256 + cm->index,
425ca0ac2c7Sad 			    cm->count);
42660c69eb3Sad 		if (rv == 0)
427ca0ac2c7Sad 			rv = copyin(cm->blue, sc->sc_cmap + 512 + cm->index,
428ca0ac2c7Sad 			    cm->count);
429ca0ac2c7Sad 		zx_cmap_put(sc);
430ca0ac2c7Sad 		return (rv);
431ca0ac2c7Sad 
432ca0ac2c7Sad 	case FBIOGCURPOS:
433ca0ac2c7Sad 		*(struct fbcurpos *)data = sc->sc_curpos;
434ca0ac2c7Sad 		break;
435ca0ac2c7Sad 
436ca0ac2c7Sad 	case FBIOSCURPOS:
437ca0ac2c7Sad 		sc->sc_curpos = *(struct fbcurpos *)data;
438ca0ac2c7Sad 		zx_cursor_move(sc);
439ca0ac2c7Sad 		break;
440ca0ac2c7Sad 
441ca0ac2c7Sad 	case FBIOGCURMAX:
442ca0ac2c7Sad 		((struct fbcurpos *)data)->x = 32;
443ca0ac2c7Sad 		((struct fbcurpos *)data)->y = 32;
444ca0ac2c7Sad 		break;
445ca0ac2c7Sad 
446ca0ac2c7Sad 	case FBIOSCURSOR:
447ca0ac2c7Sad 		cu = (struct fbcursor *)data;
448ca0ac2c7Sad 		v = cu->set;
449ca0ac2c7Sad 
450ca0ac2c7Sad 		if ((v & FB_CUR_SETSHAPE) != 0) {
451ca0ac2c7Sad 			if ((u_int)cu->size.x > 32 || (u_int)cu->size.y > 32)
452ca0ac2c7Sad 				return (EINVAL);
453ca0ac2c7Sad 			count = cu->size.y * 4;
454e07f0b93Schs 			rv = copyin(cu->mask, curbits[0], count);
455e07f0b93Schs 			if (rv)
456e07f0b93Schs 				return rv;
457e07f0b93Schs 			rv = copyin(cu->image, curbits[1], count);
458e07f0b93Schs 			if (rv)
459e07f0b93Schs 				return rv;
460ca0ac2c7Sad 		}
461ca0ac2c7Sad 		if ((v & FB_CUR_SETCUR) != 0) {
462ca0ac2c7Sad 			if (cu->enable)
463ca0ac2c7Sad 				zx_cursor_unblank(sc);
464ca0ac2c7Sad 			else
465ca0ac2c7Sad 				zx_cursor_blank(sc);
466ca0ac2c7Sad 		}
467ca0ac2c7Sad 		if ((v & (FB_CUR_SETPOS | FB_CUR_SETHOT)) != 0) {
468ca0ac2c7Sad 			if ((v & FB_CUR_SETPOS) != 0)
469ca0ac2c7Sad 				sc->sc_curpos = cu->pos;
470ca0ac2c7Sad 			if ((v & FB_CUR_SETHOT) != 0)
471ca0ac2c7Sad 				sc->sc_curhot = cu->hot;
472ca0ac2c7Sad 			zx_cursor_move(sc);
473ca0ac2c7Sad 		}
474ca0ac2c7Sad 		if ((v & FB_CUR_SETCMAP) != 0) {
475ca0ac2c7Sad 			if (cu->cmap.index > 2 ||
476ca0ac2c7Sad 			    cu->cmap.count > 2 - cu->cmap.index)
477ca0ac2c7Sad 				return (EINVAL);
47842620a4aSthorpej 
47942620a4aSthorpej 			uint8_t red[2], green[2], blue[2];
48042620a4aSthorpej 			const u_int cnt = cu->cmap.count;
48142620a4aSthorpej 
48242620a4aSthorpej 			if (cnt &&
48342620a4aSthorpej 			    ((error = copyin(cu->cmap.red,   red,   cnt)) ||
48442620a4aSthorpej 			     (error = copyin(cu->cmap.green, green, cnt)) ||
48542620a4aSthorpej 			     (error = copyin(cu->cmap.blue,  blue,  cnt)))) {
48642620a4aSthorpej 				return error;
48742620a4aSthorpej 			}
48842620a4aSthorpej 
48942620a4aSthorpej 			for (i = 0; i < cnt; i++) {
49042620a4aSthorpej 				sc->sc_curcmap[i + cu->cmap.index + 0] =
49142620a4aSthorpej 				    red[i];
49242620a4aSthorpej 				sc->sc_curcmap[i + cu->cmap.index + 2] =
49342620a4aSthorpej 				    green[i];
49442620a4aSthorpej 				sc->sc_curcmap[i + cu->cmap.index + 4] =
49542620a4aSthorpej 				    blue[i];
496ca0ac2c7Sad 			}
497ca0ac2c7Sad 			zx_cursor_color(sc);
498ca0ac2c7Sad 		}
499ca0ac2c7Sad 		if ((v & FB_CUR_SETSHAPE) != 0) {
500ca0ac2c7Sad 			sc->sc_cursize = cu->size;
501ca0ac2c7Sad 			count = cu->size.y * 4;
502ca0ac2c7Sad 			memset(sc->sc_curbits, 0, sizeof(sc->sc_curbits));
503e07f0b93Schs 			memcpy(sc->sc_curbits[0], curbits[0], count);
504e07f0b93Schs 			memcpy(sc->sc_curbits[1], curbits[1], count);
505ca0ac2c7Sad 			zx_cursor_set(sc);
506ca0ac2c7Sad 		}
507ca0ac2c7Sad 		break;
508ca0ac2c7Sad 
509ca0ac2c7Sad 	case FBIOGCURSOR:
510ca0ac2c7Sad 		cu = (struct fbcursor *)data;
511ca0ac2c7Sad 
512ca0ac2c7Sad 		cu->set = FB_CUR_SETALL;
513ca0ac2c7Sad 		cu->enable = ((sc->sc_flags & ZX_CURSOR) != 0);
514ca0ac2c7Sad 		cu->pos = sc->sc_curpos;
515ca0ac2c7Sad 		cu->hot = sc->sc_curhot;
516ca0ac2c7Sad 		cu->size = sc->sc_cursize;
517ca0ac2c7Sad 
518ca0ac2c7Sad 		if (cu->image != NULL) {
519ca0ac2c7Sad 			count = sc->sc_cursize.y * 4;
520e07f0b93Schs 			rv = copyout(sc->sc_curbits[1], cu->image, count);
521ca0ac2c7Sad 			if (rv)
522ca0ac2c7Sad 				return (rv);
523e07f0b93Schs 			rv = copyout(sc->sc_curbits[0], cu->mask, count);
524ca0ac2c7Sad 			if (rv)
525ca0ac2c7Sad 				return (rv);
526ca0ac2c7Sad 		}
527ca0ac2c7Sad 		if (cu->cmap.red != NULL) {
528bfad2cbbSchristos 			uint8_t red[2], green[2], blue[2];
529bfad2cbbSchristos 			const uint8_t *ccm = sc->sc_curcmap;
530bfad2cbbSchristos 			cm = &cu->cmap;
531bfad2cbbSchristos 
532bfad2cbbSchristos 			if (cm->index > 2 || cm->count > 2 - cm->index)
533bfad2cbbSchristos 				return EINVAL;
534bfad2cbbSchristos 
535bfad2cbbSchristos 			for (i = 0; i < cm->count; i++) {
536bfad2cbbSchristos 				red[i] = ccm[i + cm->index + 0];
537bfad2cbbSchristos 				green[i] = ccm[i + cm->index + 2];
538bfad2cbbSchristos 				blue[i] = ccm[i + cm->index + 4];
539ca0ac2c7Sad 			}
540bfad2cbbSchristos 
541bfad2cbbSchristos 			if ((error = copyout(red, cm->red, cm->count)) ||
542bfad2cbbSchristos 			    (error = copyout(green, cm->green, cm->count)) ||
543bfad2cbbSchristos 			    (error = copyout(blue, cm->blue, cm->count)))
544bfad2cbbSchristos 				return error;
545ca0ac2c7Sad 		} else {
546ca0ac2c7Sad 			cu->cmap.index = 0;
547ca0ac2c7Sad 			cu->cmap.count = 2;
548ca0ac2c7Sad 		}
549ca0ac2c7Sad 		break;
550ca0ac2c7Sad 
551ca0ac2c7Sad 	default:
552ca0ac2c7Sad #ifdef DEBUG
553ca0ac2c7Sad 		log(LOG_NOTICE, "zxioctl(0x%lx) (%s[%d])\n", cmd,
554517cd323Sjdc 		    l->l_proc->p_comm, l->l_proc->p_pid);
555ca0ac2c7Sad #endif
556ca0ac2c7Sad 		return (ENOTTY);
557ca0ac2c7Sad 	}
558ca0ac2c7Sad 
559ca0ac2c7Sad 	return (0);
560ca0ac2c7Sad }
561ca0ac2c7Sad 
562c7d8ba24Smacallan static int
zx_intr(void * cookie)563ca0ac2c7Sad zx_intr(void *cookie)
564ca0ac2c7Sad {
565ca0ac2c7Sad 
566ca0ac2c7Sad 	return (1);
567ca0ac2c7Sad }
568ca0ac2c7Sad 
569c7d8ba24Smacallan static void
zx_reset(struct zx_softc * sc)570ca0ac2c7Sad zx_reset(struct zx_softc *sc)
571ca0ac2c7Sad {
572ca0ac2c7Sad 	struct fbtype *fbt;
573ca0ac2c7Sad 	u_int i;
574ca0ac2c7Sad 
575ca0ac2c7Sad 	fbt = &sc->sc_fb.fb_type;
576ca0ac2c7Sad 
577ca0ac2c7Sad 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 0, 0x2c0);
578ca0ac2c7Sad 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 1, 0x30);
579ca0ac2c7Sad 	zx_cross_loadwid(sc, ZX_WID_DBL_8, 2, 0x20);
580ca0ac2c7Sad 	zx_cross_loadwid(sc, ZX_WID_DBL_24, 1, 0x30);
581ca0ac2c7Sad 
582f8fb75a4Stsutsui 	i = bus_space_read_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc);
583ca0ac2c7Sad 	i |= ZX_SS1_MISC_ENABLE;
584f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss1, zd_misc, i);
585ca0ac2c7Sad 
586c7d8ba24Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wid, 1);
587f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_widclip, 0);
588f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_wmask, 0xffff);
589f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmin, 0);
590f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_vclipmax,
591ca0ac2c7Sad 	    (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 16));
592f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, 0);
593c7d8ba24Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_planemask, 0xffffffff);
594f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
595ca0ac2c7Sad 
596f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent,
597ca0ac2c7Sad 	    (fbt->fb_width - 1) | ((fbt->fb_height - 1) << 11));
598f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_addrspace,
599f8fb75a4Stsutsui 	    ZX_ADDRSPC_FONT_OBGR);
600f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontt, 0);
601ca0ac2c7Sad 
602ca0ac2c7Sad 	for (i = 0; i < 256; i++) {
603ca0ac2c7Sad 		sc->sc_cmap[i] = rasops_cmap[i * 3];
604ca0ac2c7Sad 		sc->sc_cmap[i + 256] = rasops_cmap[i * 3 + 1];
605ca0ac2c7Sad 		sc->sc_cmap[i + 512] = rasops_cmap[i * 3 + 2];
606ca0ac2c7Sad 	}
607ca0ac2c7Sad 
608ca0ac2c7Sad 	zx_cmap_put(sc);
609ca0ac2c7Sad }
610ca0ac2c7Sad 
611c7d8ba24Smacallan static int
zx_cross_wait(struct zx_softc * sc)612ca0ac2c7Sad zx_cross_wait(struct zx_softc *sc)
613ca0ac2c7Sad {
614ca0ac2c7Sad 	int i;
615ca0ac2c7Sad 
616ca0ac2c7Sad 	for (i = 300000; i != 0; i--) {
617f8fb75a4Stsutsui 		if ((bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) &
618f8fb75a4Stsutsui 		    ZX_CROSS_CSR_PROGRESS) == 0)
619ca0ac2c7Sad 			break;
620ca0ac2c7Sad 		DELAY(1);
621ca0ac2c7Sad 	}
622ca0ac2c7Sad 
623ca0ac2c7Sad 	if (i == 0)
624ca0ac2c7Sad 		printf("zx_cross_wait: timed out\n");
625ca0ac2c7Sad 
626ca0ac2c7Sad 	return (i);
627ca0ac2c7Sad }
628ca0ac2c7Sad 
629c7d8ba24Smacallan static int
zx_cross_loadwid(struct zx_softc * sc,u_int type,u_int index,u_int value)630ca0ac2c7Sad zx_cross_loadwid(struct zx_softc *sc, u_int type, u_int index, u_int value)
631ca0ac2c7Sad {
632cd23cf5cSchs 	u_int tmp = 0;
633ca0ac2c7Sad 
634f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID);
635ca0ac2c7Sad 
636ca0ac2c7Sad 	if (zx_cross_wait(sc))
637ca0ac2c7Sad 		return (1);
638ca0ac2c7Sad 
639ca0ac2c7Sad 	if (type == ZX_WID_DBL_8)
640ca0ac2c7Sad 		tmp = (index & 0x0f) + 0x40;
641ca0ac2c7Sad 	else if (type == ZX_WID_DBL_24)
642ca0ac2c7Sad 		tmp = index & 0x3f;
643ca0ac2c7Sad 
644f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, 0x5800 + tmp);
645f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, value);
646f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_WID);
647f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
648f8fb75a4Stsutsui 	    ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2);
649ca0ac2c7Sad 
650ca0ac2c7Sad 	return (0);
651ca0ac2c7Sad }
652ca0ac2c7Sad 
653c7d8ba24Smacallan static int
zx_cmap_put(struct zx_softc * sc)654ca0ac2c7Sad zx_cmap_put(struct zx_softc *sc)
655ca0ac2c7Sad {
656ca0ac2c7Sad 	const u_char *b;
657ca0ac2c7Sad 	u_int i, t;
658ca0ac2c7Sad 
659f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0);
660c7d8ba24Smacallan 
661c7d8ba24Smacallan 	zx_cross_wait(sc);
662ca0ac2c7Sad 
663f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type,
664f8fb75a4Stsutsui 	    ZX_CROSS_TYPE_CLUTDATA);
665ca0ac2c7Sad 
666ca0ac2c7Sad 	for (i = 0, b = sc->sc_cmap; i < 256; i++) {
667ca0ac2c7Sad 		t = b[i];
668ca0ac2c7Sad 		t |= b[i + 256] << 8;
669ca0ac2c7Sad 		t |= b[i + 512] << 16;
670f8fb75a4Stsutsui 		bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_value, t);
671ca0ac2c7Sad 	}
672ca0ac2c7Sad 
673f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_CLUT0);
674f8fb75a4Stsutsui 	i = bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr);
675ca0ac2c7Sad 	i = i | ZX_CROSS_CSR_UNK | ZX_CROSS_CSR_UNK2;
676f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr, i);
677ca0ac2c7Sad 	return (0);
678ca0ac2c7Sad }
679ca0ac2c7Sad 
680c7d8ba24Smacallan static void
zx_cursor_move(struct zx_softc * sc)681ca0ac2c7Sad zx_cursor_move(struct zx_softc *sc)
682ca0ac2c7Sad {
683ca0ac2c7Sad 	int sx, sy, x, y;
684ca0ac2c7Sad 
685ca0ac2c7Sad 	x = sc->sc_curpos.x - sc->sc_curhot.x;
686ca0ac2c7Sad 	y = sc->sc_curpos.y - sc->sc_curhot.y;
687ca0ac2c7Sad 
688ca0ac2c7Sad 	if (x < 0) {
689d1579b2dSriastradh 		sx = uimin(-x, 32);
690ca0ac2c7Sad 		x = 0;
691ca0ac2c7Sad 	} else
692ca0ac2c7Sad 		sx = 0;
693ca0ac2c7Sad 
694ca0ac2c7Sad 	if (y < 0) {
695d1579b2dSriastradh 		sy = uimin(-y, 32);
696ca0ac2c7Sad 		y = 0;
697ca0ac2c7Sad 	} else
698ca0ac2c7Sad 		sy = 0;
699ca0ac2c7Sad 
700ca0ac2c7Sad 	if (sx != sc->sc_shiftx || sy != sc->sc_shifty) {
701ca0ac2c7Sad 		sc->sc_shiftx = sx;
702ca0ac2c7Sad 		sc->sc_shifty = sy;
703ca0ac2c7Sad 		zx_cursor_set(sc);
704ca0ac2c7Sad 	}
705ca0ac2c7Sad 
706f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_sxy,
707f8fb75a4Stsutsui 	    ((y & 0x7ff) << 11) | (x & 0x7ff));
708f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
709f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x30);
710ca0ac2c7Sad 
711ca0ac2c7Sad 	/* XXX Necessary? */
712f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
713f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
714ca0ac2c7Sad }
715ca0ac2c7Sad 
716c7d8ba24Smacallan static void
zx_cursor_set(struct zx_softc * sc)717ca0ac2c7Sad zx_cursor_set(struct zx_softc *sc)
718ca0ac2c7Sad {
719ca0ac2c7Sad 	int i, j, data;
720ca0ac2c7Sad 
72160c69eb3Sad 	if ((sc->sc_flags & ZX_CURSOR) != 0)
722f8fb75a4Stsutsui 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
723f8fb75a4Stsutsui 		    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) &
724f8fb75a4Stsutsui 		    ~0x80);
725ca0ac2c7Sad 
726ca0ac2c7Sad 	for (j = 0; j < 2; j++) {
727f8fb75a4Stsutsui 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x20 << j);
72860c69eb3Sad 
729ca0ac2c7Sad 		for (i = sc->sc_shifty; i < 32; i++) {
730ca0ac2c7Sad 			data = sc->sc_curbits[j][i];
731f8fb75a4Stsutsui 			bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data,
732f8fb75a4Stsutsui 			    data >> sc->sc_shiftx);
733ca0ac2c7Sad 		}
734ca0ac2c7Sad 		for (i = sc->sc_shifty; i != 0; i--)
735f8fb75a4Stsutsui 			bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, 0);
736ca0ac2c7Sad 	}
73760c69eb3Sad 
73860c69eb3Sad 	if ((sc->sc_flags & ZX_CURSOR) != 0)
739f8fb75a4Stsutsui 		bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
740f8fb75a4Stsutsui 		    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
741ca0ac2c7Sad }
742ca0ac2c7Sad 
743c7d8ba24Smacallan static void
zx_cursor_blank(struct zx_softc * sc)744ca0ac2c7Sad zx_cursor_blank(struct zx_softc *sc)
745ca0ac2c7Sad {
746ca0ac2c7Sad 
747ca0ac2c7Sad 	sc->sc_flags &= ~ZX_CURSOR;
748f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
749f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) & ~0x80);
750ca0ac2c7Sad }
751ca0ac2c7Sad 
752c7d8ba24Smacallan static void
zx_cursor_unblank(struct zx_softc * sc)753ca0ac2c7Sad zx_cursor_unblank(struct zx_softc *sc)
754ca0ac2c7Sad {
755ca0ac2c7Sad 
756ca0ac2c7Sad 	sc->sc_flags |= ZX_CURSOR;
757f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
758f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x80);
759ca0ac2c7Sad }
760ca0ac2c7Sad 
761c7d8ba24Smacallan static void
zx_cursor_color(struct zx_softc * sc)762ca0ac2c7Sad zx_cursor_color(struct zx_softc *sc)
763ca0ac2c7Sad {
764579b9cbdStsutsui 	uint8_t tmp;
765ca0ac2c7Sad 
766f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_type, 0x50);
767ca0ac2c7Sad 
768ca0ac2c7Sad 	tmp = sc->sc_curcmap[0] | (sc->sc_curcmap[2] << 8) |
769ca0ac2c7Sad 	    (sc->sc_curcmap[4] << 16);
770f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp);
771ca0ac2c7Sad 
772ca0ac2c7Sad 	tmp = sc->sc_curcmap[1] | (sc->sc_curcmap[3] << 8) |
773ca0ac2c7Sad 	    (sc->sc_curcmap[5] << 16);
77424ebd355Sthorpej 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_data, tmp);
775ca0ac2c7Sad 
776f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc,
777f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzcu, zcu_misc) | 0x03);
778ca0ac2c7Sad }
779ca0ac2c7Sad 
780c7d8ba24Smacallan static void
zx_blank(device_t dv)781c7d8ba24Smacallan zx_blank(device_t dv)
782ca0ac2c7Sad {
783ca0ac2c7Sad 	struct zx_softc *sc;
784ca0ac2c7Sad 
7851a9e64b4Sdrochner 	sc = device_private(dv);
786ca0ac2c7Sad 
787ca0ac2c7Sad 	if ((sc->sc_flags & ZX_BLANKED) != 0)
788ca0ac2c7Sad 		return;
789ca0ac2c7Sad 	sc->sc_flags |= ZX_BLANKED;
790ca0ac2c7Sad 
791f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO);
792f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
793f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) &
794f8fb75a4Stsutsui 	    ~ZX_CROSS_CSR_ENABLE);
795ca0ac2c7Sad }
796ca0ac2c7Sad 
797c7d8ba24Smacallan static void
zx_unblank(device_t dv)798c7d8ba24Smacallan zx_unblank(device_t dv)
799ca0ac2c7Sad {
800ca0ac2c7Sad 	struct zx_softc *sc;
801ca0ac2c7Sad 
8021a9e64b4Sdrochner 	sc = device_private(dv);
803ca0ac2c7Sad 
804ca0ac2c7Sad 	if ((sc->sc_flags & ZX_BLANKED) == 0)
805ca0ac2c7Sad 		return;
806ca0ac2c7Sad 	sc->sc_flags &= ~ZX_BLANKED;
807ca0ac2c7Sad 
808f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_type, ZX_CROSS_TYPE_VIDEO);
809f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzx, zx_csr,
810f8fb75a4Stsutsui 	    bus_space_read_4(sc->sc_bt, sc->sc_bhzx, zx_csr) |
811f8fb75a4Stsutsui 	    ZX_CROSS_CSR_ENABLE);
812ca0ac2c7Sad }
813ca0ac2c7Sad 
814c7d8ba24Smacallan static paddr_t
zxmmap(dev_t dev,off_t off,int prot)815ca0ac2c7Sad zxmmap(dev_t dev, off_t off, int prot)
816ca0ac2c7Sad {
817ca0ac2c7Sad 	struct zx_softc *sc;
818b22c03afStsutsui 	const struct zx_mmo *mm, *mmmax;
819ca0ac2c7Sad 
82096434039Scegger 	sc = device_lookup_private(&zx_cd, minor(dev));
82160c69eb3Sad 	off = trunc_page(off);
822ca0ac2c7Sad 	mm = zx_mmo;
823b22c03afStsutsui 	mmmax = mm + sizeof(zx_mmo) / sizeof(zx_mmo[0]);
824ca0ac2c7Sad 
825b22c03afStsutsui 	for (; mm < mmmax; mm++)
826ca0ac2c7Sad 		if (off >= mm->mo_va && off < mm->mo_va + mm->mo_size) {
827ca0ac2c7Sad 			off = off - mm->mo_va + mm->mo_pa;
828ca0ac2c7Sad 			return (bus_space_mmap(sc->sc_bt, sc->sc_paddr,
829ca0ac2c7Sad 			    off, prot, BUS_SPACE_MAP_LINEAR));
830ca0ac2c7Sad 		}
831ca0ac2c7Sad 
832ca0ac2c7Sad 	return (-1);
833ca0ac2c7Sad }
834ca0ac2c7Sad 
835c7d8ba24Smacallan static void
zx_fillrect(struct zx_softc * sc,int x,int y,int w,int h,uint32_t bg,int rop)836c7d8ba24Smacallan zx_fillrect(struct zx_softc *sc, int x, int y, int w, int h, uint32_t bg,
837ca0ac2c7Sad 	    int rop)
838ca0ac2c7Sad {
839ca0ac2c7Sad 
840ca0ac2c7Sad 
841f8fb75a4Stsutsui 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
842f8fb75a4Stsutsui 	    ZX_CSR_BLT_BUSY) != 0)
843ca0ac2c7Sad 		;
844ca0ac2c7Sad 
845f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, rop);
846c7d8ba24Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, bg);
847647d0c59Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent,
848647d0c59Smacallan 	    (w - 1) | ((h - 1) << 11));
849f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fill,
850f8fb75a4Stsutsui 	    x | (y << 11) | 0x80000000);
851ca0ac2c7Sad }
852ca0ac2c7Sad 
853c7d8ba24Smacallan static void
zx_copyrect(struct zx_softc * sc,int sx,int sy,int dx,int dy,int w,int h)854c7d8ba24Smacallan zx_copyrect(struct zx_softc *sc, int sx, int sy, int dx, int dy, int w,
855ca0ac2c7Sad 	    int h)
856ca0ac2c7Sad {
857c7d8ba24Smacallan 	uint32_t dir;
858ca0ac2c7Sad 
8597190e17cSmacallan 	w -= 1;
8607190e17cSmacallan 	h -= 1;
8617190e17cSmacallan 
862ca0ac2c7Sad 	if (sy < dy || sx < dx) {
863ca0ac2c7Sad 		dir = 0x80000000;
864ca0ac2c7Sad 		sx += w;
865ca0ac2c7Sad 		sy += h;
866ca0ac2c7Sad 		dx += w;
867ca0ac2c7Sad 		dy += h;
868ca0ac2c7Sad 	} else
869ca0ac2c7Sad 		dir = 0;
870ca0ac2c7Sad 
871f8fb75a4Stsutsui 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
872f8fb75a4Stsutsui 	    ZX_CSR_BLT_BUSY) != 0)
873ca0ac2c7Sad 		;
874ca0ac2c7Sad 
875f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
876f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_extent,
877f8fb75a4Stsutsui 	    w | (h << 11) | dir);
878f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_src, sx | (sy << 11));
879f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_copy, dx | (dy << 11));
880ca0ac2c7Sad }
881ca0ac2c7Sad 
882c7d8ba24Smacallan static void
zx_do_cursor(void * cookie,int on,int row,int col)883c7d8ba24Smacallan zx_do_cursor(void *cookie, int on, int row, int col)
884ca0ac2c7Sad {
885c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
886c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
887c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
888c7d8ba24Smacallan 	int x, y, wi, he;
889ca0ac2c7Sad 
890c7d8ba24Smacallan 	wi = ri->ri_font->fontwidth;
891c7d8ba24Smacallan 	he = ri->ri_font->fontheight;
892c7d8ba24Smacallan 
893c7d8ba24Smacallan 	if (ri->ri_flg & RI_CURSOR) {
894c7d8ba24Smacallan 		x = ri->ri_ccol * wi + ri->ri_xorigin;
895c7d8ba24Smacallan 		y = ri->ri_crow * he + ri->ri_yorigin;
896c7d8ba24Smacallan 		zx_fillrect(sc, x, y, wi, he, 0xff000000,
897ca0ac2c7Sad 		  ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE |
898ca0ac2c7Sad 		  ZX_ATTR_FORCE_WID);
899c7d8ba24Smacallan 		ri->ri_flg &= ~RI_CURSOR;
900ca0ac2c7Sad 	}
901ca0ac2c7Sad 
902c7d8ba24Smacallan 	ri->ri_crow = row;
903c7d8ba24Smacallan 	ri->ri_ccol = col;
904c7d8ba24Smacallan 
905c7d8ba24Smacallan 	if (on)
906ca0ac2c7Sad 	{
907c7d8ba24Smacallan 		x = ri->ri_ccol * wi + ri->ri_xorigin;
908c7d8ba24Smacallan 		y = ri->ri_crow * he + ri->ri_yorigin;
909c7d8ba24Smacallan 		zx_fillrect(sc, x, y, wi, he, 0xff000000,
910c7d8ba24Smacallan 		  ZX_ROP_NEW_XOR_OLD | ZX_ATTR_WE_ENABLE | ZX_ATTR_OE_ENABLE |
911c7d8ba24Smacallan 		  ZX_ATTR_FORCE_WID);
912c7d8ba24Smacallan 		ri->ri_flg |= RI_CURSOR;
913c7d8ba24Smacallan 	}
914ca0ac2c7Sad }
915ca0ac2c7Sad 
916c7d8ba24Smacallan static void
zx_erasecols(void * cookie,int row,int startcol,int ncols,long attr)917c7d8ba24Smacallan zx_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
918ca0ac2c7Sad {
919c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
920c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
921c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
922c7d8ba24Smacallan 	int32_t x, y, width, height, bg;
923ca0ac2c7Sad 
924c7d8ba24Smacallan 	x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
925c7d8ba24Smacallan 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
926c7d8ba24Smacallan 	width = ri->ri_font->fontwidth * ncols;
927c7d8ba24Smacallan 	height = ri->ri_font->fontheight;
928c7d8ba24Smacallan 	bg = ((uint32_t)ri->ri_devcmap[(attr >> 16) & 0xff]) << 24;
929c7d8ba24Smacallan 	zx_fillrect(sc, x, y, width, height, bg, ZX_STD_ROP);
930ca0ac2c7Sad }
931ca0ac2c7Sad 
932c7d8ba24Smacallan static void
zx_eraserows(void * cookie,int row,int nrows,long attr)933c7d8ba24Smacallan zx_eraserows(void *cookie, int row, int nrows, long attr)
934ca0ac2c7Sad {
935c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
936c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
937c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
938c7d8ba24Smacallan 	int32_t x, y, width, height, bg;
939ca0ac2c7Sad 
940c7d8ba24Smacallan 	if ((row == 0) && (nrows == ri->ri_rows)) {
941c7d8ba24Smacallan 		x = y = 0;
942c7d8ba24Smacallan 		width = ri->ri_width;
943c7d8ba24Smacallan 		height = ri->ri_height;
944c7d8ba24Smacallan 	} else {
945c7d8ba24Smacallan 		x = ri->ri_xorigin;
946c7d8ba24Smacallan 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
947c7d8ba24Smacallan 		width = ri->ri_emuwidth;
948c7d8ba24Smacallan 		height = ri->ri_font->fontheight * nrows;
949c7d8ba24Smacallan 	}
950c7d8ba24Smacallan 	bg = ((uint32_t)ri->ri_devcmap[(attr >> 16) & 0xff]) << 24;
951c7d8ba24Smacallan 	zx_fillrect(sc, x, y, width, height, bg, ZX_STD_ROP);
952ca0ac2c7Sad }
953ca0ac2c7Sad 
954c7d8ba24Smacallan static void
zx_copyrows(void * cookie,int srcrow,int dstrow,int nrows)955c7d8ba24Smacallan zx_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
956ca0ac2c7Sad {
957c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
958c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
959c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
960c7d8ba24Smacallan 	int32_t x, ys, yd, width, height;
961ca0ac2c7Sad 
962c7d8ba24Smacallan 	x = ri->ri_xorigin;
963c7d8ba24Smacallan 	ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
964c7d8ba24Smacallan 	yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
965c7d8ba24Smacallan 	width = ri->ri_emuwidth;
966c7d8ba24Smacallan 	height = ri->ri_font->fontheight * nrows;
967c7d8ba24Smacallan 	zx_copyrect(sc, x, ys, x, yd, width, height);
968ca0ac2c7Sad }
969ca0ac2c7Sad 
970c7d8ba24Smacallan static void
zx_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)971c7d8ba24Smacallan zx_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
972c7d8ba24Smacallan {
973c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
974c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
975c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
976c7d8ba24Smacallan 	int32_t xs, xd, y, width, height;
977c7d8ba24Smacallan 
978c7d8ba24Smacallan 	xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
979c7d8ba24Smacallan 	xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
980c7d8ba24Smacallan 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
981c7d8ba24Smacallan 	width = ri->ri_font->fontwidth * ncols;
982c7d8ba24Smacallan 	height = ri->ri_font->fontheight;
983c7d8ba24Smacallan 	zx_copyrect(sc, xs, y, xd, y, width, height);
984c7d8ba24Smacallan }
985c7d8ba24Smacallan 
986c7d8ba24Smacallan static void
zx_putchar(void * cookie,int row,int col,u_int uc,long attr)987ca0ac2c7Sad zx_putchar(void *cookie, int row, int col, u_int uc, long attr)
988ca0ac2c7Sad {
989c7d8ba24Smacallan 	struct rasops_info *ri = cookie;
9901c134541Smacallan 	struct wsdisplay_font *font = PICK_FONT(ri, uc);
991c7d8ba24Smacallan 	struct vcons_screen *scr = ri->ri_hw;
992c7d8ba24Smacallan 	struct zx_softc *sc = scr->scr_cookie;
993579b9cbdStsutsui 	volatile uint32_t *dp;
994579b9cbdStsutsui 	uint8_t *fb;
995c7d8ba24Smacallan 	int fs, i, ul;
996c7d8ba24Smacallan 	uint32_t fg, bg;
997ca0ac2c7Sad 
998c7d8ba24Smacallan 	rasops_unpack_attr(attr, &fg, &bg, &ul);
999c7d8ba24Smacallan 	bg = ((uint32_t)ri->ri_devcmap[bg]) << 24;
1000c7d8ba24Smacallan 	fg = ((uint32_t)ri->ri_devcmap[fg]) << 24;
1001ca0ac2c7Sad 	if (uc == ' ') {
1002c7d8ba24Smacallan 		int x, y;
1003c7d8ba24Smacallan 
10041c134541Smacallan 		x = ri->ri_xorigin + font->fontwidth * col;
10051c134541Smacallan 		y = ri->ri_yorigin + font->fontheight * row;
10061c134541Smacallan 		zx_fillrect(sc, x, y, font->fontwidth,
10071c134541Smacallan 			    font->fontheight, bg, ZX_STD_ROP);
1008ca0ac2c7Sad 		return;
1009ca0ac2c7Sad 	}
1010ca0ac2c7Sad 
1011579b9cbdStsutsui 	dp = (volatile uint32_t *)sc->sc_pixels +
1012c7d8ba24Smacallan 	    ((row * font->fontheight + ri->ri_yorigin) << 11) +
1013c7d8ba24Smacallan 	    (col * font->fontwidth + ri->ri_xorigin);
1014579b9cbdStsutsui 	fb = (uint8_t *)font->data + (uc - font->firstchar) *
1015ca0ac2c7Sad 	    ri->ri_fontscale;
1016ca0ac2c7Sad 	fs = font->stride;
1017ca0ac2c7Sad 
1018f8fb75a4Stsutsui 	while ((bus_space_read_4(sc->sc_bt, sc->sc_bhzc, zc_csr) &
1019f8fb75a4Stsutsui 	    ZX_CSR_BLT_BUSY) != 0)
1020ca0ac2c7Sad 		;
1021ca0ac2c7Sad 
1022f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_rop, ZX_STD_ROP);
1023c7d8ba24Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_fg, fg);
1024c7d8ba24Smacallan 	bus_space_write_4(sc->sc_bt, sc->sc_bhzdss0, zd_bg, bg);
1025f8fb75a4Stsutsui 	bus_space_write_4(sc->sc_bt, sc->sc_bhzc, zc_fontmsk,
1026c7d8ba24Smacallan 	    0xffffffff << (32 - font->fontwidth));
1027ca0ac2c7Sad 
1028c7d8ba24Smacallan 	if (font->fontwidth <= 8) {
1029c7d8ba24Smacallan 		for (i = font->fontheight; i != 0; i--, dp += 2048) {
1030ca0ac2c7Sad 			*dp = *fb << 24;
1031ca0ac2c7Sad 			fb += fs;
1032ca0ac2c7Sad 		}
1033ca0ac2c7Sad 	} else {
1034c7d8ba24Smacallan 		for (i = font->fontheight; i != 0; i--, dp += 2048) {
1035579b9cbdStsutsui 			*dp = *((uint16_t *)fb) << 16;
1036ca0ac2c7Sad 			fb += fs;
1037ca0ac2c7Sad 		}
1038ca0ac2c7Sad 	}
1039ca0ac2c7Sad 
1040ca0ac2c7Sad 	if (ul) {
1041ca0ac2c7Sad 		dp -= 4096;
1042ca0ac2c7Sad 		*dp = 0xffffffff;
1043ca0ac2c7Sad 	}
1044ca0ac2c7Sad }
1045c7d8ba24Smacallan 
1046c7d8ba24Smacallan static int
zx_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)1047c7d8ba24Smacallan zx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
1048c7d8ba24Smacallan 	struct lwp *l)
1049c7d8ba24Smacallan {
1050c7d8ba24Smacallan 	/* we'll probably need to add more stuff here */
1051c7d8ba24Smacallan 	struct vcons_data *vd = v;
1052c7d8ba24Smacallan 	struct zx_softc *sc = vd->cookie;
1053c7d8ba24Smacallan 	struct wsdisplay_fbinfo *wdf;
1054c7d8ba24Smacallan 	struct vcons_screen *ms = sc->vd.active;
105594553692Smacallan 	struct rasops_info *ri = &ms->scr_ri;
1056c7d8ba24Smacallan 	switch (cmd) {
1057c7d8ba24Smacallan 		case WSDISPLAYIO_GTYPE:
1058c7d8ba24Smacallan 			*(u_int *)data = WSDISPLAY_TYPE_SUNTCX;
1059c7d8ba24Smacallan 			return 0;
1060c7d8ba24Smacallan 		case WSDISPLAYIO_GINFO:
1061c7d8ba24Smacallan 			wdf = (void *)data;
1062c7d8ba24Smacallan 			wdf->height = ri->ri_height;
1063c7d8ba24Smacallan 			wdf->width = ri->ri_width;
1064c7d8ba24Smacallan 			wdf->depth = ri->ri_depth;
1065c7d8ba24Smacallan 			wdf->cmsize = 256;
1066c7d8ba24Smacallan 			return 0;
1067c7d8ba24Smacallan 
1068c7d8ba24Smacallan 		case WSDISPLAYIO_GETCMAP:
1069c7d8ba24Smacallan 			return zx_getcmap(sc,
1070c7d8ba24Smacallan 			    (struct wsdisplay_cmap *)data);
1071c7d8ba24Smacallan 		case WSDISPLAYIO_PUTCMAP:
1072c7d8ba24Smacallan 			return zx_putcmap(sc,
1073c7d8ba24Smacallan 			    (struct wsdisplay_cmap *)data);
1074c7d8ba24Smacallan 
1075c7d8ba24Smacallan 		case WSDISPLAYIO_SMODE:
1076c7d8ba24Smacallan 			{
1077c7d8ba24Smacallan 				int new_mode = *(int*)data;
1078c7d8ba24Smacallan 				if (new_mode != sc->sc_mode)
1079c7d8ba24Smacallan 				{
1080c7d8ba24Smacallan 					sc->sc_mode = new_mode;
1081c7d8ba24Smacallan 					if(new_mode == WSDISPLAYIO_MODE_EMUL)
1082c7d8ba24Smacallan 					{
1083647d0c59Smacallan 						zx_reset(sc);
1084c7d8ba24Smacallan 						vcons_redraw_screen(ms);
1085c7d8ba24Smacallan 					}
1086c7d8ba24Smacallan 				}
1087c7d8ba24Smacallan 			}
108894553692Smacallan 			return 0;
1089c7d8ba24Smacallan 	}
1090c7d8ba24Smacallan 	return EPASSTHROUGH;
1091c7d8ba24Smacallan }
1092c7d8ba24Smacallan 
1093c7d8ba24Smacallan static paddr_t
zx_mmap(void * v,void * vs,off_t offset,int prot)1094c7d8ba24Smacallan zx_mmap(void *v, void *vs, off_t offset, int prot)
1095c7d8ba24Smacallan {
1096c7d8ba24Smacallan 	/* I'm not at all sure this is the right thing to do */
1097c7d8ba24Smacallan 	return zxmmap(0, offset, prot); /* assume minor dev 0 for now */
1098c7d8ba24Smacallan }
1099c7d8ba24Smacallan 
1100c7d8ba24Smacallan static int
zx_putcmap(struct zx_softc * sc,struct wsdisplay_cmap * cm)1101c7d8ba24Smacallan zx_putcmap(struct zx_softc *sc, struct wsdisplay_cmap *cm)
1102c7d8ba24Smacallan {
1103c7d8ba24Smacallan 	u_int index = cm->index;
1104c7d8ba24Smacallan 	u_int count = cm->count;
1105c7d8ba24Smacallan 	int error,i;
1106c7d8ba24Smacallan 	if (index >= 256 || count > 256 || index + count > 256)
1107c7d8ba24Smacallan 		return EINVAL;
1108c7d8ba24Smacallan 
1109c7d8ba24Smacallan 	for (i = 0; i < count; i++)
1110c7d8ba24Smacallan 	{
1111c7d8ba24Smacallan 		error = copyin(&cm->red[i],
1112c7d8ba24Smacallan 		    &sc->sc_cmap[index + i], 1);
1113c7d8ba24Smacallan 		if (error)
1114c7d8ba24Smacallan 			return error;
1115c7d8ba24Smacallan 		error = copyin(&cm->green[i],
1116c7d8ba24Smacallan 		    &sc->sc_cmap[index + i + 256], 1);
1117c7d8ba24Smacallan 		if (error)
1118c7d8ba24Smacallan 			return error;
1119c7d8ba24Smacallan 		error = copyin(&cm->blue[i],
1120c7d8ba24Smacallan 		    &sc->sc_cmap[index + i + 512], 1);
1121c7d8ba24Smacallan 		if (error)
1122c7d8ba24Smacallan 			return error;
1123c7d8ba24Smacallan 	}
1124c7d8ba24Smacallan 	zx_cmap_put(sc);
1125c7d8ba24Smacallan 
1126c7d8ba24Smacallan 	return 0;
1127c7d8ba24Smacallan }
1128c7d8ba24Smacallan 
1129c7d8ba24Smacallan static int
zx_getcmap(struct zx_softc * sc,struct wsdisplay_cmap * cm)1130c7d8ba24Smacallan zx_getcmap(struct zx_softc *sc, struct wsdisplay_cmap *cm)
1131c7d8ba24Smacallan {
1132c7d8ba24Smacallan 	u_int index = cm->index;
1133c7d8ba24Smacallan 	u_int count = cm->count;
1134c7d8ba24Smacallan 	int error,i;
1135c7d8ba24Smacallan 
1136c7d8ba24Smacallan 	if (index >= 256 || count > 256 || index + count > 256)
1137c7d8ba24Smacallan 		return EINVAL;
1138c7d8ba24Smacallan 
1139c7d8ba24Smacallan 	for (i = 0; i < count; i++)
1140c7d8ba24Smacallan 	{
1141c7d8ba24Smacallan 		error = copyout(&sc->sc_cmap[index + i],
1142c7d8ba24Smacallan 		    &cm->red[i], 1);
1143c7d8ba24Smacallan 		if (error)
1144c7d8ba24Smacallan 			return error;
1145c7d8ba24Smacallan 		error = copyout(&sc->sc_cmap[index + i + 256],
1146c7d8ba24Smacallan 		    &cm->green[i], 1);
1147c7d8ba24Smacallan 		if (error)
1148c7d8ba24Smacallan 			return error;
1149c7d8ba24Smacallan 		error = copyout(&sc->sc_cmap[index + i + 256],
1150c7d8ba24Smacallan 		    &cm->blue[i], 1);
1151c7d8ba24Smacallan 		if (error)
1152c7d8ba24Smacallan 			return error;
1153c7d8ba24Smacallan 	}
1154c7d8ba24Smacallan 
1155c7d8ba24Smacallan 	return 0;
1156c7d8ba24Smacallan }
1157c7d8ba24Smacallan 
1158c7d8ba24Smacallan static void
zx_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)1159c7d8ba24Smacallan zx_init_screen(void *cookie, struct vcons_screen *scr,
1160c7d8ba24Smacallan     int existing, long *defattr)
1161c7d8ba24Smacallan {
1162c7d8ba24Smacallan 	struct zx_softc *sc = cookie;
1163c7d8ba24Smacallan 	struct rasops_info *ri = &scr->scr_ri;
1164c7d8ba24Smacallan 
1165c7d8ba24Smacallan 	ri->ri_depth = 8; /*sc->sc_fb.fb_type.fb_depth = 32;*/
1166c7d8ba24Smacallan 	ri->ri_width = sc->sc_width;
1167c7d8ba24Smacallan 	ri->ri_height = sc->sc_height;
1168c7d8ba24Smacallan 	ri->ri_stride = sc->sc_stride;
1169c7d8ba24Smacallan 	ri->ri_flg = RI_CENTER;
1170c7d8ba24Smacallan 
1171c7d8ba24Smacallan 	ri->ri_bits = (void *)sc->sc_pixels;
1172c7d8ba24Smacallan 
11732cbec7eeSmacallan 	rasops_init(ri, 0, 0);
1174c7d8ba24Smacallan 	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
1175c7d8ba24Smacallan 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
1176c7d8ba24Smacallan 		    sc->sc_width / ri->ri_font->fontwidth);
1177c7d8ba24Smacallan 
1178c7d8ba24Smacallan 	ri->ri_hw = scr;
1179c7d8ba24Smacallan 
1180c7d8ba24Smacallan 	ri->ri_ops.cursor = zx_do_cursor;
1181c7d8ba24Smacallan 	ri->ri_ops.copycols = zx_copycols;
1182c7d8ba24Smacallan 	ri->ri_ops.copyrows = zx_copyrows;
1183c7d8ba24Smacallan 	ri->ri_ops.erasecols = zx_erasecols;
1184c7d8ba24Smacallan 	ri->ri_ops.eraserows = zx_eraserows;
1185c7d8ba24Smacallan 	ri->ri_ops.putchar = zx_putchar;
1186c7d8ba24Smacallan }
1187