Home | History | Annotate | Line # | Download | only in dev
hyperfb.c revision 1.1
      1 /*	$NetBSD: hyperfb.c,v 1.1 2024/07/12 08:43:08 macallan Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2024 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     26  * THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * a native driver for HCRX / hyperdrive cards
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: hyperfb.c,v 1.1 2024/07/12 08:43:08 macallan Exp $");
     35 
     36 #include "opt_cputype.h"
     37 #include "opt_hyperfb.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/device.h>
     42 
     43 #include <sys/bus.h>
     44 #include <machine/cpu.h>
     45 #include <machine/iomod.h>
     46 #include <machine/autoconf.h>
     47 
     48 #include <dev/wscons/wsdisplayvar.h>
     49 #include <dev/wscons/wsconsio.h>
     50 #include <dev/wsfont/wsfont.h>
     51 #include <dev/rasops/rasops.h>
     52 #include <dev/wscons/wsdisplay_vconsvar.h>
     53 #include <dev/wscons/wsdisplay_glyphcachevar.h>
     54 
     55 #include <dev/ic/stireg.h>
     56 #include <dev/ic/stivar.h>
     57 
     58 #include <hppa/dev/cpudevs.h>
     59 #include <hppa/hppa/machdep.h>
     60 
     61 #ifdef HYPERFB_DEBUG
     62 #define	DPRINTF printf
     63 #else
     64 #define DPRINTF if (0) printf
     65 #endif
     66 
     67 #define	STI_ROMSIZE	(sizeof(struct sti_dd) * 4)
     68 
     69 #define HCRX_FBOFFSET	0x01000000
     70 #define HCRX_FBLEN	0x01000000
     71 #define HCRX_REGOFFSET	0x00100000
     72 #define HCRX_REGLEN	0x00280000
     73 
     74 #define HCRX_CONFIG_24BIT	0x100
     75 
     76 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
     77 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
     78 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
     79 #define HYPERBOWL_MODE2_8_24					15
     80 
     81 int hyperfb_match(device_t, cfdata_t, void *);
     82 void hyperfb_attach(device_t, device_t, void *);
     83 
     84 struct	hyperfb_softc {
     85 	device_t		sc_dev;
     86 	bus_space_tag_t		sc_iot;
     87 	bus_addr_t		sc_base;
     88 	bus_space_handle_t	sc_hfb, sc_hreg;
     89 	void 			*sc_fb;
     90 
     91 	int sc_width, sc_height;
     92 	int sc_locked, sc_is_console, sc_24bit;
     93 	struct vcons_screen sc_console_screen;
     94 	struct wsscreen_descr sc_defaultscreen_descr;
     95 	const struct wsscreen_descr *sc_screens[1];
     96 	struct wsscreen_list sc_screenlist;
     97 	struct vcons_data vd;
     98 	int sc_mode;
     99 	void (*sc_putchar)(void *, int, int, u_int, long);
    100 	u_char sc_cmap_red[256];
    101 	u_char sc_cmap_green[256];
    102 	u_char sc_cmap_blue[256];
    103 	kmutex_t sc_hwlock;
    104 	uint32_t sc_hwmode;
    105 #define HW_FB	0
    106 #define HW_FILL	1
    107 #define HW_BLIT	2
    108 	uint32_t sc_rect_colour, sc_rect_height;
    109 	/* cursor stuff */
    110 	int sc_cursor_x, sc_cursor_y;
    111 	int sc_hot_x, sc_hot_y, sc_enabled;
    112 	int sc_video_on;
    113 	glyphcache sc_gc;
    114 };
    115 
    116 extern struct cfdriver hyperfb_cd;
    117 
    118 CFATTACH_DECL_NEW(hyperfb, sizeof(struct hyperfb_softc), hyperfb_match,
    119     hyperfb_attach, NULL, NULL);
    120 
    121 void 		hyperfb_setup_fb(struct hyperfb_softc *);
    122 static void 	hyperfb_init_screen(void *, struct vcons_screen *,
    123 			    int, long *);
    124 static int	hyperfb_ioctl(void *, void *, u_long, void *, int,
    125 			     struct lwp *);
    126 static paddr_t	hyperfb_mmap(void *, void *, off_t, int);
    127 
    128 static int	hyperfb_putcmap(struct hyperfb_softc *, struct wsdisplay_cmap *);
    129 static int 	hyperfb_getcmap(struct hyperfb_softc *, struct wsdisplay_cmap *);
    130 static void	hyperfb_restore_palette(struct hyperfb_softc *);
    131 static int 	hyperfb_putpalreg(struct hyperfb_softc *, uint8_t, uint8_t,
    132 			    uint8_t, uint8_t);
    133 void 	hyperfb_setup(struct hyperfb_softc *);
    134 static void	hyperfb_set_video(struct hyperfb_softc *, int);
    135 
    136 #define	ngle_bt458_write(sc, r, v) \
    137 	hyperfb_write4(sc, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
    138 
    139 struct wsdisplay_accessops hyperfb_accessops = {
    140 	hyperfb_ioctl,
    141 	hyperfb_mmap,
    142 	NULL,	/* alloc_screen */
    143 	NULL,	/* free_screen */
    144 	NULL,	/* show_screen */
    145 	NULL, 	/* load_font */
    146 	NULL,	/* pollc */
    147 	NULL	/* scroll */
    148 };
    149 
    150 static inline uint32_t
    151 hyperfb_read4(struct hyperfb_softc *sc, uint32_t offset)
    152 {
    153 	return bus_space_read_4(sc->sc_iot, sc->sc_hreg, offset);
    154 }
    155 
    156 static inline uint8_t
    157 hyperfb_read1(struct hyperfb_softc *sc, uint32_t offset)
    158 {
    159 	return bus_space_read_1(sc->sc_iot, sc->sc_hreg, offset);
    160 }
    161 
    162 static inline void
    163 hyperfb_write4(struct hyperfb_softc *sc, uint32_t offset, uint32_t val)
    164 {
    165 	bus_space_write_4(sc->sc_iot, sc->sc_hreg, offset, val);
    166 }
    167 
    168 static inline void
    169 hyperfb_write1(struct hyperfb_softc *sc, uint32_t offset, uint8_t val)
    170 {
    171 	bus_space_write_1(sc->sc_iot, sc->sc_hreg, offset, val);
    172 }
    173 
    174 static inline void
    175 hyperfb_wait(struct hyperfb_softc *sc)
    176 {
    177 	uint8_t stat;
    178 
    179 	do {
    180 		stat = hyperfb_read1(sc, NGLE_REG_15b0);
    181 		if (stat == 0)
    182 			stat = hyperfb_read1(sc, NGLE_REG_15b0);
    183 	} while (stat != 0);
    184 }
    185 
    186 void
    187 hyperfb_setup_fb(struct hyperfb_softc *sc)
    188 {
    189 
    190 	hyperfb_wait(sc);
    191 	hyperfb_write4(sc, NGLE_REG_10, 0x13602000);	/* 8bit */
    192 	hyperfb_write4(sc, NGLE_REG_14, 0x83000300);
    193 	hyperfb_wait(sc);
    194 	hyperfb_write1(sc, NGLE_REG_16b1, 1);
    195 	sc->sc_hwmode = HW_FB;
    196 }
    197 
    198 int
    199 hyperfb_match(device_t parent, cfdata_t cf, void *aux)
    200 {
    201 	struct confargs *ca = aux;
    202 	bus_space_handle_t romh;
    203 	paddr_t rom;
    204 	uint32_t id = 0;
    205 	u_char devtype;
    206 	int rv = 0, romunmapped = 0;
    207 
    208 	if (ca->ca_type.iodc_type != HPPA_TYPE_FIO)
    209 		return 0;
    210 
    211 	/* these need further checking for the graphics id */
    212 	if (ca->ca_type.iodc_sv_model != HPPA_FIO_GSGC &&
    213 	    ca->ca_type.iodc_sv_model != HPPA_FIO_SGC)
    214 		return 0;
    215 
    216 	if (ca->ca_naddrs > 0)
    217 		rom = ca->ca_addrs[0].addr;
    218 	else
    219 		rom = ca->ca_hpa;
    220 
    221 	DPRINTF("%s: hpa=%x, rom=%x\n", __func__, (uint)ca->ca_hpa,
    222 	    (uint)rom);
    223 
    224 	/* if it does not map, probably part of the lasi space */
    225 	if (bus_space_map(ca->ca_iot, rom, STI_ROMSIZE, 0, &romh)) {
    226 		DPRINTF("%s: can't map rom space (%d)\n", __func__, rv);
    227 
    228 		if ((rom & HPPA_IOBEGIN) == HPPA_IOBEGIN) {
    229 			romh = rom;
    230 			romunmapped++;
    231 		} else {
    232 			/* in this case nobody has no freaking idea */
    233 			return 0;
    234 		}
    235 	}
    236 
    237 	devtype = bus_space_read_1(ca->ca_iot, romh, 3);
    238 	DPRINTF("%s: devtype=%d\n", __func__, devtype);
    239 	rv = 1;
    240 	switch (devtype) {
    241 	case STI_DEVTYPE4:
    242 		id = bus_space_read_4(ca->ca_iot, romh, STI_DEV4_DD_GRID);
    243 		break;
    244 	case STI_DEVTYPE1:
    245 		id = (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
    246 		    +  3) << 24) |
    247 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
    248 		    +  7) << 16) |
    249 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
    250 		    + 11) <<  8) |
    251 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
    252 		    + 15));
    253 		break;
    254 	default:
    255 		DPRINTF("%s: unknown type (%x)\n", __func__, devtype);
    256 		rv = 0;
    257 	}
    258 
    259 	if (id == STI_DD_HCRX)
    260 		rv = 100;	/* beat out sti */
    261 
    262 	ca->ca_addrs[ca->ca_naddrs].addr = rom;
    263 	ca->ca_addrs[ca->ca_naddrs].size = sti_rom_size(ca->ca_iot, romh);
    264 	ca->ca_naddrs++;
    265 
    266 	if (!romunmapped)
    267 		bus_space_unmap(ca->ca_iot, romh, STI_ROMSIZE);
    268 	return rv;
    269 }
    270 
    271 void
    272 hyperfb_attach(device_t parent, device_t self, void *aux)
    273 {
    274 	struct hyperfb_softc *sc = device_private(self);
    275 	struct confargs *ca = aux;
    276 	struct rasops_info *ri;
    277 	struct wsemuldisplaydev_attach_args aa;
    278 	bus_space_handle_t hrom;
    279 	hppa_hpa_t consaddr;
    280 	long defattr;
    281 	int pagezero_cookie;
    282 	paddr_t rom;
    283 	uint32_t config;
    284 
    285 	pagezero_cookie = hppa_pagezero_map();
    286 	consaddr = (hppa_hpa_t)PAGE0->mem_cons.pz_hpa;
    287 	hppa_pagezero_unmap(pagezero_cookie);
    288 
    289 	sc->sc_dev = self;
    290 	sc->sc_base = ca->ca_hpa;
    291 	sc->sc_iot = ca->ca_iot;
    292 	sc->sc_is_console =(ca->ca_hpa == consaddr);
    293 	sc->sc_width = 1280;
    294 	sc->sc_height = 1024;
    295 
    296 	/* we can *not* be interrupted when doing colour map accesses */
    297 	mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH);
    298 
    299 	/* we stashed rom addr/len into the last slot during probe */
    300 	rom = ca->ca_addrs[ca->ca_naddrs - 1].addr;
    301 
    302 	if (bus_space_map(sc->sc_iot,
    303 	    sc->sc_base + HCRX_FBOFFSET, HCRX_FBLEN,
    304 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE,
    305 	    &sc->sc_hfb)) {
    306 	    	aprint_error_dev(sc->sc_dev, "failed to map the framebuffer\n");
    307 	    	return;
    308 	}
    309 	sc->sc_fb = bus_space_vaddr(sc->sc_iot, sc->sc_hfb);
    310 
    311 	if (bus_space_map(sc->sc_iot,
    312 	    sc->sc_base + HCRX_REGOFFSET, HCRX_REGLEN, 0, &sc->sc_hreg)) {
    313 	    	aprint_error_dev(sc->sc_dev, "failed to map registers\n");
    314 	    	return;
    315 	}
    316 
    317 	/*
    318 	 * we really only need the first word so we can grab the config bits
    319 	 * between the bytes
    320 	 */
    321 	if (bus_space_map(sc->sc_iot,
    322 	    rom, 4, 0, &hrom)) {
    323 	    	aprint_error_dev(sc->sc_dev, "failed to map ROM, assuming 8bit\n");
    324 	    	config = 0;
    325 	} else {
    326 		/* alright, we got the ROM. now do the idle dance. */
    327 		volatile uint32_t r = hyperfb_read4(sc, NGLE_REG_15);
    328 		__USE(r);
    329 		hyperfb_wait(sc);
    330 		config = bus_space_read_4(sc->sc_iot, hrom, 0);
    331 		bus_space_unmap(sc->sc_iot, hrom, 4);
    332 	}
    333 	sc->sc_24bit = ((config & HCRX_CONFIG_24BIT) != 0);
    334 
    335 	printf(" %s\n", sc->sc_24bit ? "HCRX24" : "HCRX");
    336 #ifdef HP7300LC_CPU
    337 	/*
    338 	 * PCXL2: enable accel I/O for this space, see PCX-L2 ERS "ACCEL_IO".
    339 	 * "pcxl2_ers.{ps,pdf}", (section / chapter . rel. page / abs. page)
    340 	 * 8.7.4 / 8-12 / 92, 11.3.14 / 11-14 / 122 and 14.8 / 14-5 / 203.
    341 	 */
    342 	if (hppa_cpu_info->hci_cputype == hpcxl2
    343 	    && ca->ca_hpa >= PCXL2_ACCEL_IO_START
    344 	    && ca->ca_hpa <= PCXL2_ACCEL_IO_END)
    345 		eaio_l2(PCXL2_ACCEL_IO_ADDR2MASK(ca->ca_hpa));
    346 #endif /* HP7300LC_CPU */
    347 
    348 	hyperfb_setup(sc);
    349 	hyperfb_setup_fb(sc);
    350 
    351 	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
    352 		"default",
    353 		0, 0,
    354 		NULL,
    355 		8, 16,
    356 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
    357 		      WSSCREEN_RESIZE,
    358 		NULL
    359 	};
    360 
    361 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
    362 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
    363 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    364 	sc->sc_locked = 0;
    365 
    366 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
    367 	    &hyperfb_accessops);
    368 	sc->vd.init_screen = hyperfb_init_screen;
    369 	sc->vd.show_screen_cookie = &sc->sc_gc;
    370 	sc->vd.show_screen_cb = glyphcache_adapt;
    371 
    372 	ri = &sc->sc_console_screen.scr_ri;
    373 
    374 	//sc->sc_gc.gc_bitblt = hyperfb_bitblt;
    375 	//sc->sc_gc.gc_blitcookie = sc;
    376 	//sc->sc_gc.gc_rop = RopSrc;
    377 
    378 	if (sc->sc_is_console) {
    379 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    380 		    &defattr);
    381 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    382 
    383 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
    384 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
    385 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
    386 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
    387 
    388 #if 0
    389 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
    390 				sc->sc_scr.fbheight - sc->sc_height - 5,
    391 				sc->sc_scr.fbwidth,
    392 				ri->ri_font->fontwidth,
    393 				ri->ri_font->fontheight,
    394 				defattr);
    395 #endif
    396 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
    397 		    defattr);
    398 #if 0
    399 		hyperfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
    400 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
    401 #endif
    402 		vcons_replay_msgbuf(&sc->sc_console_screen);
    403 	} else {
    404 		/*
    405 		 * since we're not the console we can postpone the rest
    406 		 * until someone actually allocates a screen for us
    407 		 */
    408 		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
    409 			/* do some minimal setup to avoid weirdnesses later */
    410 			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    411 			    &defattr);
    412 		} else
    413 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    414 
    415 #if 0
    416 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
    417 				sc->sc_scr.fbheight - sc->sc_height - 5,
    418 				sc->sc_scr.fbwidth,
    419 				ri->ri_font->fontwidth,
    420 				ri->ri_font->fontheight,
    421 				defattr);
    422 #endif
    423 	}
    424 
    425 	hyperfb_restore_palette(sc);
    426 
    427 	/* no suspend/resume support yet */
    428 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
    429 		aprint_error_dev(sc->sc_dev,
    430 		    "couldn't establish power handler\n");
    431 
    432 	aa.console = sc->sc_is_console;
    433 	aa.scrdata = &sc->sc_screenlist;
    434 	aa.accessops = &hyperfb_accessops;
    435 	aa.accesscookie = &sc->vd;
    436 
    437 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
    438 
    439 }
    440 
    441 static void
    442 hyperfb_init_screen(void *cookie, struct vcons_screen *scr,
    443     int existing, long *defattr)
    444 {
    445 	struct hyperfb_softc *sc = cookie;
    446 	struct rasops_info *ri = &scr->scr_ri;
    447 
    448 	ri->ri_depth = 8;
    449 	ri->ri_width = 1280;
    450 	ri->ri_height = 1024;
    451 	ri->ri_stride = 2048;
    452 	ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB /*|
    453 		     RI_ENABLE_ALPHA | RI_PREFER_ALPHA*/;
    454 
    455 	ri->ri_bits = (void *)sc->sc_fb;
    456 	rasops_init(ri, 0, 0);
    457 	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
    458 		      WSSCREEN_RESIZE;
    459 	scr->scr_flags |= VCONS_LOADFONT | VCONS_DONT_READ;
    460 
    461 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
    462 		    sc->sc_width / ri->ri_font->fontwidth);
    463 
    464 	ri->ri_hw = scr;
    465 #if 0
    466 	sc->sc_putchar = ri->ri_ops.putchar;
    467 	ri->ri_ops.copyrows = gftfb_copyrows;
    468 	ri->ri_ops.copycols = gftfb_copycols;
    469 	ri->ri_ops.eraserows = gftfb_eraserows;
    470 	ri->ri_ops.erasecols = gftfb_erasecols;
    471 	ri->ri_ops.cursor = gftfb_cursor;
    472 	ri->ri_ops.putchar = gftfb_putchar;
    473 #endif
    474 }
    475 
    476 static int
    477 hyperfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    478 	struct lwp *l)
    479 {
    480 	struct vcons_data *vd = v;
    481 	struct hyperfb_softc *sc = vd->cookie;
    482 	struct wsdisplay_fbinfo *wdf;
    483 	struct vcons_screen *ms = vd->active;
    484 
    485 	switch (cmd) {
    486 	case WSDISPLAYIO_GTYPE:
    487 		*(u_int *)data = WSDISPLAY_TYPE_STI;
    488 		return 0;
    489 
    490 	case WSDISPLAYIO_GINFO:
    491 		if (ms == NULL)
    492 			return ENODEV;
    493 		wdf = (void *)data;
    494 		wdf->height = ms->scr_ri.ri_height;
    495 		wdf->width = ms->scr_ri.ri_width;
    496 		wdf->depth = ms->scr_ri.ri_depth;
    497 		wdf->cmsize = 256;
    498 		return 0;
    499 
    500 	case WSDISPLAYIO_GETCMAP:
    501 		return hyperfb_getcmap(sc,
    502 		    (struct wsdisplay_cmap *)data);
    503 
    504 	case WSDISPLAYIO_PUTCMAP:
    505 		return hyperfb_putcmap(sc,
    506 		    (struct wsdisplay_cmap *)data);
    507 	case WSDISPLAYIO_LINEBYTES:
    508 		*(u_int *)data = 2048;
    509 		return 0;
    510 
    511 	case WSDISPLAYIO_SMODE: {
    512 		int new_mode = *(int*)data;
    513 		if (new_mode != sc->sc_mode) {
    514 			sc->sc_mode = new_mode;
    515 			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
    516 				hyperfb_setup(sc);
    517 				hyperfb_restore_palette(sc);
    518 #if 0
    519 				glyphcache_wipe(&sc->sc_gc);
    520 				hyperfb_rectfill(sc, 0, 0, sc->sc_width,
    521 				    sc->sc_height, ms->scr_ri.ri_devcmap[
    522 				    (ms->scr_defattr >> 16) & 0xff]);
    523 #endif
    524 				vcons_redraw_screen(ms);
    525 				hyperfb_set_video(sc, 1);
    526 			}
    527 		}
    528 		}
    529 		return 0;
    530 
    531 	case WSDISPLAYIO_GET_FBINFO:
    532 		{
    533 			struct wsdisplayio_fbinfo *fbi = data;
    534 			int ret;
    535 
    536 			ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
    537 			fbi->fbi_fbsize = sc->sc_height * 2048;
    538 			return ret;
    539 		}
    540 
    541 #if 0
    542 	case WSDISPLAYIO_GCURPOS:
    543 		{
    544 			struct wsdisplay_curpos *cp = (void *)data;
    545 
    546 			cp->x = sc->sc_cursor_x;
    547 			cp->y = sc->sc_cursor_y;
    548 		}
    549 		return 0;
    550 
    551 	case WSDISPLAYIO_SCURPOS:
    552 		{
    553 			struct wsdisplay_curpos *cp = (void *)data;
    554 
    555 			gftfb_move_cursor(sc, cp->x, cp->y);
    556 		}
    557 		return 0;
    558 
    559 	case WSDISPLAYIO_GCURMAX:
    560 		{
    561 			struct wsdisplay_curpos *cp = (void *)data;
    562 
    563 			cp->x = 64;
    564 			cp->y = 64;
    565 		}
    566 		return 0;
    567 
    568 	case WSDISPLAYIO_SCURSOR:
    569 		{
    570 			struct wsdisplay_cursor *cursor = (void *)data;
    571 
    572 			return gftfb_do_cursor(sc, cursor);
    573 		}
    574 #endif
    575 
    576 	case WSDISPLAYIO_SVIDEO:
    577 		hyperfb_set_video(sc, *(int *)data);
    578 		return 0;
    579 	case WSDISPLAYIO_GVIDEO:
    580 		return sc->sc_video_on ?
    581 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
    582 	}
    583 	return EPASSTHROUGH;
    584 }
    585 
    586 static paddr_t
    587 hyperfb_mmap(void *v, void *vs, off_t offset, int prot)
    588 {
    589 	struct vcons_data *vd = v;
    590 	struct hyperfb_softc *sc = vd->cookie;
    591 	paddr_t pa = -1;
    592 
    593 
    594 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)
    595 		return -1;
    596 
    597 	if (offset >= 0 || offset < 2048 * 1024) {
    598 		/* framebuffer */
    599 		pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_FBOFFSET, offset,
    600 		    prot, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
    601 	} else if (offset >= 0x80000000 && offset < 0x8040000) {
    602 		/* blitter registers etc. */
    603 		pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_REGOFFSET,
    604 		    offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR);
    605 	}
    606 
    607 	return pa;
    608 }
    609 
    610 static int
    611 hyperfb_putcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm)
    612 {
    613 	u_char *r, *g, *b;
    614 	u_int index = cm->index;
    615 	u_int count = cm->count;
    616 	int i, error;
    617 	u_char rbuf[256], gbuf[256], bbuf[256];
    618 
    619 	if (cm->index >= 256 || cm->count > 256 ||
    620 	    (cm->index + cm->count) > 256)
    621 		return EINVAL;
    622 	error = copyin(cm->red, &rbuf[index], count);
    623 	if (error)
    624 		return error;
    625 	error = copyin(cm->green, &gbuf[index], count);
    626 	if (error)
    627 		return error;
    628 	error = copyin(cm->blue, &bbuf[index], count);
    629 	if (error)
    630 		return error;
    631 
    632 	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
    633 	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
    634 	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
    635 
    636 	r = &sc->sc_cmap_red[index];
    637 	g = &sc->sc_cmap_green[index];
    638 	b = &sc->sc_cmap_blue[index];
    639 
    640 	for (i = 0; i < count; i++) {
    641 		hyperfb_putpalreg(sc, index, *r, *g, *b);
    642 		index++;
    643 		r++, g++, b++;
    644 	}
    645 	return 0;
    646 }
    647 
    648 static int
    649 hyperfb_getcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm)
    650 {
    651 	u_int index = cm->index;
    652 	u_int count = cm->count;
    653 	int error;
    654 
    655 	if (index >= 255 || count > 256 || index + count > 256)
    656 		return EINVAL;
    657 
    658 	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
    659 	if (error)
    660 		return error;
    661 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
    662 	if (error)
    663 		return error;
    664 	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
    665 	if (error)
    666 		return error;
    667 
    668 	return 0;
    669 }
    670 
    671 static void
    672 hyperfb_restore_palette(struct hyperfb_softc *sc)
    673 {
    674 	uint8_t cmap[768];
    675 	int i, j;
    676 
    677 	j = 0;
    678 	rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap));
    679 	for (i = 0; i < 256; i++) {
    680 		sc->sc_cmap_red[i] = cmap[j];
    681 		sc->sc_cmap_green[i] = cmap[j + 1];
    682 		sc->sc_cmap_blue[i] = cmap[j + 2];
    683 		hyperfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
    684 		j += 3;
    685 	}
    686 }
    687 
    688 static int
    689 hyperfb_putpalreg(struct hyperfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
    690     uint8_t b)
    691 {
    692 
    693 	mutex_enter(&sc->sc_hwlock);
    694 	hyperfb_wait(sc);
    695 	hyperfb_write4(sc, NGLE_REG_10, 0xbbe0f000);
    696 	hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
    697 	hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
    698 
    699 	hyperfb_wait(sc);
    700 	hyperfb_write4(sc, NGLE_REG_3, 0x400 | (idx << 2));
    701 	hyperfb_write4(sc, NGLE_REG_4, (r << 16) | (g << 8) | b);
    702 
    703 	hyperfb_write4(sc, NGLE_REG_2, 0x400);
    704 	hyperfb_write4(sc, NGLE_REG_38, 0x82000100);
    705 	hyperfb_setup_fb(sc);
    706 	mutex_exit(&sc->sc_hwlock);
    707 	return 0;
    708 }
    709 
    710 void
    711 hyperfb_setup(struct hyperfb_softc *sc)
    712 {
    713 	int i;
    714 	uint32_t reg;
    715 
    716 	sc->sc_hwmode = HW_FB;
    717 	sc->sc_hot_x = 0;
    718 	sc->sc_hot_y = 0;
    719 	sc->sc_enabled = 0;
    720 	sc->sc_video_on = 1;
    721 
    722 #if 0
    723 	sc->sc_rect_colour = 0xf0000000;
    724 	sc->sc_rect_height = 0;
    725 #endif
    726 
    727 	/* set Bt458 read mask register to all planes */
    728 	/* XXX I'm not sure HCRX even has one of these */
    729 	hyperfb_wait(sc);
    730 	ngle_bt458_write(sc, 0x08, 0x04);
    731 	ngle_bt458_write(sc, 0x0a, 0xff);
    732 
    733 	reg = hyperfb_read4(sc, NGLE_REG_32);
    734 	DPRINTF("planereg %08x\n", reg);
    735 	hyperfb_write4(sc, NGLE_REG_32, 0xffff0000);
    736 
    737 	hyperfb_setup_fb(sc);
    738 
    739 	/* attr. planes */
    740 	hyperfb_wait(sc);
    741 	hyperfb_write4(sc, NGLE_REG_11, 0x2ea0d000);
    742 	hyperfb_write4(sc, NGLE_REG_14, 0x23000302);
    743 	hyperfb_write4(sc, NGLE_REG_12, NGLE_BUFF1_CMAP0);
    744 	hyperfb_write4(sc, NGLE_REG_8, 0xffffffff);
    745 
    746 	hyperfb_wait(sc);
    747 	hyperfb_write4(sc, NGLE_REG_6, 0x00000000);
    748 	hyperfb_write4(sc, NGLE_REG_9,
    749 	    (sc->sc_width << 16) | sc->sc_height);
    750 	/*
    751 	 * blit into offscreen memory to force flush previous - apparently
    752 	 * some chips have a bug this works around
    753 	 */
    754 	hyperfb_write4(sc, NGLE_REG_6, 0x05000000);
    755 	hyperfb_write4(sc, NGLE_REG_9, 0x00040001);
    756 
    757 	hyperfb_wait(sc);
    758 	hyperfb_write4(sc, NGLE_REG_12, 0x00000000);
    759 
    760 	hyperfb_setup_fb(sc);
    761 
    762 	/* make sure video output is enabled */
    763 	hyperfb_wait(sc);
    764 	hyperfb_write4(sc, NGLE_REG_33,
    765 	    hyperfb_read4(sc, NGLE_REG_33) | 0x0a000000);
    766 
    767 	/* hyperbowl */
    768 	hyperfb_wait(sc);
    769 	if(sc->sc_24bit) {
    770 		/* write must happen twice because hw bug */
    771 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE);
    772 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE);
    773 		hyperfb_write4(sc, NGLE_REG_39, HYPERBOWL_MODE2_8_24);
    774 		hyperfb_write4(sc, NGLE_REG_42, 0x014c0148); /* Set lut 0 to be the direct color */
    775 		hyperfb_write4(sc, NGLE_REG_43, 0x404c4048);
    776 		hyperfb_write4(sc, NGLE_REG_44, 0x034c0348);
    777 		hyperfb_write4(sc, NGLE_REG_45, 0x444c4448);
    778 	} else {
    779 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES);
    780 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES);
    781 
    782 		hyperfb_write4(sc, NGLE_REG_42, 0);
    783 		hyperfb_write4(sc, NGLE_REG_43, 0);
    784 		hyperfb_write4(sc, NGLE_REG_44, 0);
    785 		hyperfb_write4(sc, NGLE_REG_45, 0);
    786 	}
    787 	/* cursor mask */
    788 	hyperfb_wait(sc);
    789 	hyperfb_write4(sc, NGLE_REG_30, 0);
    790 	for (i = 0; i < 64; i++) {
    791 		hyperfb_write4(sc, NGLE_REG_31, 0xffffffff);
    792 		hyperfb_write4(sc, NGLE_REG_31, 0xffffffff);
    793 	}
    794 
    795 	/* cursor image */
    796 	hyperfb_wait(sc);
    797 	hyperfb_write4(sc, NGLE_REG_30, 0x80);
    798 	for (i = 0; i < 64; i++) {
    799 		hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00);
    800 		hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00);
    801 	}
    802 
    803 	/* colour map - doesn't work yet*/
    804 	hyperfb_wait(sc);
    805 	hyperfb_write4(sc, NGLE_REG_10, 0xBBE0F000);
    806 	hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
    807 	hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
    808 	hyperfb_wait(sc);
    809 	hyperfb_write4(sc, NGLE_REG_3, 0);
    810 	hyperfb_write4(sc, NGLE_REG_4, 0);
    811 	hyperfb_write4(sc, NGLE_REG_4, 0);
    812 	hyperfb_write4(sc, NGLE_REG_4, 0x000000ff);	/* BG */
    813 	hyperfb_write4(sc, NGLE_REG_4, 0x00ff0000);	/* FG */
    814 	hyperfb_wait(sc);
    815 	hyperfb_write4(sc, NGLE_REG_2, 0);
    816 	hyperfb_write4(sc, NGLE_REG_1, 0x80008004);
    817 	hyperfb_setup_fb(sc);
    818 
    819 	//hyperfb_write4(sc, NGLE_REG_29, 0x80200020);
    820 
    821 	//gftfb_move_cursor(sc, 100, 100);
    822 
    823 }
    824 
    825 static void
    826 hyperfb_set_video(struct hyperfb_softc *sc, int on)
    827 {
    828 	uint32_t reg;
    829 
    830 	if (sc->sc_video_on == on)
    831 		return;
    832 
    833 	sc->sc_video_on = on;
    834 
    835 	hyperfb_wait(sc);
    836 	reg = hyperfb_read4(sc, NGLE_REG_33);
    837 
    838 	if (on) {
    839 		hyperfb_write4(sc, NGLE_REG_33, reg | 0x0a000000);
    840 	} else {
    841 		hyperfb_write4(sc, NGLE_REG_33, reg & ~0x0a000000);
    842 	}
    843 }
    844