xref: /netbsd-src/sys/arch/hppa/dev/hyperfb.c (revision cf4b16e0a3ab626b5e49bb54759c1427fb1aaaf7)
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