xref: /netbsd-src/sys/dev/sbus/agten.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: agten.c,v 1.34 2021/08/07 16:19:15 thorpej Exp $ */
209a01aa6Smacallan 
309a01aa6Smacallan /*-
409a01aa6Smacallan  * Copyright (c) 2007 Michael Lorenz
509a01aa6Smacallan  * All rights reserved.
609a01aa6Smacallan  *
709a01aa6Smacallan  * Redistribution and use in source and binary forms, with or without
809a01aa6Smacallan  * modification, are permitted provided that the following conditions
909a01aa6Smacallan  * are met:
1009a01aa6Smacallan  * 1. Redistributions of source code must retain the above copyright
1109a01aa6Smacallan  *    notice, this list of conditions and the following disclaimer.
1209a01aa6Smacallan  * 2. Redistributions in binary form must reproduce the above copyright
1309a01aa6Smacallan  *    notice, this list of conditions and the following disclaimer in the
1409a01aa6Smacallan  *    documentation and/or other materials provided with the distribution.
1509a01aa6Smacallan  *
1609a01aa6Smacallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1709a01aa6Smacallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1809a01aa6Smacallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1909a01aa6Smacallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2009a01aa6Smacallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2109a01aa6Smacallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2209a01aa6Smacallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2309a01aa6Smacallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2409a01aa6Smacallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2509a01aa6Smacallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2609a01aa6Smacallan  * POSSIBILITY OF SUCH DAMAGE.
2709a01aa6Smacallan  */
2809a01aa6Smacallan 
2909a01aa6Smacallan #include <sys/cdefs.h>
30*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: agten.c,v 1.34 2021/08/07 16:19:15 thorpej Exp $");
3109a01aa6Smacallan 
3209a01aa6Smacallan /*
3309a01aa6Smacallan  * a driver for the Fujitsu AG-10e SBus framebuffer
3409a01aa6Smacallan  *
3509a01aa6Smacallan  * this thing is Frankenstein's Monster among graphics boards.
3609a01aa6Smacallan  * it contains three graphics chips:
3762d7fcf0Smacallan  * a GLint 300SX - 24bit stuff, double-buffered
3809a01aa6Smacallan  * an Imagine 128 which provides an 8bit overlay
3909a01aa6Smacallan  * a Weitek P9100 which provides WIDs
4009a01aa6Smacallan  * so here we need to mess only with the P9100 and the I128 - for X we just
4109a01aa6Smacallan  * hide the overlay and let the Xserver mess with the GLint
4209a01aa6Smacallan  */
4309a01aa6Smacallan 
4409a01aa6Smacallan #include <sys/param.h>
4509a01aa6Smacallan #include <sys/systm.h>
4609a01aa6Smacallan #include <sys/kernel.h>
4709a01aa6Smacallan #include <sys/device.h>
4809a01aa6Smacallan #include <sys/proc.h>
4909a01aa6Smacallan #include <sys/mutex.h>
5009a01aa6Smacallan #include <sys/ioctl.h>
5109a01aa6Smacallan #include <sys/kernel.h>
5209a01aa6Smacallan #include <sys/systm.h>
532be61cb9Smacallan #include <sys/conf.h>
5409a01aa6Smacallan 
5509a01aa6Smacallan #include <dev/sun/fbio.h>
5609a01aa6Smacallan #include <dev/sun/fbvar.h>
5709a01aa6Smacallan #include <dev/sun/btreg.h>
5809a01aa6Smacallan #include <dev/sun/btvar.h>
5909a01aa6Smacallan 
60a2a38285Sad #include <sys/bus.h>
6109a01aa6Smacallan #include <machine/autoconf.h>
6209a01aa6Smacallan 
6309a01aa6Smacallan #include <dev/sbus/sbusvar.h>
6409a01aa6Smacallan 
6509a01aa6Smacallan #include <dev/wscons/wsconsio.h>
6609a01aa6Smacallan #include <dev/wscons/wsdisplayvar.h>
6709a01aa6Smacallan #include <dev/rasops/rasops.h>
6809a01aa6Smacallan #include <dev/wsfont/wsfont.h>
6909a01aa6Smacallan 
7009a01aa6Smacallan #include <dev/wscons/wsdisplay_vconsvar.h>
7162d7fcf0Smacallan #include <dev/wscons/wsdisplay_glyphcachevar.h>
7209a01aa6Smacallan 
7309a01aa6Smacallan #include <dev/sbus/p9100reg.h>
7409a01aa6Smacallan #include <dev/ic/ibm561reg.h>
7509a01aa6Smacallan #include <dev/ic/i128reg.h>
7609a01aa6Smacallan #include <dev/ic/i128var.h>
7709a01aa6Smacallan 
7809a01aa6Smacallan #include "opt_agten.h"
7908c90221Stsutsui #include "ioconf.h"
8009a01aa6Smacallan 
81d16a259fScegger static int	agten_match(device_t, cfdata_t, void *);
820c74b4e4Smacallan static void	agten_attach(device_t, device_t, void *);
8309a01aa6Smacallan 
8409a01aa6Smacallan static int	agten_ioctl(void *, void *, u_long, void *, int, struct lwp *);
8509a01aa6Smacallan static paddr_t	agten_mmap(void *, void *, off_t, int);
8609a01aa6Smacallan static void	agten_init_screen(void *, struct vcons_screen *, int, long *);
8709a01aa6Smacallan 
8809a01aa6Smacallan struct agten_softc {
890c74b4e4Smacallan 	device_t	sc_dev;		/* base device */
9009a01aa6Smacallan 	struct fbdevice	sc_fb;		/* frame buffer device */
9109a01aa6Smacallan 
9209a01aa6Smacallan 	struct vcons_screen sc_console_screen;
9309a01aa6Smacallan 	struct wsscreen_descr sc_defaultscreen_descr;
9409a01aa6Smacallan 	const struct wsscreen_descr *sc_screens[1];
9509a01aa6Smacallan 	struct wsscreen_list sc_screenlist;
9609a01aa6Smacallan 
9709a01aa6Smacallan 	bus_space_tag_t	sc_bustag;
9809a01aa6Smacallan 
9909a01aa6Smacallan 	bus_space_handle_t 	sc_i128_fbh;
10009a01aa6Smacallan 	bus_size_t		sc_i128_fbsz;
10109a01aa6Smacallan 	bus_space_handle_t 	sc_i128_regh;
10209a01aa6Smacallan 	bus_space_handle_t 	sc_p9100_regh;
103639b5a68Smacallan 	bus_addr_t		sc_glint_fb;
104639b5a68Smacallan 	bus_addr_t		sc_glint_regs;
105639b5a68Smacallan 	uint32_t		sc_glint_fbsz;
10609a01aa6Smacallan 
10709a01aa6Smacallan 	uint32_t	sc_width;
10809a01aa6Smacallan 	uint32_t	sc_height;	/* panel width / height */
10909a01aa6Smacallan 	uint32_t	sc_stride;
11009a01aa6Smacallan 	uint32_t	sc_depth;
11109a01aa6Smacallan 
112699639e6Smacallan 	int sc_cursor_x;
113699639e6Smacallan 	int sc_cursor_y;
114f9794c16Smacallan 	int sc_video;			/* video output enabled */
115699639e6Smacallan 
1162be61cb9Smacallan 	/* some /dev/fb* stuff */
1172be61cb9Smacallan 	int sc_fb_is_open;
1182be61cb9Smacallan 
11909a01aa6Smacallan 	union	bt_cmap sc_cmap;	/* Brooktree color map */
12009a01aa6Smacallan 
12109a01aa6Smacallan 	int sc_mode;
12209a01aa6Smacallan 	uint32_t sc_bg;
12362d7fcf0Smacallan 
12462d7fcf0Smacallan 	void (*sc_putchar)(void *, int, int, u_int, long);
12562d7fcf0Smacallan 
12609a01aa6Smacallan 	struct vcons_data vd;
12762d7fcf0Smacallan 	glyphcache sc_gc;
12809a01aa6Smacallan };
12909a01aa6Smacallan 
130dcb185e7Smacallan CFATTACH_DECL_NEW(agten, sizeof(struct agten_softc),
13109a01aa6Smacallan     agten_match, agten_attach, NULL, NULL);
13209a01aa6Smacallan 
13309a01aa6Smacallan 
13409a01aa6Smacallan static int	agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *);
13509a01aa6Smacallan static int 	agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *);
13609a01aa6Smacallan static int 	agten_putpalreg(struct agten_softc *, uint8_t, uint8_t,
13709a01aa6Smacallan 			    uint8_t, uint8_t);
13809a01aa6Smacallan static void	agten_init(struct agten_softc *);
13956d11704Smacallan static void	agten_init_cmap(struct agten_softc *, struct rasops_info *);
140639b5a68Smacallan static void	agten_gfx(struct agten_softc *);
1412be61cb9Smacallan static void	agten_set_video(struct agten_softc *, int);
1422be61cb9Smacallan static int	agten_get_video(struct agten_softc *);
14309a01aa6Smacallan 
14462d7fcf0Smacallan static void	agten_bitblt(void *, int, int, int, int, int, int, int);
14562d7fcf0Smacallan static void 	agten_rectfill(void *, int, int, int, int, long);
14662d7fcf0Smacallan 
14762d7fcf0Smacallan static void	agten_putchar(void *, int, int, u_int, long);
14862d7fcf0Smacallan static void	agten_cursor(void *, int, int, int);
14909a01aa6Smacallan static void	agten_copycols(void *, int, int, int, int);
15009a01aa6Smacallan static void	agten_erasecols(void *, int, int, int, long);
15109a01aa6Smacallan static void	agten_copyrows(void *, int, int, int);
15209a01aa6Smacallan static void	agten_eraserows(void *, int, int, long);
15309a01aa6Smacallan 
154699639e6Smacallan static void	agten_move_cursor(struct agten_softc *, int, int);
155699639e6Smacallan static int	agten_do_cursor(struct agten_softc *sc,
156699639e6Smacallan 				struct wsdisplay_cursor *);
1572be61cb9Smacallan static int	agten_do_sun_cursor(struct agten_softc *sc,
1582be61cb9Smacallan 				struct fbcursor *);
159699639e6Smacallan 
160f9794c16Smacallan static uint16_t util_interleave(uint8_t, uint8_t);
161f9794c16Smacallan static uint16_t util_interleave_lin(uint8_t, uint8_t);
162699639e6Smacallan 
16309a01aa6Smacallan extern const u_char rasops_cmap[768];
16409a01aa6Smacallan 
16509a01aa6Smacallan struct wsdisplay_accessops agten_accessops = {
16609a01aa6Smacallan 	agten_ioctl,
16709a01aa6Smacallan 	agten_mmap,
16809a01aa6Smacallan 	NULL,	/* alloc_screen */
16909a01aa6Smacallan 	NULL,	/* free_screen */
17009a01aa6Smacallan 	NULL,	/* show_screen */
17109a01aa6Smacallan 	NULL, 	/* load_font */
17209a01aa6Smacallan 	NULL,	/* pollc */
17309a01aa6Smacallan 	NULL	/* scroll */
17409a01aa6Smacallan };
17509a01aa6Smacallan 
1762be61cb9Smacallan /* /dev/fb* stuff */
1772be61cb9Smacallan 
1782be61cb9Smacallan static int agten_fb_open(dev_t, int, int, struct lwp *);
1792be61cb9Smacallan static int agten_fb_close(dev_t, int, int, struct lwp *);
1802be61cb9Smacallan static int agten_fb_ioctl(dev_t, u_long, void *, int, struct lwp *);
1812be61cb9Smacallan static paddr_t agten_fb_mmap(dev_t, off_t, int);
1820c74b4e4Smacallan static void agten_fb_unblank(device_t);
1832be61cb9Smacallan 
1842be61cb9Smacallan static struct fbdriver agtenfbdriver = {
1852be61cb9Smacallan 	agten_fb_unblank, agten_fb_open, agten_fb_close, agten_fb_ioctl,
1862be61cb9Smacallan 	nopoll, agten_fb_mmap, nokqfilter
1872be61cb9Smacallan };
1882be61cb9Smacallan 
18909a01aa6Smacallan static inline void
agten_write_dac(struct agten_softc * sc,int reg,uint8_t val)19009a01aa6Smacallan agten_write_dac(struct agten_softc *sc, int reg, uint8_t val)
19109a01aa6Smacallan {
19209a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
19309a01aa6Smacallan 	    0x200 + (reg << 2), (uint32_t)val << 16);
19409a01aa6Smacallan }
19509a01aa6Smacallan 
19609a01aa6Smacallan static inline void
agten_write_idx(struct agten_softc * sc,int offset)19709a01aa6Smacallan agten_write_idx(struct agten_softc *sc, int offset)
19809a01aa6Smacallan {
19909a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
20009a01aa6Smacallan 	    0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16);
20109a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
20209a01aa6Smacallan 	    0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16);
20309a01aa6Smacallan }
20409a01aa6Smacallan 
20509a01aa6Smacallan static inline void
agten_write_dac_10(struct agten_softc * sc,int reg,uint16_t val)20609a01aa6Smacallan agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val)
20709a01aa6Smacallan {
20809a01aa6Smacallan 	agten_write_dac(sc, reg, (val >> 2) & 0xff);
20909a01aa6Smacallan 	agten_write_dac(sc, reg, (val & 0x3) << 6);
21009a01aa6Smacallan }
21109a01aa6Smacallan 
21209a01aa6Smacallan static int
agten_match(device_t dev,cfdata_t cf,void * aux)213d16a259fScegger agten_match(device_t dev, cfdata_t cf, void *aux)
21409a01aa6Smacallan {
21509a01aa6Smacallan 	struct sbus_attach_args *sa = aux;
21609a01aa6Smacallan 
21709a01aa6Smacallan 	if (strcmp("PFU,aga", sa->sa_name) == 0)
21809a01aa6Smacallan 		return 100;
21909a01aa6Smacallan 	return 0;
22009a01aa6Smacallan }
22109a01aa6Smacallan 
22209a01aa6Smacallan static void
agten_attach(device_t parent,device_t dev,void * aux)2230c74b4e4Smacallan agten_attach(device_t parent, device_t dev, void *aux)
22409a01aa6Smacallan {
2250c74b4e4Smacallan 	struct agten_softc *sc = device_private(dev);
22609a01aa6Smacallan 	struct sbus_attach_args *sa = aux;
22709a01aa6Smacallan 	struct fbdevice *fb = &sc->sc_fb;
22809a01aa6Smacallan 	struct wsemuldisplaydev_attach_args aa;
22909a01aa6Smacallan 	struct rasops_info *ri;
23009a01aa6Smacallan 	long defattr;
23109a01aa6Smacallan 	uint32_t reg;
23209a01aa6Smacallan 	int node = sa->sa_node;
23309a01aa6Smacallan 	int console;
23409a01aa6Smacallan 
2350c74b4e4Smacallan  	sc->sc_dev = dev;
23609a01aa6Smacallan 	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
23709a01aa6Smacallan 		"default",
23809a01aa6Smacallan 		0, 0,
23909a01aa6Smacallan 		NULL,
24009a01aa6Smacallan 		8, 16,
24109a01aa6Smacallan 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
24209a01aa6Smacallan 		NULL
24309a01aa6Smacallan 	};
24409a01aa6Smacallan 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
24509a01aa6Smacallan 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
24609a01aa6Smacallan 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
2472be61cb9Smacallan 	sc->sc_fb_is_open = 0;
248f9794c16Smacallan 	sc->sc_video = -1;
24909a01aa6Smacallan 	sc->sc_bustag = sa->sa_bustag;
25062d7fcf0Smacallan 	sc->sc_putchar = NULL;
25109a01aa6Smacallan 
252f0f02f06Smacallan 	sc->sc_width = prom_getpropint(node, "ffb_width", 1152);
253f0f02f06Smacallan 	sc->sc_height = prom_getpropint(node, "ffb_height", 900);
254f0f02f06Smacallan 	sc->sc_depth = prom_getpropint(node, "ffb_depth", 8);
255f0f02f06Smacallan 	sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
256f0f02f06Smacallan 
25709a01aa6Smacallan 	reg = prom_getpropint(node, "i128_fb_physaddr", -1);
25809a01aa6Smacallan 	sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1);
2590483b5b9Smacallan 	if (sbus_bus_map(sc->sc_bustag,
26009a01aa6Smacallan 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
261565f3dd6Smacallan 	    round_page(sc->sc_stride * sc->sc_height),
2620483b5b9Smacallan 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
263f0f02f06Smacallan 	    &sc->sc_i128_fbh) != 0) {
26409a01aa6Smacallan 
2654c5fa20dScegger 		aprint_error_dev(dev, "unable to map the framebuffer\n");
26609a01aa6Smacallan 		return;
26709a01aa6Smacallan 	}
26809a01aa6Smacallan 	fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh);
26909a01aa6Smacallan 
270639b5a68Smacallan 	reg = prom_getpropint(node, "i128_reg_physaddr", -1);
271639b5a68Smacallan 	if (sbus_bus_map(sc->sc_bustag,
272639b5a68Smacallan 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
273639b5a68Smacallan 	    0x10000, 0, &sc->sc_i128_regh) != 0) {
274639b5a68Smacallan 
2754c5fa20dScegger 		aprint_error_dev(dev, "unable to map I128 registers\n");
276639b5a68Smacallan 		return;
277639b5a68Smacallan 	}
278639b5a68Smacallan 
27909a01aa6Smacallan 	reg = prom_getpropint(node, "p9100_reg_physaddr", -1);
28009a01aa6Smacallan 	if (sbus_bus_map(sc->sc_bustag,
28109a01aa6Smacallan 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
28209a01aa6Smacallan 	    0x8000, 0, &sc->sc_p9100_regh) != 0) {
28309a01aa6Smacallan 
2844c5fa20dScegger 		aprint_error_dev(dev, "unable to map P9100 registers\n");
28509a01aa6Smacallan 		return;
28609a01aa6Smacallan 	}
28709a01aa6Smacallan 
288639b5a68Smacallan 	reg = prom_getpropint(node, "glint_fb0_physaddr", -1);
289639b5a68Smacallan 	sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag,
290639b5a68Smacallan 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
291a53919d5Smacallan 	sc->sc_glint_fbsz = prom_getpropint(node, "glint_lb_size", -1);
292639b5a68Smacallan 	reg = prom_getpropint(node, "glint_reg_physaddr", -1);
293639b5a68Smacallan 	sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag,
294639b5a68Smacallan 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
2957863a2faSmacallan 
29609a01aa6Smacallan #if 0
29709a01aa6Smacallan 	bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO,
29809a01aa6Smacallan 	    agten_intr, sc);
29909a01aa6Smacallan #endif
30009a01aa6Smacallan 
301a53919d5Smacallan 	printf(": %dx%d\n", sc->sc_width, sc->sc_height);
30209a01aa6Smacallan 	agten_init(sc);
30309a01aa6Smacallan 
30409a01aa6Smacallan 	console = fb_is_console(node);
30509a01aa6Smacallan 
30609a01aa6Smacallan 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
30709a01aa6Smacallan 	    &agten_accessops);
30809a01aa6Smacallan 	sc->vd.init_screen = agten_init_screen;
30909a01aa6Smacallan 
31009a01aa6Smacallan 	ri = &sc->sc_console_screen.scr_ri;
31109a01aa6Smacallan 
31262d7fcf0Smacallan 	sc->sc_gc.gc_bitblt = agten_bitblt;
31362d7fcf0Smacallan 	sc->sc_gc.gc_rectfill = agten_rectfill;
31462d7fcf0Smacallan 	sc->sc_gc.gc_blitcookie = sc;
31562d7fcf0Smacallan 	sc->sc_gc.gc_rop = CR_COPY;
31662d7fcf0Smacallan 
31762d7fcf0Smacallan #if defined(AGTEN_DEBUG)
31862d7fcf0Smacallan 	sc->sc_height -= 200;
31962d7fcf0Smacallan #endif
32062d7fcf0Smacallan 
32109a01aa6Smacallan 	if (console) {
32209a01aa6Smacallan 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
32309a01aa6Smacallan 		    &defattr);
32409a01aa6Smacallan 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
32509a01aa6Smacallan 
32609a01aa6Smacallan 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
32709a01aa6Smacallan 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
32809a01aa6Smacallan 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
32909a01aa6Smacallan 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
33062d7fcf0Smacallan 		glyphcache_init(&sc->sc_gc,
33162d7fcf0Smacallan 		    sc->sc_height + 5,
33262d7fcf0Smacallan 		    (0x400000 / sc->sc_stride) - sc->sc_height - 5,
33362d7fcf0Smacallan 		    sc->sc_width,
33462d7fcf0Smacallan 		    ri->ri_font->fontwidth,
33562d7fcf0Smacallan 		    ri->ri_font->fontheight,
33662d7fcf0Smacallan 		    defattr);
33762d7fcf0Smacallan 
33809a01aa6Smacallan 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
33909a01aa6Smacallan 		    defattr);
3407863a2faSmacallan 		i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0,
3417863a2faSmacallan 		    sc->sc_width, sc->sc_height,
3427863a2faSmacallan 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
343a63997dcSmacallan 		vcons_replay_msgbuf(&sc->sc_console_screen);
34409a01aa6Smacallan 	} else {
34509a01aa6Smacallan 		/*
34609a01aa6Smacallan 		 * since we're not the console we can postpone the rest
34709a01aa6Smacallan 		 * until someone actually allocates a screen for us
34809a01aa6Smacallan 		 */
34962d7fcf0Smacallan 		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
35062d7fcf0Smacallan 			/* do some minimal setup to avoid weirdnesses later */
35162d7fcf0Smacallan 			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
35262d7fcf0Smacallan 			    &defattr);
3534453737fSmacallan 		} else
3544453737fSmacallan 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
3554453737fSmacallan 
35662d7fcf0Smacallan 		glyphcache_init(&sc->sc_gc,
35762d7fcf0Smacallan 		    sc->sc_height + 5,
35862d7fcf0Smacallan 		    (0x400000 / sc->sc_stride) - sc->sc_height - 5,
35962d7fcf0Smacallan 		    sc->sc_width,
36062d7fcf0Smacallan 		    ri->ri_font->fontwidth,
36162d7fcf0Smacallan 		    ri->ri_font->fontheight,
36262d7fcf0Smacallan 		    defattr);
36309a01aa6Smacallan 	}
36409a01aa6Smacallan 
36509a01aa6Smacallan 	/* Initialize the default color map. */
36656d11704Smacallan 	agten_init_cmap(sc, ri);
36709a01aa6Smacallan 
36809a01aa6Smacallan 	aa.console = console;
36909a01aa6Smacallan 	aa.scrdata = &sc->sc_screenlist;
37009a01aa6Smacallan 	aa.accessops = &agten_accessops;
37109a01aa6Smacallan 	aa.accesscookie = &sc->vd;
37209a01aa6Smacallan 
373*c7fb772bSthorpej 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
3742be61cb9Smacallan 
3752be61cb9Smacallan 	fb->fb_driver = &agtenfbdriver;
3760c74b4e4Smacallan 	fb->fb_device = sc->sc_dev;
3770c74b4e4Smacallan 	fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK;
3782be61cb9Smacallan 	fb->fb_type.fb_type = FBTYPE_AG10E;
3792be61cb9Smacallan 	fb->fb_type.fb_cmsize = 256;	/* doesn't matter, we're always 24bit */
3802be61cb9Smacallan 	fb->fb_type.fb_size = sc->sc_glint_fbsz;
3812be61cb9Smacallan 	fb->fb_type.fb_width = sc->sc_width;
3822be61cb9Smacallan 	fb->fb_type.fb_height = sc->sc_height;
3832be61cb9Smacallan 	fb->fb_type.fb_depth = 32;
384fc934dfaSmacallan 	fb->fb_linebytes = sc->sc_stride << 2;
3852be61cb9Smacallan 	fb_attach(fb, console);
386f9794c16Smacallan 	agten_set_video(sc, 1);	/* make sure video's on */
38709a01aa6Smacallan }
38809a01aa6Smacallan 
38909a01aa6Smacallan static int
agten_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)39009a01aa6Smacallan agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
39109a01aa6Smacallan 	struct lwp *l)
39209a01aa6Smacallan {
39309a01aa6Smacallan 	struct vcons_data *vd = v;
39409a01aa6Smacallan 	struct agten_softc *sc = vd->cookie;
39509a01aa6Smacallan 	struct wsdisplay_fbinfo *wdf;
39609a01aa6Smacallan 	struct vcons_screen *ms = vd->active;
39709a01aa6Smacallan 
39809a01aa6Smacallan 	switch (cmd) {
39909a01aa6Smacallan 
400639b5a68Smacallan 		case WSDISPLAYIO_GTYPE:
401639b5a68Smacallan 			*(u_int *)data = WSDISPLAY_TYPE_AG10;
402639b5a68Smacallan 			return 0;
403639b5a68Smacallan 
40409a01aa6Smacallan 		case WSDISPLAYIO_GINFO:
40509a01aa6Smacallan 			if (ms == NULL)
40609a01aa6Smacallan 				return ENODEV;
40709a01aa6Smacallan 			wdf = (void *)data;
40809a01aa6Smacallan 			wdf->height = ms->scr_ri.ri_height;
40909a01aa6Smacallan 			wdf->width = ms->scr_ri.ri_width;
410639b5a68Smacallan 			wdf->depth = 32;
41109a01aa6Smacallan 			wdf->cmsize = 256;
41209a01aa6Smacallan 			return 0;
41309a01aa6Smacallan 
414f9794c16Smacallan 		case WSDISPLAYIO_GVIDEO:
415f9794c16Smacallan 			*(int *)data = sc->sc_video;
416f9794c16Smacallan 			return 0;
417f9794c16Smacallan 
418f9794c16Smacallan 		case WSDISPLAYIO_SVIDEO:
419f9794c16Smacallan 			agten_set_video(sc, *(int *)data);
420f9794c16Smacallan 			return 0;
421f9794c16Smacallan 
42209a01aa6Smacallan 		case WSDISPLAYIO_GETCMAP:
42309a01aa6Smacallan 			return agten_getcmap(sc,
42409a01aa6Smacallan 			    (struct wsdisplay_cmap *)data);
42509a01aa6Smacallan 
42609a01aa6Smacallan 		case WSDISPLAYIO_PUTCMAP:
42709a01aa6Smacallan 			return agten_putcmap(sc,
42809a01aa6Smacallan 			    (struct wsdisplay_cmap *)data);
42909a01aa6Smacallan 
43009a01aa6Smacallan 		case WSDISPLAYIO_LINEBYTES:
431639b5a68Smacallan 			*(u_int *)data = sc->sc_stride << 2;
43209a01aa6Smacallan 			return 0;
43309a01aa6Smacallan 
43409a01aa6Smacallan 		case WSDISPLAYIO_SMODE:
43509a01aa6Smacallan 			{
43609a01aa6Smacallan 				int new_mode = *(int*)data;
43709a01aa6Smacallan 				if (new_mode != sc->sc_mode) {
43809a01aa6Smacallan 					sc->sc_mode = new_mode;
43909a01aa6Smacallan 					if(new_mode == WSDISPLAYIO_MODE_EMUL) {
4407863a2faSmacallan 						agten_init(sc);
44156d11704Smacallan 						agten_init_cmap(sc,
44256d11704Smacallan 						    &ms->scr_ri);
44309a01aa6Smacallan 						vcons_redraw_screen(ms);
444639b5a68Smacallan 					} else {
445639b5a68Smacallan 						agten_gfx(sc);
44609a01aa6Smacallan 					}
44709a01aa6Smacallan 				}
44809a01aa6Smacallan 			}
44909a01aa6Smacallan 			return 0;
450699639e6Smacallan 
451699639e6Smacallan 		case WSDISPLAYIO_GCURPOS:
452699639e6Smacallan 			{
453699639e6Smacallan 				struct wsdisplay_curpos *cp = (void *)data;
454699639e6Smacallan 
455699639e6Smacallan 				cp->x = sc->sc_cursor_x;
456699639e6Smacallan 				cp->y = sc->sc_cursor_y;
457699639e6Smacallan 			}
458699639e6Smacallan 			return 0;
459699639e6Smacallan 
460699639e6Smacallan 		case WSDISPLAYIO_SCURPOS:
461699639e6Smacallan 			{
462699639e6Smacallan 				struct wsdisplay_curpos *cp = (void *)data;
463699639e6Smacallan 
464699639e6Smacallan 				agten_move_cursor(sc, cp->x, cp->y);
465699639e6Smacallan 			}
466699639e6Smacallan 			return 0;
467699639e6Smacallan 
468699639e6Smacallan 		case WSDISPLAYIO_GCURMAX:
469699639e6Smacallan 			{
470699639e6Smacallan 				struct wsdisplay_curpos *cp = (void *)data;
471699639e6Smacallan 
472699639e6Smacallan 				cp->x = 64;
473699639e6Smacallan 				cp->y = 64;
474699639e6Smacallan 			}
475699639e6Smacallan 			return 0;
476699639e6Smacallan 
477699639e6Smacallan 		case WSDISPLAYIO_SCURSOR:
478699639e6Smacallan 			{
479699639e6Smacallan 				struct wsdisplay_cursor *cursor = (void *)data;
480699639e6Smacallan 
481699639e6Smacallan 				return agten_do_cursor(sc, cursor);
482699639e6Smacallan 			}
48309a01aa6Smacallan 	}
48409a01aa6Smacallan 	return EPASSTHROUGH;
48509a01aa6Smacallan }
48609a01aa6Smacallan 
48709a01aa6Smacallan static paddr_t
agten_mmap(void * v,void * vs,off_t offset,int prot)48809a01aa6Smacallan agten_mmap(void *v, void *vs, off_t offset, int prot)
48909a01aa6Smacallan {
49009a01aa6Smacallan 	struct vcons_data *vd = v;
49109a01aa6Smacallan 	struct agten_softc *sc = vd->cookie;
49209a01aa6Smacallan 
493639b5a68Smacallan 	if (offset < sc->sc_glint_fbsz)
494639b5a68Smacallan 		return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset,
49509a01aa6Smacallan 		    prot, BUS_SPACE_MAP_LINEAR);
49609a01aa6Smacallan 	return -1;
49709a01aa6Smacallan }
49809a01aa6Smacallan 
49909a01aa6Smacallan static void
agten_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)50009a01aa6Smacallan agten_init_screen(void *cookie, struct vcons_screen *scr,
50109a01aa6Smacallan     int existing, long *defattr)
50209a01aa6Smacallan {
50309a01aa6Smacallan 	struct agten_softc *sc = cookie;
50409a01aa6Smacallan 	struct rasops_info *ri = &scr->scr_ri;
50509a01aa6Smacallan 
50609a01aa6Smacallan 	ri->ri_depth = sc->sc_depth;
50709a01aa6Smacallan 	ri->ri_width = sc->sc_width;
50809a01aa6Smacallan 	ri->ri_height = sc->sc_height;
50909a01aa6Smacallan 	ri->ri_stride = sc->sc_stride;
51056d11704Smacallan 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
51109a01aa6Smacallan 
51209a01aa6Smacallan 	ri->ri_bits = (char *)sc->sc_fb.fb_pixels;
51309a01aa6Smacallan 
51409a01aa6Smacallan 	if (existing) {
51509a01aa6Smacallan 		ri->ri_flg |= RI_CLEAR;
51609a01aa6Smacallan 	}
51709a01aa6Smacallan 
5182cbec7eeSmacallan 	rasops_init(ri, 0, 0);
51962d7fcf0Smacallan 	sc->sc_putchar = ri->ri_ops.putchar;
52062d7fcf0Smacallan 
52109a01aa6Smacallan 	ri->ri_caps = WSSCREEN_WSCOLORS;
52209a01aa6Smacallan 
52309a01aa6Smacallan 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
52409a01aa6Smacallan 		    sc->sc_width / ri->ri_font->fontwidth);
52509a01aa6Smacallan 
52609a01aa6Smacallan 	ri->ri_hw = scr;
52762d7fcf0Smacallan 	ri->ri_ops.putchar   = agten_putchar;
52862d7fcf0Smacallan 	ri->ri_ops.cursor    = agten_cursor;
52909a01aa6Smacallan 	ri->ri_ops.copyrows  = agten_copyrows;
53009a01aa6Smacallan 	ri->ri_ops.eraserows = agten_eraserows;
53109a01aa6Smacallan 	ri->ri_ops.copycols  = agten_copycols;
53209a01aa6Smacallan 	ri->ri_ops.erasecols = agten_erasecols;
53309a01aa6Smacallan 
53409a01aa6Smacallan }
53509a01aa6Smacallan 
53609a01aa6Smacallan static int
agten_putcmap(struct agten_softc * sc,struct wsdisplay_cmap * cm)53709a01aa6Smacallan agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
53809a01aa6Smacallan {
53909a01aa6Smacallan 	u_int index = cm->index;
54009a01aa6Smacallan 	u_int count = cm->count;
54109a01aa6Smacallan 	int i, error;
54209a01aa6Smacallan 	u_char rbuf[256], gbuf[256], bbuf[256];
54309a01aa6Smacallan 	u_char *r, *g, *b;
54409a01aa6Smacallan 
54509a01aa6Smacallan 	if (cm->index >= 256 || cm->count > 256 ||
54609a01aa6Smacallan 	    (cm->index + cm->count) > 256)
54709a01aa6Smacallan 		return EINVAL;
54809a01aa6Smacallan 	error = copyin(cm->red, &rbuf[index], count);
54909a01aa6Smacallan 	if (error)
55009a01aa6Smacallan 		return error;
55109a01aa6Smacallan 	error = copyin(cm->green, &gbuf[index], count);
55209a01aa6Smacallan 	if (error)
55309a01aa6Smacallan 		return error;
55409a01aa6Smacallan 	error = copyin(cm->blue, &bbuf[index], count);
55509a01aa6Smacallan 	if (error)
55609a01aa6Smacallan 		return error;
55709a01aa6Smacallan 
55809a01aa6Smacallan 	r = &rbuf[index];
55909a01aa6Smacallan 	g = &gbuf[index];
56009a01aa6Smacallan 	b = &bbuf[index];
56109a01aa6Smacallan 
56209a01aa6Smacallan 	for (i = 0; i < count; i++) {
56309a01aa6Smacallan 		agten_putpalreg(sc, index, *r, *g, *b);
56409a01aa6Smacallan 		index++;
56509a01aa6Smacallan 		r++, g++, b++;
56609a01aa6Smacallan 	}
56709a01aa6Smacallan 	return 0;
56809a01aa6Smacallan }
56909a01aa6Smacallan 
57009a01aa6Smacallan static int
agten_getcmap(struct agten_softc * sc,struct wsdisplay_cmap * cm)57109a01aa6Smacallan agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
57209a01aa6Smacallan {
57309a01aa6Smacallan 	u_int index = cm->index;
57409a01aa6Smacallan 	u_int count = cm->count;
57509a01aa6Smacallan 	int error, i;
57609a01aa6Smacallan 	uint8_t red[256], green[256], blue[256];
57709a01aa6Smacallan 
57809a01aa6Smacallan 	if (index >= 255 || count > 256 || index + count > 256)
57909a01aa6Smacallan 		return EINVAL;
58009a01aa6Smacallan 
58109a01aa6Smacallan 	i = index;
58209a01aa6Smacallan 	while (i < (index + count)) {
58309a01aa6Smacallan 		red[i] = sc->sc_cmap.cm_map[i][0];
58409a01aa6Smacallan 		green[i] = sc->sc_cmap.cm_map[i][1];
58509a01aa6Smacallan 		blue[i] = sc->sc_cmap.cm_map[i][2];
58609a01aa6Smacallan 		i++;
58709a01aa6Smacallan 	}
58809a01aa6Smacallan 	error = copyout(&red[index],   cm->red,   count);
58909a01aa6Smacallan 	if (error)
59009a01aa6Smacallan 		return error;
59109a01aa6Smacallan 	error = copyout(&green[index], cm->green, count);
59209a01aa6Smacallan 	if (error)
59309a01aa6Smacallan 		return error;
59409a01aa6Smacallan 	error = copyout(&blue[index],  cm->blue,  count);
59509a01aa6Smacallan 	if (error)
59609a01aa6Smacallan 		return error;
59709a01aa6Smacallan 
59809a01aa6Smacallan 	return 0;
59909a01aa6Smacallan }
60009a01aa6Smacallan 
60109a01aa6Smacallan static int
agten_putpalreg(struct agten_softc * sc,uint8_t idx,uint8_t r,uint8_t g,uint8_t b)60209a01aa6Smacallan agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
60309a01aa6Smacallan     uint8_t b)
60409a01aa6Smacallan {
60509a01aa6Smacallan 
60609a01aa6Smacallan 	sc->sc_cmap.cm_map[idx][0] = r;
60709a01aa6Smacallan 	sc->sc_cmap.cm_map[idx][1] = g;
60809a01aa6Smacallan 	sc->sc_cmap.cm_map[idx][2] = b;
60909a01aa6Smacallan 	agten_write_idx(sc, IBM561_CMAP_TABLE + idx);
61009a01aa6Smacallan 	agten_write_dac(sc, IBM561_CMD_CMAP, r);
61109a01aa6Smacallan 	agten_write_dac(sc, IBM561_CMD_CMAP, g);
61209a01aa6Smacallan 	agten_write_dac(sc, IBM561_CMD_CMAP, b);
61309a01aa6Smacallan 	return 0;
61409a01aa6Smacallan }
61509a01aa6Smacallan 
61609a01aa6Smacallan static void
agten_init(struct agten_softc * sc)61709a01aa6Smacallan agten_init(struct agten_softc *sc)
61809a01aa6Smacallan {
61956d11704Smacallan 	int i;
62009a01aa6Smacallan 	uint32_t src, srcw;
62109a01aa6Smacallan 
622639b5a68Smacallan 	/* then we set up a linear LUT for 24bit colour */
623639b5a68Smacallan 	agten_write_idx(sc, IBM561_CMAP_TABLE + 256);
624639b5a68Smacallan 	for (i = 0; i < 256; i++) {
625639b5a68Smacallan 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
626639b5a68Smacallan 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
627639b5a68Smacallan 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
628639b5a68Smacallan 	}
629639b5a68Smacallan 
630639b5a68Smacallan 	/* and the linear gamma maps */
631639b5a68Smacallan 	agten_write_idx(sc, IBM561_RED_GAMMA_TABLE);
632639b5a68Smacallan 	for (i = 0; i < 0x3ff; i+= 4)
633639b5a68Smacallan 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
634639b5a68Smacallan 	agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE);
635639b5a68Smacallan 	for (i = 0; i < 0x3ff; i+= 4)
636639b5a68Smacallan 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
637639b5a68Smacallan 	agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE);
638639b5a68Smacallan 	for (i = 0; i < 0x3ff; i+= 4)
639639b5a68Smacallan 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
640639b5a68Smacallan 
6410c74b4e4Smacallan 	/* enable outputs, RGB mode */
642639b5a68Smacallan 	agten_write_idx(sc, IBM561_CONFIG_REG3);
643a4e1a9b8Smacallan 	agten_write_dac(sc, IBM561_CMD, CR3_SERIAL_CLK_CTRL | CR3_RGB);
644639b5a68Smacallan 
645639b5a68Smacallan 	/* MUX 4:1 basic, 8bit overlay, 8bit WIDs */
646639b5a68Smacallan 	agten_write_idx(sc, IBM561_CONFIG_REG1);
647a4e1a9b8Smacallan 	agten_write_dac(sc, IBM561_CMD, CR1_MODE_4_1_BASIC | CR1_OVL_8BPP |
648a4e1a9b8Smacallan 	    CR1_WID_8);
649639b5a68Smacallan 
650a4e1a9b8Smacallan 	/* use external clock, enable video output */
651f9794c16Smacallan 	agten_write_idx(sc, IBM561_CONFIG_REG2);
652f9794c16Smacallan 	agten_write_dac(sc, IBM561_CMD, CR2_ENABLE_CLC | CR2_PLL_REF_SELECT |
653f9794c16Smacallan 	    CR2_PIXEL_CLOCK_SELECT | CR2_ENABLE_RGB_OUTPUT);
654f9794c16Smacallan 
65509a01aa6Smacallan 	/* now set up some window attributes */
656639b5a68Smacallan 
657639b5a68Smacallan 	/*
658639b5a68Smacallan 	 * direct colour, 24 bit, transparency off, LUT from 0x100
659639b5a68Smacallan 	 * we need to use direct colour and a linear LUT because for some
660639b5a68Smacallan 	 * reason true color mode gives messed up colours
661639b5a68Smacallan 	 */
662639b5a68Smacallan 	agten_write_idx(sc, IBM561_FB_WINTYPE);
663a4e1a9b8Smacallan 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x100 | FB_PIXEL_24BIT |
664a4e1a9b8Smacallan 	    FB_MODE_DIRECT);
665639b5a68Smacallan 
666639b5a68Smacallan 	/* use gamma LUTs, no crosshair, 0 is transparent */
667639b5a68Smacallan 	agten_write_idx(sc, IBM561_AUXFB_WINTYPE);
668639b5a68Smacallan 	agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0);
669639b5a68Smacallan 
670639b5a68Smacallan 	/* overlay is 8 bit, opaque */
6717863a2faSmacallan 	agten_write_idx(sc, IBM561_OL_WINTYPE);
67209a01aa6Smacallan 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00);
67309a01aa6Smacallan 
674639b5a68Smacallan 	/* now we fill the WID fb with zeroes */
67509a01aa6Smacallan 	src = 0;
67609a01aa6Smacallan 	srcw = sc->sc_width << 16 | sc->sc_height;
67709a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR,
67809a01aa6Smacallan 	    0x0);
67909a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR,
68009a01aa6Smacallan 	    0x0);
68109a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT);
68209a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0);
68309a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src);
68409a01aa6Smacallan 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw);
68541e64636Smrg 	(void)bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD);
68609a01aa6Smacallan 
687699639e6Smacallan 	/* initialize the cursor registers */
688699639e6Smacallan 
689699639e6Smacallan 	/* initialize the Imagine 128 */
6907863a2faSmacallan 	i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8);
69109a01aa6Smacallan }
69209a01aa6Smacallan 
69309a01aa6Smacallan static void
agten_init_cmap(struct agten_softc * sc,struct rasops_info * ri)69456d11704Smacallan agten_init_cmap(struct agten_softc *sc, struct rasops_info *ri)
69556d11704Smacallan {
69656d11704Smacallan 	int i, j;
69756d11704Smacallan 	uint8_t cmap[768];
69856d11704Smacallan 
69956d11704Smacallan 	rasops_get_cmap(ri, cmap, 768);
70056d11704Smacallan 	j = 0;
70156d11704Smacallan 	for (i = 0; i < 256; i++) {
70256d11704Smacallan 
70356d11704Smacallan 		agten_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
70456d11704Smacallan 		j += 3;
70556d11704Smacallan 	}
70656d11704Smacallan }
70756d11704Smacallan 
70856d11704Smacallan static void
agten_gfx(struct agten_softc * sc)709639b5a68Smacallan agten_gfx(struct agten_softc *sc)
710639b5a68Smacallan {
711639b5a68Smacallan 	/* enable overlay transparency on colour 0x00 */
712639b5a68Smacallan 	agten_write_idx(sc, IBM561_OL_WINTYPE);
713a4e1a9b8Smacallan 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, OL_MODE_TRANSP_ENABLE);
714639b5a68Smacallan 
715639b5a68Smacallan 	/* then blit the overlay full of 0x00 */
716639b5a68Smacallan 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width,
717639b5a68Smacallan 	    sc->sc_height, 0);
718639b5a68Smacallan 
719639b5a68Smacallan 	/* ... so we can see the 24bit framebuffer */
720639b5a68Smacallan }
721639b5a68Smacallan 
722639b5a68Smacallan static void
agten_set_video(struct agten_softc * sc,int flag)7232be61cb9Smacallan agten_set_video(struct agten_softc *sc, int flag)
7242be61cb9Smacallan {
725f9794c16Smacallan 	uint8_t reg =
726f9794c16Smacallan 	    CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | CR2_PIXEL_CLOCK_SELECT;
727f9794c16Smacallan 
728f9794c16Smacallan 	if (flag == sc->sc_video)
729f9794c16Smacallan 		return;
730f9794c16Smacallan 
731f9794c16Smacallan 	agten_write_idx(sc, IBM561_CONFIG_REG2);
732f9794c16Smacallan 	agten_write_dac(sc, IBM561_CMD, flag ? reg | CR2_ENABLE_RGB_OUTPUT :
733f9794c16Smacallan 	    reg);
734f9794c16Smacallan 
735f9794c16Smacallan 	sc->sc_video = flag;
7362be61cb9Smacallan }
7372be61cb9Smacallan 
7382be61cb9Smacallan static int
agten_get_video(struct agten_softc * sc)7392be61cb9Smacallan agten_get_video(struct agten_softc *sc)
7402be61cb9Smacallan {
741f9794c16Smacallan 
742f9794c16Smacallan 	return sc->sc_video;
7432be61cb9Smacallan }
7442be61cb9Smacallan 
7452be61cb9Smacallan static void
agten_bitblt(void * cookie,int xs,int ys,int xd,int yd,int wi,int he,int rop)74662d7fcf0Smacallan agten_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he,
74762d7fcf0Smacallan              int rop)
74862d7fcf0Smacallan {
74962d7fcf0Smacallan 	struct agten_softc *sc = cookie;
75062d7fcf0Smacallan 
75162d7fcf0Smacallan 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh,
75262d7fcf0Smacallan 	    xs, ys, xd, yd, wi, he, rop);
75362d7fcf0Smacallan }
75462d7fcf0Smacallan 
75562d7fcf0Smacallan static void
agten_rectfill(void * cookie,int x,int y,int wi,int he,long fg)75662d7fcf0Smacallan agten_rectfill(void *cookie, int x, int y, int wi, int he, long fg)
75762d7fcf0Smacallan {
75862d7fcf0Smacallan 	struct agten_softc *sc = cookie;
75962d7fcf0Smacallan 	struct vcons_screen *scr = sc->vd.active;
76062d7fcf0Smacallan 	uint32_t col;
76162d7fcf0Smacallan 
76262d7fcf0Smacallan 	if (scr == NULL)
76362d7fcf0Smacallan 		return;
76462d7fcf0Smacallan 	col = scr->scr_ri.ri_devcmap[fg];
76562d7fcf0Smacallan 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he, col);
76662d7fcf0Smacallan }
76762d7fcf0Smacallan 
76862d7fcf0Smacallan static void
agten_putchar(void * cookie,int row,int col,u_int c,long attr)76962d7fcf0Smacallan agten_putchar(void *cookie, int row, int col, u_int c, long attr)
77062d7fcf0Smacallan {
77162d7fcf0Smacallan 	struct rasops_info *ri = cookie;
77262d7fcf0Smacallan 	struct wsdisplay_font *font = PICK_FONT(ri, c);
77362d7fcf0Smacallan 	struct vcons_screen *scr = ri->ri_hw;
77462d7fcf0Smacallan 	struct agten_softc *sc = scr->scr_cookie;
77562d7fcf0Smacallan 	uint32_t fg, bg;
77662d7fcf0Smacallan 	int x, y, wi, he, rv;
77762d7fcf0Smacallan 
77862d7fcf0Smacallan 	wi = font->fontwidth;
77962d7fcf0Smacallan 	he = font->fontheight;
78062d7fcf0Smacallan 
78162d7fcf0Smacallan 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
78262d7fcf0Smacallan 	fg = ri->ri_devcmap[(attr >> 24) & 0xf];
78362d7fcf0Smacallan 
78462d7fcf0Smacallan 	x = ri->ri_xorigin + col * wi;
78562d7fcf0Smacallan 	y = ri->ri_yorigin + row * he;
78662d7fcf0Smacallan 
78762d7fcf0Smacallan 	if (c == 0x20) {
78862d7fcf0Smacallan 		i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he,
78962d7fcf0Smacallan 		    bg);
79062d7fcf0Smacallan 		if (attr & 1)
79162d7fcf0Smacallan 			i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
79262d7fcf0Smacallan 			    y + he - 2, wi, 1, fg);
79362d7fcf0Smacallan 		return;
79462d7fcf0Smacallan 	}
79562d7fcf0Smacallan 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
79662d7fcf0Smacallan 	if (rv == GC_OK)
79762d7fcf0Smacallan 		return;
79862d7fcf0Smacallan 	i128_sync(sc->sc_bustag, sc->sc_i128_regh);
79962d7fcf0Smacallan 	sc->sc_putchar(cookie, row, col, c, attr & ~1);
80062d7fcf0Smacallan 
80162d7fcf0Smacallan 	if (rv == GC_ADD) {
80262d7fcf0Smacallan 		glyphcache_add(&sc->sc_gc, c, x, y);
80362d7fcf0Smacallan 	} else {
80462d7fcf0Smacallan 		if (attr & 1)
80562d7fcf0Smacallan 			i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
80662d7fcf0Smacallan 			    y + he - 2, wi, 1, fg);
80762d7fcf0Smacallan 	}
80862d7fcf0Smacallan }
80962d7fcf0Smacallan 
81062d7fcf0Smacallan static void
agten_cursor(void * cookie,int on,int row,int col)81162d7fcf0Smacallan agten_cursor(void *cookie, int on, int row, int col)
81262d7fcf0Smacallan {
81362d7fcf0Smacallan 	struct rasops_info *ri = cookie;
81462d7fcf0Smacallan 	struct vcons_screen *scr = ri->ri_hw;
81562d7fcf0Smacallan 	struct agten_softc *sc = scr->scr_cookie;
81662d7fcf0Smacallan 	int x, y, wi,he;
81762d7fcf0Smacallan 
81862d7fcf0Smacallan 	wi = ri->ri_font->fontwidth;
81962d7fcf0Smacallan 	he = ri->ri_font->fontheight;
82062d7fcf0Smacallan 
82162d7fcf0Smacallan 	if (ri->ri_flg & RI_CURSOR) {
82262d7fcf0Smacallan 		x = ri->ri_ccol * wi + ri->ri_xorigin;
82362d7fcf0Smacallan 		y = ri->ri_crow * he + ri->ri_yorigin;
82462d7fcf0Smacallan 		i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
82562d7fcf0Smacallan 		    CR_COPY_INV);
82662d7fcf0Smacallan 		ri->ri_flg &= ~RI_CURSOR;
82762d7fcf0Smacallan 	}
82862d7fcf0Smacallan 
82962d7fcf0Smacallan 	ri->ri_crow = row;
83062d7fcf0Smacallan 	ri->ri_ccol = col;
83162d7fcf0Smacallan 
83262d7fcf0Smacallan 	if (on)
83362d7fcf0Smacallan 	{
83462d7fcf0Smacallan 		x = ri->ri_ccol * wi + ri->ri_xorigin;
83562d7fcf0Smacallan 		y = ri->ri_crow * he + ri->ri_yorigin;
83662d7fcf0Smacallan 		i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
83762d7fcf0Smacallan 		    CR_COPY_INV);
83862d7fcf0Smacallan 		ri->ri_flg |= RI_CURSOR;
83962d7fcf0Smacallan 	}
84062d7fcf0Smacallan }
84162d7fcf0Smacallan 
84262d7fcf0Smacallan static void
agten_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)84309a01aa6Smacallan agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
84409a01aa6Smacallan {
84509a01aa6Smacallan 	struct rasops_info *ri = cookie;
84609a01aa6Smacallan 	struct vcons_screen *scr = ri->ri_hw;
84709a01aa6Smacallan 	struct agten_softc *sc = scr->scr_cookie;
84809a01aa6Smacallan 	int32_t xs, xd, y, width, height;
84909a01aa6Smacallan 
85009a01aa6Smacallan 	xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
85109a01aa6Smacallan 	xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
85209a01aa6Smacallan 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
85309a01aa6Smacallan 	width = ri->ri_font->fontwidth * ncols;
85409a01aa6Smacallan 	height = ri->ri_font->fontheight;
85509a01aa6Smacallan 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width,
8567863a2faSmacallan 	    height, CR_COPY);
85709a01aa6Smacallan }
85809a01aa6Smacallan 
85909a01aa6Smacallan static void
agten_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)86009a01aa6Smacallan agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
86109a01aa6Smacallan {
86209a01aa6Smacallan 	struct rasops_info *ri = cookie;
86309a01aa6Smacallan 	struct vcons_screen *scr = ri->ri_hw;
86409a01aa6Smacallan 	struct agten_softc *sc = scr->scr_cookie;
86509a01aa6Smacallan 	int32_t x, y, width, height, bg;
86609a01aa6Smacallan 
86709a01aa6Smacallan 	x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
86809a01aa6Smacallan 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
86909a01aa6Smacallan 	width = ri->ri_font->fontwidth * ncols;
87009a01aa6Smacallan 	height = ri->ri_font->fontheight;
87109a01aa6Smacallan 	bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
87209a01aa6Smacallan 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
87309a01aa6Smacallan }
87409a01aa6Smacallan 
87509a01aa6Smacallan static void
agten_copyrows(void * cookie,int srcrow,int dstrow,int nrows)87609a01aa6Smacallan agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
87709a01aa6Smacallan {
87809a01aa6Smacallan 	struct rasops_info *ri = cookie;
87909a01aa6Smacallan 	struct vcons_screen *scr = ri->ri_hw;
88009a01aa6Smacallan 	struct agten_softc *sc = scr->scr_cookie;
88109a01aa6Smacallan 	int32_t x, ys, yd, width, height;
88209a01aa6Smacallan 
88309a01aa6Smacallan 	x = ri->ri_xorigin;
88409a01aa6Smacallan 	ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
88509a01aa6Smacallan 	yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
88609a01aa6Smacallan 	width = ri->ri_emuwidth;
88709a01aa6Smacallan 	height = ri->ri_font->fontheight * nrows;
88809a01aa6Smacallan 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width,
8897863a2faSmacallan 	    height, CR_COPY);
89009a01aa6Smacallan }
89109a01aa6Smacallan 
89209a01aa6Smacallan static void
agten_eraserows(void * cookie,int row,int nrows,long fillattr)89309a01aa6Smacallan agten_eraserows(void *cookie, int row, int nrows, long fillattr)
89409a01aa6Smacallan {
89509a01aa6Smacallan 	struct rasops_info *ri = cookie;
89609a01aa6Smacallan 	struct vcons_screen *scr = ri->ri_hw;
89709a01aa6Smacallan 	struct agten_softc *sc = scr->scr_cookie;
89809a01aa6Smacallan 	int32_t x, y, width, height, bg;
89909a01aa6Smacallan 
90009a01aa6Smacallan 	if ((row == 0) && (nrows == ri->ri_rows)) {
90109a01aa6Smacallan 		x = y = 0;
90209a01aa6Smacallan 		width = ri->ri_width;
90309a01aa6Smacallan 		height = ri->ri_height;
90409a01aa6Smacallan 	} else {
90509a01aa6Smacallan 		x = ri->ri_xorigin;
90609a01aa6Smacallan 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
90709a01aa6Smacallan 		width = ri->ri_emuwidth;
90809a01aa6Smacallan 		height = ri->ri_font->fontheight * nrows;
90909a01aa6Smacallan 	}
91009a01aa6Smacallan 	bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
91109a01aa6Smacallan 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
91209a01aa6Smacallan }
913699639e6Smacallan 
914699639e6Smacallan static void
agten_move_cursor(struct agten_softc * sc,int x,int y)915699639e6Smacallan agten_move_cursor(struct agten_softc *sc, int x, int y)
916699639e6Smacallan {
917699639e6Smacallan 
918699639e6Smacallan 	sc->sc_cursor_x = x;
919699639e6Smacallan 	sc->sc_cursor_y = y;
920699639e6Smacallan 	agten_write_idx(sc, IBM561_CURSOR_X_REG);
921699639e6Smacallan 	agten_write_dac(sc, IBM561_CMD, x & 0xff);
922699639e6Smacallan 	agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff);
923699639e6Smacallan 	agten_write_dac(sc, IBM561_CMD, y & 0xff);
924699639e6Smacallan 	agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff);
925699639e6Smacallan }
926699639e6Smacallan 
927699639e6Smacallan static int
agten_do_cursor(struct agten_softc * sc,struct wsdisplay_cursor * cur)928699639e6Smacallan agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur)
929699639e6Smacallan {
930699639e6Smacallan 	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
931699639e6Smacallan 
932699639e6Smacallan 		agten_write_idx(sc, IBM561_CURS_CNTL_REG);
933699639e6Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->enable ?
934699639e6Smacallan 		    CURS_ENABLE : 0);
935699639e6Smacallan 	}
936699639e6Smacallan 	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
937699639e6Smacallan 
938699639e6Smacallan 		agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
939699639e6Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->hot.x);
940699639e6Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->hot.y);
941699639e6Smacallan 	}
942699639e6Smacallan 	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
943699639e6Smacallan 
944699639e6Smacallan 		agten_move_cursor(sc, cur->pos.x, cur->pos.y);
945699639e6Smacallan 	}
946699639e6Smacallan 	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
947699639e6Smacallan 		int i;
948699639e6Smacallan 
949699639e6Smacallan 		agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
950699639e6Smacallan 		for (i = 0; i < cur->cmap.count; i++) {
951699639e6Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
952a4e1a9b8Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP,
953a4e1a9b8Smacallan 			    cur->cmap.green[i]);
954699639e6Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
955699639e6Smacallan 		}
956699639e6Smacallan 	}
957699639e6Smacallan 	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
958699639e6Smacallan 		int i;
959699639e6Smacallan 		uint16_t tmp;
960699639e6Smacallan 
961699639e6Smacallan 		agten_write_idx(sc, IBM561_CURSOR_BITMAP);
962699639e6Smacallan 		for (i = 0; i < 512; i++) {
963699639e6Smacallan 			tmp = util_interleave(cur->mask[i], cur->image[i]);
964699639e6Smacallan 			agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
965699639e6Smacallan 			agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
966699639e6Smacallan 		}
967699639e6Smacallan 	}
968699639e6Smacallan 	return 0;
969699639e6Smacallan }
970699639e6Smacallan 
9712be61cb9Smacallan static int
agten_do_sun_cursor(struct agten_softc * sc,struct fbcursor * cur)9722be61cb9Smacallan agten_do_sun_cursor(struct agten_softc *sc, struct fbcursor *cur)
9732be61cb9Smacallan {
9742be61cb9Smacallan 	if (cur->set & FB_CUR_SETCUR) {
9752be61cb9Smacallan 
9762be61cb9Smacallan 		agten_write_idx(sc, IBM561_CURS_CNTL_REG);
9772be61cb9Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->enable ?
9782be61cb9Smacallan 		    CURS_ENABLE : 0);
9792be61cb9Smacallan 	}
9802be61cb9Smacallan 	if (cur->set & FB_CUR_SETHOT) {
9812be61cb9Smacallan 
9822be61cb9Smacallan 		agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
9832be61cb9Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->hot.x);
9842be61cb9Smacallan 		agten_write_dac(sc, IBM561_CMD, cur->hot.y);
9852be61cb9Smacallan 	}
9862be61cb9Smacallan 	if (cur->set & FB_CUR_SETPOS) {
9872be61cb9Smacallan 
9882be61cb9Smacallan 		agten_move_cursor(sc, cur->pos.x, cur->pos.y);
9892be61cb9Smacallan 	}
9902be61cb9Smacallan 	if (cur->set & FB_CUR_SETCMAP) {
9912be61cb9Smacallan 		int i;
9922be61cb9Smacallan 
9932be61cb9Smacallan 		agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
9942be61cb9Smacallan 		for (i = 0; i < cur->cmap.count; i++) {
9952be61cb9Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
9960c74b4e4Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP,
9970c74b4e4Smacallan 			    cur->cmap.green[i]);
9982be61cb9Smacallan 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
9992be61cb9Smacallan 		}
10002be61cb9Smacallan 	}
10012be61cb9Smacallan 	if (cur->set & FB_CUR_SETSHAPE) {
10022be61cb9Smacallan 		int i;
10032be61cb9Smacallan 		uint16_t tmp;
10042be61cb9Smacallan 
10052be61cb9Smacallan 		agten_write_idx(sc, IBM561_CURSOR_BITMAP);
10062be61cb9Smacallan 		for (i = 0; i < 512; i++) {
10072be61cb9Smacallan 			tmp = util_interleave_lin(cur->mask[i], cur->image[i]);
10082be61cb9Smacallan 			agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
10092be61cb9Smacallan 			agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
10102be61cb9Smacallan 		}
10112be61cb9Smacallan 	}
10122be61cb9Smacallan 	return 0;
10132be61cb9Smacallan }
10142be61cb9Smacallan 
1015699639e6Smacallan uint16_t
util_interleave(uint8_t b1,uint8_t b2)1016699639e6Smacallan util_interleave(uint8_t b1, uint8_t b2)
1017699639e6Smacallan {
1018699639e6Smacallan 	int i;
1019699639e6Smacallan 	uint16_t ret = 0;
1020699639e6Smacallan 	uint16_t mask = 0x8000;
1021699639e6Smacallan 	uint8_t mask8 = 0x01;
1022699639e6Smacallan 
1023699639e6Smacallan 	for (i = 0; i < 8; i++) {
1024699639e6Smacallan 		if (b1 & mask8)
1025699639e6Smacallan 			ret |= mask;
1026699639e6Smacallan 		mask = mask >> 1;
1027699639e6Smacallan 		if (b2 & mask8)
1028699639e6Smacallan 			ret |= mask;
1029699639e6Smacallan 		mask = mask >> 1;
1030699639e6Smacallan 		mask8 = mask8 << 1;
1031699639e6Smacallan 	}
1032699639e6Smacallan 	return ret;
1033699639e6Smacallan }
10342be61cb9Smacallan 
10352be61cb9Smacallan uint16_t
util_interleave_lin(uint8_t b1,uint8_t b2)10362be61cb9Smacallan util_interleave_lin(uint8_t b1, uint8_t b2)
10372be61cb9Smacallan {
10382be61cb9Smacallan 	int i;
10392be61cb9Smacallan 	uint16_t ret = 0;
10402be61cb9Smacallan 	uint16_t mask = 0x8000;
10412be61cb9Smacallan 	uint8_t mask8 = 0x80;
10422be61cb9Smacallan 
10432be61cb9Smacallan 	for (i = 0; i < 8; i++) {
10442be61cb9Smacallan 		if (b1 & mask8)
10452be61cb9Smacallan 			ret |= mask;
10462be61cb9Smacallan 		mask = mask >> 1;
10472be61cb9Smacallan 		if (b2 & mask8)
10482be61cb9Smacallan 			ret |= mask;
10492be61cb9Smacallan 		mask = mask >> 1;
10502be61cb9Smacallan 		mask8 = mask8 >> 1;
10512be61cb9Smacallan 	}
10522be61cb9Smacallan 	return ret;
10532be61cb9Smacallan }
10542be61cb9Smacallan 
10552be61cb9Smacallan /* and now the /dev/fb* stuff */
10562be61cb9Smacallan static void
agten_fb_unblank(device_t dev)10570c74b4e4Smacallan agten_fb_unblank(device_t dev)
10582be61cb9Smacallan {
10590c74b4e4Smacallan 	struct agten_softc *sc = device_private(dev);
1060f9794c16Smacallan 
1061f9794c16Smacallan 	agten_init(sc);
1062f9794c16Smacallan 	agten_set_video(sc, 1);
10632be61cb9Smacallan }
10642be61cb9Smacallan 
10652be61cb9Smacallan static int
agten_fb_open(dev_t dev,int flags,int mode,struct lwp * l)10662be61cb9Smacallan agten_fb_open(dev_t dev, int flags, int mode, struct lwp *l)
10672be61cb9Smacallan {
1068708f88d6Scegger 	struct agten_softc *sc;
10692be61cb9Smacallan 
1070708f88d6Scegger 	sc = device_lookup_private(&agten_cd, minor(dev));
1071708f88d6Scegger 	if (sc == NULL)
10722be61cb9Smacallan 		return (ENXIO);
10732be61cb9Smacallan 	if (sc->sc_fb_is_open)
10742be61cb9Smacallan 		return 0;
10752be61cb9Smacallan 
10762be61cb9Smacallan 	sc->sc_fb_is_open++;
10772be61cb9Smacallan 	agten_gfx(sc);
10782be61cb9Smacallan 
10792be61cb9Smacallan 	return (0);
10802be61cb9Smacallan }
10812be61cb9Smacallan 
10822be61cb9Smacallan static int
agten_fb_close(dev_t dev,int flags,int mode,struct lwp * l)10832be61cb9Smacallan agten_fb_close(dev_t dev, int flags, int mode, struct lwp *l)
10842be61cb9Smacallan {
1085708f88d6Scegger 	struct agten_softc *sc;
1086708f88d6Scegger 
1087708f88d6Scegger 	sc = device_lookup_private(&agten_cd, minor(dev));
10882be61cb9Smacallan 
10892be61cb9Smacallan 	sc->sc_fb_is_open--;
10902be61cb9Smacallan 	if (sc->sc_fb_is_open < 0)
10912be61cb9Smacallan 		sc->sc_fb_is_open = 0;
10922be61cb9Smacallan 
10932be61cb9Smacallan 	if (sc->sc_fb_is_open == 0) {
10942be61cb9Smacallan 		agten_init(sc);
10952be61cb9Smacallan 		vcons_redraw_screen(sc->vd.active);
10962be61cb9Smacallan 	}
10972be61cb9Smacallan 
10982be61cb9Smacallan 	return (0);
10992be61cb9Smacallan }
11002be61cb9Smacallan 
11012be61cb9Smacallan static int
agten_fb_ioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)11022be61cb9Smacallan agten_fb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
11032be61cb9Smacallan {
1104708f88d6Scegger 	struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
11052be61cb9Smacallan 	struct fbgattr *fba;
11062be61cb9Smacallan 	int error;
11072be61cb9Smacallan 
11082be61cb9Smacallan 	switch (cmd) {
11092be61cb9Smacallan 
11102be61cb9Smacallan 	case FBIOGTYPE:
11112be61cb9Smacallan 		*(struct fbtype *)data = sc->sc_fb.fb_type;
11122be61cb9Smacallan 		break;
11132be61cb9Smacallan 
11142be61cb9Smacallan 	case FBIOGATTR:
11152be61cb9Smacallan 		fba = (struct fbgattr *)data;
11162be61cb9Smacallan 		fba->real_type = sc->sc_fb.fb_type.fb_type;
11172be61cb9Smacallan 		fba->owner = 0;		/* XXX ??? */
11182be61cb9Smacallan 		fba->fbtype = sc->sc_fb.fb_type;
11192be61cb9Smacallan 		fba->sattr.flags = 0;
11202be61cb9Smacallan 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
11212be61cb9Smacallan 		fba->sattr.dev_specific[0] = -1;
11222be61cb9Smacallan 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
11232be61cb9Smacallan 		fba->emu_types[1] = -1;
11242be61cb9Smacallan 		break;
11252be61cb9Smacallan 
11262be61cb9Smacallan 	case FBIOGETCMAP:
11272be61cb9Smacallan #define p ((struct fbcmap *)data)
11282be61cb9Smacallan 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
11292be61cb9Smacallan 
11302be61cb9Smacallan 	case FBIOPUTCMAP:
11312be61cb9Smacallan 		/* copy to software map */
11322be61cb9Smacallan 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
11332be61cb9Smacallan 		if (error)
11342be61cb9Smacallan 			return (error);
11352be61cb9Smacallan 		/* now blast them into the chip */
11362be61cb9Smacallan 		/* don't bother - we're 24bit */
11372be61cb9Smacallan #undef p
11382be61cb9Smacallan 		break;
11392be61cb9Smacallan 
11402be61cb9Smacallan 	case FBIOGVIDEO:
11412be61cb9Smacallan 		*(int *)data = agten_get_video(sc);
11422be61cb9Smacallan 		break;
11432be61cb9Smacallan 
11442be61cb9Smacallan 	case FBIOSVIDEO:
11452be61cb9Smacallan 		agten_set_video(sc, *(int *)data);
11462be61cb9Smacallan 		break;
11472be61cb9Smacallan 
11482be61cb9Smacallan /* these are for both FBIOSCURSOR and FBIOGCURSOR */
11492be61cb9Smacallan #define p ((struct fbcursor *)data)
11502be61cb9Smacallan #define pc (&sc->sc_cursor)
11512be61cb9Smacallan 
11522be61cb9Smacallan 	case FBIOGCURSOR:
11532be61cb9Smacallan 		/* does anyone use this ioctl?! */
11542be61cb9Smacallan 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
11552be61cb9Smacallan 		p->enable = 1;
11562be61cb9Smacallan 		p->pos.x = sc->sc_cursor_x;
11572be61cb9Smacallan 		p->pos.y = sc->sc_cursor_y;
11582be61cb9Smacallan 		p->size.x = 64;
11592be61cb9Smacallan 		p->size.y = 64;
11602be61cb9Smacallan 		break;
11612be61cb9Smacallan 
11622be61cb9Smacallan 	case FBIOSCURSOR:
11632be61cb9Smacallan 		agten_do_sun_cursor(sc, p);
11642be61cb9Smacallan 	break;
11652be61cb9Smacallan 
11662be61cb9Smacallan #undef p
11672be61cb9Smacallan #undef cc
11682be61cb9Smacallan 
11692be61cb9Smacallan 	case FBIOGCURPOS:
11702be61cb9Smacallan 	{
11712be61cb9Smacallan 		struct fbcurpos *cp = (struct fbcurpos *)data;
11722be61cb9Smacallan 		cp->x = sc->sc_cursor_x;
11732be61cb9Smacallan 		cp->y = sc->sc_cursor_y;
11742be61cb9Smacallan 	}
11752be61cb9Smacallan 	break;
11762be61cb9Smacallan 
11772be61cb9Smacallan 	case FBIOSCURPOS:
11782be61cb9Smacallan 	{
11792be61cb9Smacallan 		struct fbcurpos *cp = (struct fbcurpos *)data;
11802be61cb9Smacallan 		agten_move_cursor(sc, cp->x, cp->y);
11812be61cb9Smacallan 	}
11822be61cb9Smacallan 	break;
11832be61cb9Smacallan 
11842be61cb9Smacallan 	case FBIOGCURMAX:
11852be61cb9Smacallan 		/* max cursor size is 64x64 */
11862be61cb9Smacallan 		((struct fbcurpos *)data)->x = 64;
11872be61cb9Smacallan 		((struct fbcurpos *)data)->y = 64;
11882be61cb9Smacallan 		break;
11892be61cb9Smacallan 
11902be61cb9Smacallan 	default:
11912be61cb9Smacallan 		return (ENOTTY);
11922be61cb9Smacallan 	}
11932be61cb9Smacallan 	return (0);
11942be61cb9Smacallan }
11952be61cb9Smacallan 
11962be61cb9Smacallan static paddr_t
agten_fb_mmap(dev_t dev,off_t off,int prot)11972be61cb9Smacallan agten_fb_mmap(dev_t dev, off_t off, int prot)
11982be61cb9Smacallan {
1199708f88d6Scegger 	struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
12002be61cb9Smacallan 
12012be61cb9Smacallan 	/*
12022be61cb9Smacallan 	 * mappings are subject to change
12032be61cb9Smacallan 	 * for now we put the framebuffer at offset 0 and the GLint registers
12042be61cb9Smacallan 	 * right after that. We may want to expose more register ranges and
12052be61cb9Smacallan 	 * probably will want to map the 2nd framebuffer as well
12062be61cb9Smacallan 	 */
12072be61cb9Smacallan 
12082be61cb9Smacallan 	if (off < 0)
12092be61cb9Smacallan 		return EINVAL;
12102be61cb9Smacallan 
12112be61cb9Smacallan 	if (off >= sc->sc_glint_fbsz + 0x10000)
12122be61cb9Smacallan 		return EINVAL;
12132be61cb9Smacallan 
12142be61cb9Smacallan 	if (off < sc->sc_glint_fbsz) {
12152be61cb9Smacallan 		return (bus_space_mmap(sc->sc_bustag,
12162be61cb9Smacallan 			sc->sc_glint_fb,
12172be61cb9Smacallan 			off,
12182be61cb9Smacallan 			prot,
12192be61cb9Smacallan 			BUS_SPACE_MAP_LINEAR));
12202be61cb9Smacallan 	}
12212be61cb9Smacallan 
12222be61cb9Smacallan 	off -= sc->sc_glint_fbsz;
12232be61cb9Smacallan 	if (off < 0x10000) {
12242be61cb9Smacallan 		return (bus_space_mmap(sc->sc_bustag,
12252be61cb9Smacallan 			sc->sc_glint_regs,
12262be61cb9Smacallan 			off,
12272be61cb9Smacallan 			prot,
12282be61cb9Smacallan 			BUS_SPACE_MAP_LINEAR));
12292be61cb9Smacallan 	}
12302be61cb9Smacallan 	return EINVAL;
12312be61cb9Smacallan }
1232