Home | History | Annotate | Line # | Download | only in sbus
      1 /*	$NetBSD: cgtwelve.c,v 1.10 2026/09/22 16:48:56 macallan Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2010 Michael Lorenz
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /* a console driver for the Sun CG12 / Matrox SG3 graphics board */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: cgtwelve.c,v 1.10 2026/09/22 16:48:56 macallan Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/systm.h>
     36 #include <sys/buf.h>
     37 #include <sys/device.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/conf.h>
     40 #include <sys/kmem.h>
     41 
     42 #include <sys/bus.h>
     43 #include <machine/autoconf.h>
     44 
     45 #include <dev/sbus/sbusvar.h>
     46 #include <dev/sun/fbio.h>
     47 #include <dev/sun/fbvar.h>
     48 
     49 #include <dev/wscons/wsdisplayvar.h>
     50 #include <dev/wscons/wsconsio.h>
     51 #include <dev/wsfont/wsfont.h>
     52 #include <dev/rasops/rasops.h>
     53 
     54 #include <dev/wscons/wsdisplay_vconsvar.h>
     55 
     56 #include <dev/sbus/cgtwelvereg.h>
     57 //#include <dev/ic/bt462reg.h>
     58 
     59 #include "opt_wsemul.h"
     60 #include "opt_cgtwelve.h"
     61 
     62 
     63 struct cgtwelve_softc {
     64 	device_t	sc_dev;
     65 	bus_space_tag_t sc_tag;
     66 	bus_space_handle_t sc_regh;
     67 	bus_addr_t	sc_paddr;
     68 	void		*sc_fbaddr;
     69 	void		*sc_shadow;
     70 	uint8_t		*sc_wids;
     71 	void		*sc_int;
     72 	int		sc_width;
     73 	int		sc_height;
     74 	int		sc_stride;
     75 	int		sc_fbsize;
     76 	int		sc_mode;
     77 	int		sc_video;
     78 	int		sc_depth;
     79 	/* colour map */
     80 	uint8_t		sc_r[256], sc_g[256], sc_b[256];
     81 	uint32_t	sc_cursor_mask[32];
     82 	uint32_t	sc_cursor_image[32];
     83 	int		sc_cursor_wi, sc_cursor_he;	/* real size of sprite */
     84 	int		sc_cursor_x, sc_cursor_y;
     85 	int		sc_hot_x, sc_hot_y;
     86 	int		sc_cursor_on;
     87 	struct vcons_data vd;
     88 };
     89 
     90 static int	cgtwelve_match(device_t, cfdata_t, void *);
     91 static void	cgtwelve_attach(device_t, device_t, void *);
     92 static int	cgtwelve_ioctl(void *, void *, u_long, void *, int,
     93 				 struct lwp*);
     94 static paddr_t	cgtwelve_mmap(void *, void *, off_t, int);
     95 static void	cgtwelve_init_screen(void *, struct vcons_screen *, int,
     96 				 long *);
     97 static void	cgtwelve_write_wid(struct cgtwelve_softc *, int, uint8_t);
     98 static void	cgtwelve_select_ovl(struct cgtwelve_softc *, int);
     99 #define CG12_SEL_OVL	0
    100 #define CG12_SEL_ENABLE	1
    101 #define CG12_SEL_8BIT	2
    102 #define CG12_SEL_24BIT	3
    103 #define CG12_SEL_WID	4
    104 static void	cgtwelve_write_dac(struct cgtwelve_softc *, int, int, int, int);
    105 static void	cgtwelve_setup(struct cgtwelve_softc *, int);
    106 static void	cgtwelve_set_video(struct cgtwelve_softc *, int);
    107 static int	cgtwelve_putcmap(struct cgtwelve_softc *, struct wsdisplay_cmap *);
    108 static int	cgtwelve_getcmap(struct cgtwelve_softc *, struct wsdisplay_cmap *);
    109 static void	cgtwelve_move_cursor(struct cgtwelve_softc *, int, int);
    110 static int	cgtwelve_do_cursor(struct cgtwelve_softc *,
    111                            struct wsdisplay_cursor *);
    112 
    113 CFATTACH_DECL_NEW(cgtwelve, sizeof(struct cgtwelve_softc),
    114     cgtwelve_match, cgtwelve_attach, NULL, NULL);
    115 
    116 struct wsscreen_descr cgtwelve_defscreendesc = {
    117 	"default",
    118 	0, 0,
    119 	NULL,
    120 	8, 16,
    121 	0,
    122 };
    123 
    124 static struct vcons_screen cgtwelve_console_screen;
    125 
    126 const struct wsscreen_descr *_cgtwelve_scrlist[] = {
    127 	&cgtwelve_defscreendesc,
    128 	/* XXX other formats, graphics screen? */
    129 };
    130 
    131 struct wsscreen_list cgtwelve_screenlist = {
    132 	sizeof(_cgtwelve_scrlist) / sizeof(struct wsscreen_descr *),
    133 	_cgtwelve_scrlist
    134 };
    135 
    136 struct wsdisplay_accessops cgtwelve_accessops = {
    137 	cgtwelve_ioctl,
    138 	cgtwelve_mmap,
    139 	NULL,	/* vcons_alloc_screen */
    140 	NULL,	/* vcons_free_screen */
    141 	NULL,	/* vcons_show_screen */
    142 	NULL,	/* load_font */
    143 	NULL,	/* polls */
    144 	NULL,	/* scroll */
    145 };
    146 
    147 extern const u_char rasops_cmap[768];
    148 
    149 static int
    150 cgtwelve_match(device_t parent, cfdata_t cf, void *aux)
    151 {
    152 	struct sbus_attach_args *sa = aux;
    153 
    154 	if (strcmp("cgtwelve", sa->sa_name) == 0)
    155 		return 100;
    156 	return 0;
    157 }
    158 
    159 /*
    160  * Attach a display.  We need to notice if it is the console, too.
    161  */
    162 static void
    163 cgtwelve_attach(device_t parent, device_t self, void *args)
    164 {
    165 	struct cgtwelve_softc *sc = device_private(self);
    166 	struct sbus_attach_args *sa = args;
    167 	struct wsemuldisplaydev_attach_args aa;
    168 	struct rasops_info *ri;
    169 	unsigned long defattr;
    170 	bus_space_handle_t bh;
    171 	int node = sa->sa_node;
    172 	int isconsole;
    173 
    174 	aprint_normal("\n");
    175 	sc->sc_dev = self;
    176 	sc->sc_tag = sa->sa_bustag;
    177 
    178 	sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, sa->sa_offset);
    179 
    180 	/* read geometry information from the device tree */
    181 	sc->sc_width = prom_getpropint(sa->sa_node, "width", 1152);
    182 	sc->sc_height = prom_getpropint(sa->sa_node, "height", 900);
    183 #ifdef CG12_COLOR
    184 	sc->sc_stride = sc->sc_width;
    185 #else
    186 	sc->sc_stride = (sc->sc_width + 7) >> 3;
    187 #endif
    188 	sc->sc_fbsize = sc->sc_height * sc->sc_stride;
    189 
    190 	sc->sc_fbaddr = (void *)prom_getpropint(sa->sa_node, "address", 0);
    191 	if (sc->sc_fbaddr == NULL) {
    192 		if (sbus_bus_map(sa->sa_bustag,
    193 			 sa->sa_slot,
    194 			 sa->sa_offset + CG12_FB_MONO,
    195 			 sc->sc_fbsize,
    196 			 BUS_SPACE_MAP_LINEAR, &bh) != 0) {
    197 			aprint_error_dev(self, "cannot map framebuffer\n");
    198 			return;
    199 		}
    200 		sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh);
    201 	}
    202 
    203 	aprint_normal_dev(self, "%d x %d\n", sc->sc_width, sc->sc_height);
    204 
    205 	if (sbus_bus_map(sa->sa_bustag,
    206 			 sa->sa_slot,
    207 			 sa->sa_offset + CG12_OFF_REGISTERS,
    208 			 0xc0000, 0, &sc->sc_regh) != 0) {
    209 		aprint_error("%s: couldn't map registers\n",
    210 		    device_xname(sc->sc_dev));
    211 		return;
    212 	}
    213 
    214 	if (sbus_bus_map(sa->sa_bustag,
    215 			 sa->sa_slot,
    216 			 sa->sa_offset + CG12_OFF_WID, 0x100000,
    217 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    218 			 &bh) != 0) {
    219 		aprint_error("%s: couldn't map WID\n",
    220 		    device_xname(sc->sc_dev));
    221 		return;
    222 	}
    223 	sc->sc_wids = bus_space_vaddr(sa->sa_bustag, bh);
    224 
    225 	if (sbus_bus_map(sa->sa_bustag,
    226 			 sa->sa_slot,
    227 			 sa->sa_offset + CG12_OFF_INTEN, 0x400000,
    228 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    229 			 &bh) != 0) {
    230 		aprint_error("%s: couldn't map colour fb\n",
    231 		    device_xname(sc->sc_dev));
    232 		return;
    233 	}
    234 	sc->sc_int = bus_space_vaddr(sa->sa_bustag, bh);
    235 	sc->sc_video = WSDISPLAYIO_VIDEO_ON;
    236 	sc->sc_depth = 32;
    237 #ifdef CG12_COLOR
    238 	cgtwelve_setup(sc, 8);
    239 #else
    240 	cgtwelve_setup(sc, 1);
    241 #endif
    242 #ifdef CG12_SHADOW
    243 	sc->sc_shadow = kmem_alloc(sc->sc_fbsize, KM_SLEEP);
    244 #else
    245 	sc->sc_shadow = NULL;
    246 #endif
    247 
    248 	isconsole = fb_is_console(node);
    249 
    250 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    251 	wsfont_init();
    252 
    253 	vcons_init(&sc->vd, sc, &cgtwelve_defscreendesc, &cgtwelve_accessops);
    254 	sc->vd.init_screen = cgtwelve_init_screen;
    255 
    256 	vcons_init_screen(&sc->vd, &cgtwelve_console_screen, 1, &defattr);
    257 	cgtwelve_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    258 
    259 	ri = &cgtwelve_console_screen.scr_ri;
    260 
    261 	cgtwelve_defscreendesc.nrows = ri->ri_rows;
    262 	cgtwelve_defscreendesc.ncols = ri->ri_cols;
    263 	cgtwelve_defscreendesc.textops = &ri->ri_ops;
    264 	cgtwelve_defscreendesc.capabilities = ri->ri_caps;
    265 
    266 	if(isconsole) {
    267 		wsdisplay_cnattach(&cgtwelve_defscreendesc, ri, 0, 0, defattr);
    268 		vcons_replay_msgbuf(&cgtwelve_console_screen);
    269 	}
    270 
    271 	aa.console = isconsole;
    272 	aa.scrdata = &cgtwelve_screenlist;
    273 	aa.accessops = &cgtwelve_accessops;
    274 	aa.accesscookie = &sc->vd;
    275 
    276 	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
    277 #ifdef CG12_DEBUG
    278 	{
    279 		int i;
    280 		for (i = 0; i < 0x10; i++) {
    281 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    282 			    CG12DAC_ADDR0, (i << 16) | (i << 8) | i);
    283 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    284 			    CG12DAC_ADDR1, 0x010101);
    285 			printf("%02x: %08x\n", i, bus_space_read_4(sc->sc_tag,
    286 			    sc->sc_regh, CG12DAC_CTRL));
    287 		}
    288 	}
    289 #endif
    290 }
    291 
    292 /* 0 - overlay plane, 1 - enable plane, 2 - 8bit fb, 3 - 24bit fb, 4 - WIDs */
    293 static void
    294 cgtwelve_select_ovl(struct cgtwelve_softc *sc, int which)
    295 {
    296 	switch(which) {
    297 		case 0:
    298 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    299 			    CG12DPU_PLN_RDMSK_HOST, CG12_PLN_RD_OVERLAY);
    300 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    301 			    CG12DPU_PLN_WRMSK_HOST, CG12_PLN_WR_OVERLAY);
    302 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    303 			    CG12DPU_PLN_SL_HOST, CG12_PLN_SL_OVERLAY);
    304 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    305 			    CG12APU_HPAGE, CG12_HPAGE_OVERLAY);
    306 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    307 			    CG12APU_HACCESS, CG12_HACCESS_OVERLAY);
    308 			break;
    309 		case 1:
    310 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    311 			    CG12DPU_PLN_RDMSK_HOST, CG12_PLN_RD_ENABLE);
    312 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    313 			    CG12DPU_PLN_WRMSK_HOST, CG12_PLN_WR_ENABLE);
    314 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    315 			    CG12DPU_PLN_SL_HOST, CG12_PLN_SL_ENABLE);
    316 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    317 			    CG12APU_HPAGE, CG12_HPAGE_ENABLE);
    318 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    319 			    CG12APU_HACCESS, CG12_HACCESS_ENABLE);
    320 			break;
    321 		case 2:
    322 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    323 			    CG12DPU_PLN_RDMSK_HOST, CG12_PLN_RD_8BIT);
    324 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    325 			    CG12DPU_PLN_WRMSK_HOST, CG12_PLN_WR_8BIT);
    326 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    327 			    CG12DPU_PLN_SL_HOST, CG12_PLN_SL_8BIT);
    328 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    329 			    CG12APU_HPAGE, CG12_HPAGE_8BIT);
    330 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    331 			    CG12APU_HACCESS, CG12_HACCESS_8BIT);
    332 			break;
    333 		case 3:
    334 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    335 			    CG12DPU_PLN_RDMSK_HOST, CG12_PLN_RD_24BIT);
    336 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    337 			    CG12DPU_PLN_WRMSK_HOST, CG12_PLN_WR_24BIT);
    338 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    339 			    CG12DPU_PLN_SL_HOST, CG12_PLN_SL_24BIT);
    340 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    341 			    CG12APU_HPAGE, CG12_HPAGE_24BIT);
    342 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    343 			    CG12APU_HACCESS, CG12_HACCESS_24BIT);
    344 			break;
    345 		case 4:
    346 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    347 			    CG12DPU_PLN_RDMSK_HOST, CG12_PLN_RD_WID);
    348 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    349 			    CG12DPU_PLN_WRMSK_HOST, CG12_PLN_WR_WID);
    350 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    351 			    CG12DPU_PLN_SL_HOST, CG12_PLN_SL_WID);
    352 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    353 			    CG12APU_HPAGE, CG12_HPAGE_WID);
    354 			bus_space_write_4(sc->sc_tag, sc->sc_regh,
    355 			    CG12APU_HACCESS, CG12_HACCESS_WID);
    356 			break;
    357 	}
    358 }
    359 
    360 static void
    361 cgtwelve_write_wid(struct cgtwelve_softc *sc, int idx, uint8_t wid)
    362 {
    363 	bus_space_write_4(sc->sc_tag, sc->sc_regh, CG12_WSC_ADDR, idx << 16);
    364 	bus_space_write_4(sc->sc_tag, sc->sc_regh, CG12_WSC_DATA,
    365 	    ((uint32_t)wid) << 16);
    366 }
    367 
    368 static void
    369 cgtwelve_write_dac(struct cgtwelve_softc *sc, int idx, int r, int g, int b)
    370 {
    371 	uint32_t lo = (idx & 0xff);
    372 	uint32_t hi = (idx >> 8) & 0xff;
    373 	int use_alt = idx & 0x10000;
    374 
    375 	lo |= lo << 8 | lo << 16;
    376 	hi |= hi << 8 | hi << 16;
    377 	bus_space_write_4(sc->sc_tag, sc->sc_regh, CG12DAC_ADDR0, lo);
    378 	bus_space_write_4(sc->sc_tag, sc->sc_regh, CG12DAC_ADDR1, hi);
    379 	bus_space_write_4(sc->sc_tag, sc->sc_regh,
    380 	    use_alt ? CG12DAC_CTRL : CG12DAC_DATA,
    381 	    b << 16 | g << 8 | r);
    382 }
    383 
    384 static int
    385 cgtwelve_putcmap(struct cgtwelve_softc *sc, struct wsdisplay_cmap *cm)
    386 {
    387 	u_int index = cm->index;
    388 	u_int count = cm->count;
    389 	int i, error;
    390 
    391 	if (cm->index >= 256 || cm->count > 256 ||
    392 	    (cm->index + cm->count) > 256)
    393 		return EINVAL;
    394 	error = copyin(cm->red, &sc->sc_r[index], count);
    395 	if (error)
    396 		return error;
    397 	error = copyin(cm->green, &sc->sc_g[index], count);
    398 	if (error)
    399 		return error;
    400 	error = copyin(cm->blue, &sc->sc_b[index], count);
    401 	if (error)
    402 		return error;
    403 
    404 	if (sc->sc_depth == 8) {
    405 		for (i = index; i < index + count; i++) {
    406 			cgtwelve_write_dac(sc, i, sc->sc_r[i], sc->sc_g[i], sc->sc_b[i]);
    407 		}
    408 	}
    409 	return 0;
    410 }
    411 
    412 static int
    413 cgtwelve_getcmap(struct cgtwelve_softc *sc, struct wsdisplay_cmap *cm)
    414 {
    415 	u_int index = cm->index;
    416 	u_int count = cm->count;
    417 	int error;
    418 
    419 	if (index >= 255 || count > 256 || index + count > 256)
    420 		return EINVAL;
    421 
    422 
    423 	error = copyout(&sc->sc_r[index],   cm->red,   count);
    424 	if (error)
    425 		return error;
    426 	error = copyout(&sc->sc_g[index], cm->green, count);
    427 	if (error)
    428 		return error;
    429 	error = copyout(&sc->sc_b[index],  cm->blue,  count);
    430 	if (error)
    431 		return error;
    432 
    433 	return 0;
    434 }
    435 
    436 static void
    437 cgtwelve_setup(struct cgtwelve_softc *sc, int depth)
    438 {
    439 	int i, j;
    440 
    441 	/* first let's put some stuff into the WID table */
    442 	cgtwelve_write_wid(sc, 0, CG12_WID_8_BIT);
    443 	cgtwelve_write_wid(sc, 1, CG12_WID_24_BIT);
    444 
    445 	/* a linear ramp for the gamma table */
    446 	for (i = 0; i < 256; i++)
    447 		cgtwelve_write_dac(sc, i + 0x100, i, i, i);
    448 
    449 	j = 0;
    450 	/* rasops' ANSI colour map */
    451 	for (i = 0; i < 256; i++) {
    452 		sc->sc_r[i] = rasops_cmap[j];
    453 		sc->sc_g[i] = rasops_cmap[j + 1];
    454 		sc->sc_g[i] = rasops_cmap[j + 2];
    455 		cgtwelve_write_dac(sc, i,
    456 		    rasops_cmap[j],
    457 		    rasops_cmap[j + 1],
    458 		    rasops_cmap[j + 2]);
    459 		j += 3;
    460 	}
    461 
    462 	switch(depth) {
    463 	case 1:
    464 		/* setup the console */
    465 
    466 		/* first, make the overlay all opaque */
    467 		cgtwelve_select_ovl(sc, CG12_SEL_ENABLE);
    468 		memset(sc->sc_fbaddr, 0xff, 0x20000);
    469 
    470 		/* now write the right thing into the WID plane */
    471 		cgtwelve_select_ovl(sc, CG12_SEL_WID);
    472 		memset(sc->sc_wids, 0, 0x100000);
    473 
    474 		/* now clean the plane */
    475 		cgtwelve_select_ovl(sc, CG12_SEL_OVL);
    476 		memset(sc->sc_fbaddr, 0, 0x20000);
    477 		break;
    478 	case 8:
    479 		/* setup the 8bit fb */
    480 		/*
    481 		 * first clean the 8bit fb - for aesthetic reasons do it while
    482 		 * it's still not visible ( we hope... )
    483 		 */
    484 		cgtwelve_select_ovl(sc, CG12_SEL_8BIT);
    485 		memset(sc->sc_int, 0x00, 0x100000);
    486 
    487 		/* now write the right thing into the WID plane */
    488 		cgtwelve_select_ovl(sc, CG12_SEL_WID);
    489 		memset(sc->sc_wids, 0, 0x100000);
    490 
    491 		/* hide the overlay */
    492 		cgtwelve_select_ovl(sc, CG12_SEL_ENABLE);
    493 		memset(sc->sc_fbaddr, 0, 0x20000);
    494 
    495 		/* now clean the plane */
    496 		cgtwelve_select_ovl(sc, CG12_SEL_OVL);
    497 		memset(sc->sc_fbaddr, 0, 0x20000);
    498 
    499 		/* and make sure we can write the 8bit fb */
    500 		cgtwelve_select_ovl(sc, CG12_SEL_8BIT);
    501 		break;
    502 	case 24:
    503 	case 32:
    504 		/* setup the 24bit fb for X */
    505 		/*
    506 		 * first clean the 24bit fb - for aesthetic reasons do it while
    507 		 * it's still not visible ( we hope... )
    508 		 */
    509 		cgtwelve_select_ovl(sc, CG12_SEL_24BIT);
    510 		memset(sc->sc_int, 0x80, 0x400000);
    511 
    512 		/* now write the right thing into the WID plane */
    513 		cgtwelve_select_ovl(sc, CG12_SEL_WID);
    514 		memset(sc->sc_wids, 1, 0x100000);
    515 
    516 		/* hide the overlay */
    517 		cgtwelve_select_ovl(sc, CG12_SEL_ENABLE);
    518 		memset(sc->sc_fbaddr, 0, 0x20000);
    519 
    520 		/* now clean the plane */
    521 		cgtwelve_select_ovl(sc, CG12_SEL_OVL);
    522 		memset(sc->sc_fbaddr, 0, 0x20000);
    523 
    524 		/* and make sure we can write the 24bit fb */
    525 		cgtwelve_select_ovl(sc, CG12_SEL_24BIT);
    526 		break;
    527 	}
    528 }
    529 
    530 static void
    531 cgtwelve_set_video(struct cgtwelve_softc *sc, int on)
    532 {
    533 	uint32_t reg;
    534 	if (on == sc->sc_video) return;
    535 	on = on == 0 ? WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    536 	reg = bus_space_read_4(sc->sc_tag, sc->sc_regh, CG12APU_VSG_CTL);
    537 	reg &= ~CG12APU_VIDEO_ENABLE;
    538 	if (on) reg |= CG12APU_VIDEO_ENABLE;
    539 	bus_space_write_4(sc->sc_tag, sc->sc_regh, CG12APU_VSG_CTL, reg);
    540 	sc->sc_video = on;
    541 }
    542 
    543 static void
    544 cgtwelve_init_screen(void *cookie, struct vcons_screen *scr,
    545     int existing, long *defattr)
    546 {
    547 	struct cgtwelve_softc *sc = cookie;
    548 	struct rasops_info *ri = &scr->scr_ri;
    549 
    550 #ifdef CG12_COLOR
    551 	ri->ri_depth = 8;
    552 #else
    553 	ri->ri_depth = 1;
    554 #endif
    555 	ri->ri_width = sc->sc_width;
    556 	ri->ri_height = sc->sc_height;
    557 	ri->ri_stride = sc->sc_stride;
    558 	ri->ri_flg = RI_CENTER;
    559 
    560 	if (sc->sc_shadow == NULL) {
    561 #ifdef CG12_COLOR
    562 		ri->ri_bits = sc->sc_int;
    563 #else
    564 		ri->ri_bits = sc->sc_fbaddr;
    565 #endif
    566 		scr->scr_flags |= VCONS_DONT_READ;
    567 	} else {
    568 #ifdef CG12_COLOR
    569 		ri->ri_hwbits = sc->sc_int;
    570 #else
    571 		ri->ri_hwbits = sc->sc_fbaddr;
    572 #endif
    573 		ri->ri_bits = sc->sc_shadow;
    574 	}
    575 
    576 	rasops_init(ri, 0, 0);
    577 #ifdef CG12_COLOR
    578 	ri->ri_caps = WSSCREEN_REVERSE | WSSCREEN_WSCOLORS;
    579 #else
    580 	ri->ri_caps = WSSCREEN_REVERSE;
    581 #endif
    582 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
    583 		    ri->ri_width / ri->ri_font->fontwidth);
    584 }
    585 
    586 static int
    587 cgtwelve_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    588     struct lwp *l)
    589 {
    590 	struct vcons_data *vd = v;
    591 	struct cgtwelve_softc *sc = vd->cookie;
    592 	struct wsdisplay_fbinfo *wdf;
    593 	struct vcons_screen *ms = vd->active;
    594 
    595 	switch (cmd) {
    596 		case WSDISPLAYIO_GTYPE:
    597 			*(u_int *)data = WSDISPLAY_TYPE_SUNCG12;
    598 			return 0;
    599 
    600 		case WSDISPLAYIO_GINFO:
    601 			wdf = (void *)data;
    602 			wdf->height = sc->sc_height;
    603 			wdf->width = sc->sc_width;
    604 			wdf->depth = sc->sc_depth;
    605 			wdf->cmsize = 256;
    606 			return 0;
    607 
    608 		case FBIOGVIDEO:
    609 		case WSDISPLAYIO_GVIDEO:
    610 			*(int *)data = sc->sc_video;
    611 			return 0;
    612 
    613 		case WSDISPLAYIO_SVIDEO:
    614 		case FBIOSVIDEO:
    615 			cgtwelve_set_video(sc, *(int *)data);
    616 			return 0;
    617 
    618 		case WSDISPLAYIO_GETCMAP:
    619 			return cgtwelve_getcmap(sc,
    620 			    (struct wsdisplay_cmap *)data);
    621 
    622 		case WSDISPLAYIO_PUTCMAP:
    623 			return cgtwelve_putcmap(sc,
    624 			    (struct wsdisplay_cmap *)data);
    625 
    626 		case WSDISPLAYIO_LINEBYTES:
    627 			{
    628 				int *ret = (int *)data;
    629 				if (sc->sc_depth == 32) {
    630 					*ret = sc->sc_width << 2;
    631 				} else
    632 					*ret = sc->sc_width;
    633 			}
    634 			return 0;
    635 
    636 		case WSDISPLAYIO_SMODE:
    637 			{
    638 				int new_mode = *(int*)data;
    639 				if (new_mode != sc->sc_mode)
    640 				{
    641 					sc->sc_mode = new_mode;
    642 					if (new_mode == WSDISPLAYIO_MODE_EMUL)
    643 					{
    644 #ifdef CG12_COLOR
    645 						cgtwelve_setup(sc, 8);
    646 #else
    647 						cgtwelve_setup(sc, 1);
    648 #endif
    649 						vcons_redraw_screen(ms);
    650 					} else {
    651 						cgtwelve_setup(sc, sc->sc_depth);
    652 					}
    653 				}
    654 			}
    655 			return 0;
    656 
    657 		case WSDISPLAYIO_GCURPOS:
    658 			{
    659 				struct wsdisplay_curpos *cp = (void *)data;
    660 
    661 				cp->x = sc->sc_cursor_x;
    662 				cp->y = sc->sc_cursor_y;
    663 			}
    664 			return 0;
    665 
    666 		case WSDISPLAYIO_SCURPOS:
    667 			{
    668 				struct wsdisplay_curpos *cp = (void *)data;
    669 
    670 				cgtwelve_move_cursor(sc, cp->x, cp->y);
    671 			}
    672 			return 0;
    673 
    674 		case WSDISPLAYIO_GCURMAX:
    675 			{
    676 				struct wsdisplay_curpos *cp = (void *)data;
    677 
    678 				cp->x = 32;
    679 				cp->y = 32;
    680 			}
    681 			return 0;
    682 
    683 		case WSDISPLAYIO_SCURSOR:
    684 			{
    685 				struct wsdisplay_cursor *cursor = (void *)data;
    686 
    687 				return cgtwelve_do_cursor(sc, cursor);
    688 			}
    689 
    690 		case WSDISPLAYIO_SET_DEPTH:
    691 			{
    692 				int new_depth = *(int*)data;
    693 
    694 				if ((new_depth == 8) || (new_depth == 32)) {
    695 					sc->sc_depth = new_depth;
    696 					return 0;
    697 				}
    698 				return EINVAL;
    699 			}
    700 
    701 		case WSDISPLAYIO_GET_FBINFO:
    702 		{
    703 			struct wsdisplayio_fbinfo *fbi = data;
    704 
    705 			if (sc->sc_depth == 8) {
    706 				fbi->fbi_stride = sc->sc_width;
    707 				fbi->fbi_fbsize = 1024 * 1024;
    708 				fbi->fbi_bitsperpixel = 8;
    709 				fbi->fbi_pixeltype = WSFB_CI;
    710 			} else {
    711 				fbi->fbi_stride = sc->sc_width * 4;
    712 				fbi->fbi_fbsize = 4 * 1024 * 1024;
    713 				fbi->fbi_bitsperpixel = 32;
    714 				fbi->fbi_pixeltype = WSFB_RGB;
    715 			}
    716 			fbi->fbi_width = sc->sc_width;
    717 			fbi->fbi_height = sc->sc_height;
    718 			fbi->fbi_subtype.fbi_rgbmasks.red_offset = 0;
    719 			fbi->fbi_subtype.fbi_rgbmasks.red_size = 8;
    720 			fbi->fbi_subtype.fbi_rgbmasks.green_offset = 8;
    721 			fbi->fbi_subtype.fbi_rgbmasks.green_size = 8;
    722 			fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 16;
    723 			fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8;
    724 			fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0;
    725 			fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0;
    726 			return 0;
    727 		}
    728 	}
    729 
    730 	return EPASSTHROUGH;
    731 }
    732 
    733 static paddr_t
    734 cgtwelve_mmap(void *v, void *vs, off_t offset, int prot)
    735 {
    736 	struct vcons_data *vd = v;
    737 	struct cgtwelve_softc *sc = vd->cookie;
    738 
    739 	/* regular fb mapping at 0 */
    740 	if ((offset >= 0) && (offset < 0x400000)) {
    741 		return bus_space_mmap(sc->sc_tag, sc->sc_paddr + CG12_OFF_INTEN,
    742 		    offset, prot, BUS_SPACE_MAP_LINEAR);
    743 	}
    744 
    745 	return -1;
    746 }
    747 
    748 static void
    749 cgtwelve_move_cursor(struct cgtwelve_softc *sc, int x, int y)
    750 {
    751 	int start, end, wi, he;
    752 	uint8_t *saddr;
    753 	uint32_t *addr;
    754 	int monostride = sc->sc_width >> 5;
    755 	int shift, i;
    756 
    757 	/* first we clear the old image */
    758 	start = sc->sc_cursor_x & ~0x1f;
    759 	end = (sc->sc_cursor_x + sc->sc_cursor_wi - 1) & ~0x1f;
    760 	/* if start == end the whole thing fits in one 32bit word */
    761 	cgtwelve_select_ovl(sc, CG12_SEL_ENABLE);
    762 	wi = sc->sc_width - sc->sc_cursor_x - 1;
    763 	if (wi > sc->sc_cursor_wi) wi = sc->sc_cursor_wi;
    764 	if (wi < 1) goto skip;
    765 	he = sc->sc_height - sc->sc_cursor_y - 1;
    766 	if (he > sc->sc_cursor_he) he = sc->sc_cursor_he;
    767 	if (he < 1) goto skip;
    768 	saddr = (uint8_t *)sc->sc_fbaddr + (start >> 3);
    769 	if (start == end) {
    770 		addr = (uint32_t *)saddr + monostride * sc->sc_cursor_y;
    771 		for (i = 0; i < he; i++) {
    772 			*addr = 0;
    773 			addr += monostride;
    774 		}
    775 	} else {
    776 		addr = (uint32_t *)saddr + monostride * sc->sc_cursor_y;
    777 		for (i = 0; i < he; i++) {
    778 			addr[0] = 0;
    779 			addr[1] = 0;
    780 			addr += monostride;
    781 		}
    782 	}
    783 	/* clear it in the image plane as well */
    784 	cgtwelve_select_ovl(sc, CG12_SEL_OVL);
    785 	if (start == end) {
    786 		addr = (uint32_t *)saddr + monostride * sc->sc_cursor_y;
    787 		for (i = 0; i < he; i++) {
    788 			*addr = 0;
    789 			addr += monostride;
    790 		}
    791 	} else {
    792 		addr = (uint32_t *)saddr + monostride * sc->sc_cursor_y;
    793 		for (i = 0; i < he; i++) {
    794 			addr[0] = 0;
    795 			addr[1] = 0;
    796 			addr += monostride;
    797 		}
    798 	}
    799 skip:
    800 	/* now draw the cursor at the new position, mask first */
    801 	cgtwelve_select_ovl(sc, CG12_SEL_ENABLE);
    802 	wi = sc->sc_width - x - 1;
    803 	if (wi > sc->sc_cursor_wi) wi = sc->sc_cursor_wi;
    804 	if (wi < 1) goto out;
    805 	he = sc->sc_height - y - 1;
    806 	if (he > sc->sc_cursor_he) he = sc->sc_cursor_he;
    807 	if (he < 1) goto out;
    808 
    809 	start = x & ~0x1f;
    810 	end =   (x + wi - 1) & ~0x1f;
    811 	saddr = (uint8_t *)sc->sc_fbaddr + (start >> 3);
    812 	shift = x & 0x1f;
    813 	if ((shift + wi) < 32) {
    814 		/* fits in a single 32bit word */
    815 		addr = (uint32_t *)saddr + monostride * y;
    816 		for (i = 0; i < he; i++) {
    817 			*addr = sc->sc_cursor_mask[i] >> shift;
    818 			addr += monostride;
    819 		}
    820 	} else {
    821 		/* split into two 32bit words */
    822 		addr = (uint32_t *)saddr + monostride * y;
    823 		for (i = 0; i < he; i++) {
    824 			addr[0] = sc->sc_cursor_mask[i] >> shift;
    825 			addr[1] = sc->sc_cursor_mask[i] << (32 - shift);
    826 			addr += monostride;
    827 		}
    828 	}
    829 	/* ... and now the image */
    830 	cgtwelve_select_ovl(sc, CG12_SEL_OVL);
    831 	if ((shift + wi) < 32) {
    832 		/* fits in a single 32bit word */
    833 		addr = (uint32_t *)saddr + monostride * y;
    834 		for (i = 0; i < he; i++) {
    835 			*addr = sc->sc_cursor_image[i] >> shift;
    836 			addr += monostride;
    837 		}
    838 	} else {
    839 		/* split into two 32bit words */
    840 		addr = (uint32_t *)saddr + monostride * y;
    841 		for (i = 0; i < he; i++) {
    842 			addr[0] = sc->sc_cursor_image[i] >> shift;
    843 			addr[1] = sc->sc_cursor_image[i] << (32 - shift);
    844 			addr += monostride;
    845 		}
    846 	}
    847 out:
    848 	sc->sc_cursor_x = x;
    849 	sc->sc_cursor_y = y;
    850 	cgtwelve_select_ovl(sc, sc->sc_depth == 8 ? CG12_SEL_8BIT : CG12_SEL_24BIT);
    851 }
    852 
    853 static int
    854 cgtwelve_do_cursor(struct cgtwelve_softc *sc,
    855                            struct wsdisplay_cursor *cur)
    856 {
    857 	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
    858 
    859 		if (cur->enable != sc->sc_cursor_on) {
    860 			/* clear or draw as needed */
    861 			sc->sc_cursor_on = cur->enable;
    862 		}
    863 	}
    864 	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
    865 
    866 		sc->sc_hot_x = cur->hot.x;
    867 		sc->sc_hot_y = cur->hot.y;
    868 		cur->which |= WSDISPLAY_CURSOR_DOPOS;
    869 	}
    870 	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
    871 
    872 		cgtwelve_move_cursor(sc, cur->pos.x, cur->pos.y);
    873 	}
    874 	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
    875 		int i;
    876 
    877 		if ((cur->cmap.index > 1) || (cur->cmap.count > 2) ||
    878 		    (cur->cmap.index + cur->cmap.count > 2))
    879 			return EINVAL;
    880 
    881 		for (i = 0; i < uimin(cur->cmap.count, 2); i++) {
    882 			/* overlay colours live in alt space at 0x100 */
    883 			cgtwelve_write_dac(sc, ((i << 1) + cur->cmap.index + 1) | 0x10100, cur->cmap.red[i],
    884 			    cur->cmap.green[i], cur->cmap.blue[i]);
    885 		}
    886 	}
    887 	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
    888 		uint32_t buffer[32], latch, tmp;
    889 		int i, s;
    890 
    891 		sc->sc_cursor_wi = 0;
    892 		sc->sc_cursor_he = 0;
    893 		copyin(cur->mask, buffer, 128);
    894 		for (i = 0; i < 32; i++) {
    895 			latch = 0;
    896 			tmp = buffer[i] & 0x80808080;
    897 			latch |= tmp >> 7;
    898 			tmp = buffer[i] & 0x40404040;
    899 			latch |= tmp >> 5;
    900 			tmp = buffer[i] & 0x20202020;
    901 			latch |= tmp >> 3;
    902 			tmp = buffer[i] & 0x10101010;
    903 			latch |= tmp >> 1;
    904 			tmp = buffer[i] & 0x08080808;
    905 			latch |= tmp << 1;
    906 			tmp = buffer[i] & 0x04040404;
    907 			latch |= tmp << 3;
    908 			tmp = buffer[i] & 0x02020202;
    909 			latch |= tmp << 5;
    910 			tmp = buffer[i] & 0x01010101;
    911 			latch |= tmp << 7;
    912 			sc->sc_cursor_mask[i] = latch;
    913 			/* measure sprite size to optimize drawing */
    914 			if (latch != 0) {
    915 				sc->sc_cursor_he = i + 1;
    916 				s = ffs(latch);
    917 				s = 33 - s;
    918 				if (s > sc->sc_cursor_wi) sc->sc_cursor_wi = s;
    919 			}
    920 		}
    921 
    922 		copyin(cur->image, buffer, 128);
    923 		for (i = 0; i < 32; i++) {
    924 			latch = 0;
    925 			tmp = buffer[i] & 0x80808080;
    926 			latch |= tmp >> 7;
    927 			tmp = buffer[i] & 0x40404040;
    928 			latch |= tmp >> 5;
    929 			tmp = buffer[i] & 0x20202020;
    930 			latch |= tmp >> 3;
    931 			tmp = buffer[i] & 0x10101010;
    932 			latch |= tmp >> 1;
    933 			tmp = buffer[i] & 0x08080808;
    934 			latch |= tmp << 1;
    935 			tmp = buffer[i] & 0x04040404;
    936 			latch |= tmp << 3;
    937 			tmp = buffer[i] & 0x02020202;
    938 			latch |= tmp << 5;
    939 			tmp = buffer[i] & 0x01010101;
    940 			latch |= tmp << 7;
    941 			sc->sc_cursor_image[i] = latch;
    942 		}
    943 	}
    944 	return 0;
    945 }
    946 
    947