xref: /netbsd-src/sys/arch/hppa/dev/hyperfb.c (revision aee609b2c67b98b07314e90060c2fd8f2071530e)
1 /*	$NetBSD: hyperfb.c,v 1.5 2024/07/24 08:34:03 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  * tested on a HCRX24Z in a C360 only so far
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: hyperfb.c,v 1.5 2024/07/24 08:34:03 macallan Exp $");
36 
37 #include "opt_cputype.h"
38 #include "opt_hyperfb.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 
44 #include <sys/bus.h>
45 #include <machine/cpu.h>
46 #include <machine/iomod.h>
47 #include <machine/autoconf.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 #include <dev/wscons/wsdisplay_vconsvar.h>
54 #include <dev/wscons/wsdisplay_glyphcachevar.h>
55 
56 #include <dev/ic/stireg.h>
57 #include <dev/ic/stivar.h>
58 
59 #include <hppa/dev/cpudevs.h>
60 #include <hppa/hppa/machdep.h>
61 
62 #ifdef HYPERFB_DEBUG
63 #define	DPRINTF printf
64 #else
65 #define DPRINTF if (0) printf
66 #endif
67 
68 #define	STI_ROMSIZE	(sizeof(struct sti_dd) * 4)
69 
70 #define HCRX_FBOFFSET	0x01000000
71 #define HCRX_FBLEN	0x01000000
72 #define HCRX_REGOFFSET	0x00100000
73 #define HCRX_REGLEN	0x00280000
74 
75 #define HCRX_CONFIG_24BIT	0x100
76 
77 int hyperfb_match(device_t, cfdata_t, void *);
78 void hyperfb_attach(device_t, device_t, void *);
79 
80 struct	hyperfb_softc {
81 	device_t		sc_dev;
82 	bus_space_tag_t		sc_iot;
83 	bus_addr_t		sc_base;
84 	bus_space_handle_t	sc_hfb, sc_hreg;
85 	void 			*sc_fb;
86 
87 	int sc_width, sc_height;
88 	int sc_locked, sc_is_console, sc_24bit;
89 	struct vcons_screen sc_console_screen;
90 	struct wsscreen_descr sc_defaultscreen_descr;
91 	const struct wsscreen_descr *sc_screens[1];
92 	struct wsscreen_list sc_screenlist;
93 	struct vcons_data vd;
94 	int sc_mode;
95 	void (*sc_putchar)(void *, int, int, u_int, long);
96 	u_char sc_cmap_red[256];
97 	u_char sc_cmap_green[256];
98 	u_char sc_cmap_blue[256];
99 	kmutex_t sc_hwlock;
100 	uint32_t sc_hwmode;
101 #define HW_FB	0
102 #define HW_FILL	1
103 #define HW_BLIT	2
104 	/* cursor stuff */
105 	int sc_cursor_x, sc_cursor_y;
106 	int sc_hot_x, sc_hot_y, sc_enabled;
107 	int sc_video_on;
108 	glyphcache sc_gc;
109 };
110 
111 extern struct cfdriver hyperfb_cd;
112 
113 CFATTACH_DECL_NEW(hyperfb, sizeof(struct hyperfb_softc), hyperfb_match,
114     hyperfb_attach, NULL, NULL);
115 
116 static inline void  hyperfb_setup_fb(struct hyperfb_softc *);
117 static inline void  hyperfb_setup_fb24(struct hyperfb_softc *);
118 static void 	hyperfb_init_screen(void *, struct vcons_screen *,
119 			    int, long *);
120 static int	hyperfb_ioctl(void *, void *, u_long, void *, int,
121 			     struct lwp *);
122 static paddr_t	hyperfb_mmap(void *, void *, off_t, int);
123 
124 static int	hyperfb_putcmap(struct hyperfb_softc *, struct wsdisplay_cmap *);
125 static int 	hyperfb_getcmap(struct hyperfb_softc *, struct wsdisplay_cmap *);
126 static void	hyperfb_restore_palette(struct hyperfb_softc *);
127 static int 	hyperfb_putpalreg(struct hyperfb_softc *, uint8_t, uint8_t,
128 			    uint8_t, uint8_t);
129 void 	hyperfb_setup(struct hyperfb_softc *);
130 static void	hyperfb_set_video(struct hyperfb_softc *, int);
131 
132 static void	hyperfb_rectfill(struct hyperfb_softc *, int, int, int, int,
133 			    uint32_t);
134 static void	hyperfb_bitblt(void *, int, int, int, int, int,
135 			    int, int);
136 
137 static void	hyperfb_cursor(void *, int, int, int);
138 static void	hyperfb_putchar(void *, int, int, u_int, long);
139 static void	hyperfb_copycols(void *, int, int, int, int);
140 static void	hyperfb_erasecols(void *, int, int, int, long);
141 static void	hyperfb_copyrows(void *, int, int, int);
142 static void	hyperfb_eraserows(void *, int, int, long);
143 
144 static void	hyperfb_move_cursor(struct hyperfb_softc *, int, int);
145 static int	hyperfb_do_cursor(struct hyperfb_softc *, struct wsdisplay_cursor *);
146 
147 static inline void hyperfb_wait_fifo(struct hyperfb_softc *, uint32_t);
148 
149 #define	ngle_bt458_write(sc, r, v) \
150 	hyperfb_write4(sc, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
151 
152 struct wsdisplay_accessops hyperfb_accessops = {
153 	hyperfb_ioctl,
154 	hyperfb_mmap,
155 	NULL,	/* alloc_screen */
156 	NULL,	/* free_screen */
157 	NULL,	/* show_screen */
158 	NULL, 	/* load_font */
159 	NULL,	/* pollc */
160 	NULL	/* scroll */
161 };
162 
163 static inline uint32_t
164 hyperfb_read4(struct hyperfb_softc *sc, uint32_t offset)
165 {
166 	return bus_space_read_4(sc->sc_iot, sc->sc_hreg, offset);
167 }
168 
169 static inline uint8_t
170 hyperfb_read1(struct hyperfb_softc *sc, uint32_t offset)
171 {
172 	return bus_space_read_1(sc->sc_iot, sc->sc_hreg, offset);
173 }
174 
175 static inline void
176 hyperfb_write4(struct hyperfb_softc *sc, uint32_t offset, uint32_t val)
177 {
178 	bus_space_write_4(sc->sc_iot, sc->sc_hreg, offset, val);
179 }
180 
181 static inline void
182 hyperfb_write1(struct hyperfb_softc *sc, uint32_t offset, uint8_t val)
183 {
184 	bus_space_write_1(sc->sc_iot, sc->sc_hreg, offset, val);
185 }
186 
187 static inline void
188 hyperfb_wait(struct hyperfb_softc *sc)
189 {
190 	uint8_t stat;
191 
192 	do {
193 		stat = hyperfb_read1(sc, NGLE_REG_15b0);
194 		if (stat == 0)
195 			stat = hyperfb_read1(sc, NGLE_REG_15b0);
196 	} while (stat != 0);
197 }
198 
199 static inline void
200 hyperfb_wait_fifo(struct hyperfb_softc *sc, uint32_t slots)
201 {
202 	uint32_t reg;
203 
204 	do {
205 		reg = hyperfb_read4(sc, NGLE_REG_34);
206 	} while (reg < slots);
207 }
208 
209 static inline void
210 hyperfb_setup_fb(struct hyperfb_softc *sc)
211 {
212 
213 	hyperfb_wait(sc);
214 	if ((sc->sc_mode != WSDISPLAYIO_MODE_EMUL) && sc->sc_24bit) {
215 		hyperfb_write4(sc, NGLE_REG_10, 0xBBA0A000);	/* 24bit */
216 		hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
217 	} else
218 		hyperfb_write4(sc, NGLE_REG_10, 0x13602000);	/* 8bit */
219 	hyperfb_write4(sc, NGLE_REG_14, 0x83000300);
220 	hyperfb_wait(sc);
221 	hyperfb_write1(sc, NGLE_REG_16b1, 1);
222 	sc->sc_hwmode = HW_FB;
223 }
224 
225 static inline void
226 hyperfb_setup_fb24(struct hyperfb_softc *sc)
227 {
228 
229 	hyperfb_wait(sc);
230 	hyperfb_write4(sc, NGLE_REG_10, 0xBBA0A000);	/* 24bit */
231 	hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
232 	hyperfb_write4(sc, NGLE_REG_14, 0x83000300);
233 	//IBOvals(RopSrc,0,BitmapExtent08,0,DataDynamic,MaskDynamic,0,0)
234 	hyperfb_wait(sc);
235 	hyperfb_write1(sc, NGLE_REG_16b1, 1);
236 	sc->sc_hwmode = HW_FB;
237 }
238 
239 int
240 hyperfb_match(device_t parent, cfdata_t cf, void *aux)
241 {
242 	struct confargs *ca = aux;
243 	bus_space_handle_t romh;
244 	paddr_t rom;
245 	uint32_t id = 0;
246 	u_char devtype;
247 	int rv = 0, romunmapped = 0;
248 
249 	if (ca->ca_type.iodc_type != HPPA_TYPE_FIO)
250 		return 0;
251 
252 	/* these need further checking for the graphics id */
253 	if (ca->ca_type.iodc_sv_model != HPPA_FIO_GSGC &&
254 	    ca->ca_type.iodc_sv_model != HPPA_FIO_SGC)
255 		return 0;
256 
257 	if (ca->ca_naddrs > 0)
258 		rom = ca->ca_addrs[0].addr;
259 	else
260 		rom = ca->ca_hpa;
261 
262 	DPRINTF("%s: hpa=%x, rom=%x\n", __func__, (uint)ca->ca_hpa,
263 	    (uint)rom);
264 
265 	/* if it does not map, probably part of the lasi space */
266 	if (bus_space_map(ca->ca_iot, rom, STI_ROMSIZE, 0, &romh)) {
267 		DPRINTF("%s: can't map rom space (%d)\n", __func__, rv);
268 
269 		if ((rom & HPPA_IOBEGIN) == HPPA_IOBEGIN) {
270 			romh = rom;
271 			romunmapped++;
272 		} else {
273 			/* in this case nobody has no freaking idea */
274 			return 0;
275 		}
276 	}
277 
278 	devtype = bus_space_read_1(ca->ca_iot, romh, 3);
279 	DPRINTF("%s: devtype=%d\n", __func__, devtype);
280 	rv = 1;
281 	switch (devtype) {
282 	case STI_DEVTYPE4:
283 		id = bus_space_read_4(ca->ca_iot, romh, STI_DEV4_DD_GRID);
284 		break;
285 	case STI_DEVTYPE1:
286 		id = (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
287 		    +  3) << 24) |
288 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
289 		    +  7) << 16) |
290 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
291 		    + 11) <<  8) |
292 		    (bus_space_read_1(ca->ca_iot, romh, STI_DEV1_DD_GRID
293 		    + 15));
294 		break;
295 	default:
296 		DPRINTF("%s: unknown type (%x)\n", __func__, devtype);
297 		rv = 0;
298 	}
299 
300 	if (id == STI_DD_HCRX)
301 		rv = 100;	/* beat out sti */
302 
303 	ca->ca_addrs[ca->ca_naddrs].addr = rom;
304 	ca->ca_addrs[ca->ca_naddrs].size = sti_rom_size(ca->ca_iot, romh);
305 	ca->ca_naddrs++;
306 
307 	if (!romunmapped)
308 		bus_space_unmap(ca->ca_iot, romh, STI_ROMSIZE);
309 	return rv;
310 }
311 
312 void
313 hyperfb_attach(device_t parent, device_t self, void *aux)
314 {
315 	struct hyperfb_softc *sc = device_private(self);
316 	struct confargs *ca = aux;
317 	struct rasops_info *ri;
318 	struct wsemuldisplaydev_attach_args aa;
319 	bus_space_handle_t hrom;
320 	hppa_hpa_t consaddr;
321 	long defattr;
322 	int pagezero_cookie;
323 	paddr_t rom;
324 	uint32_t config;
325 
326 	pagezero_cookie = hppa_pagezero_map();
327 	consaddr = (hppa_hpa_t)PAGE0->mem_cons.pz_hpa;
328 	hppa_pagezero_unmap(pagezero_cookie);
329 
330 	sc->sc_dev = self;
331 	sc->sc_base = ca->ca_hpa;
332 	sc->sc_iot = ca->ca_iot;
333 	sc->sc_is_console =(ca->ca_hpa == consaddr);
334 	sc->sc_width = 1280;
335 	sc->sc_height = 1024;
336 
337 	/* we can *not* be interrupted when doing colour map accesses */
338 	mutex_init(&sc->sc_hwlock, MUTEX_DEFAULT, IPL_HIGH);
339 
340 	/* we stashed rom addr/len into the last slot during probe */
341 	rom = ca->ca_addrs[ca->ca_naddrs - 1].addr;
342 
343 	if (bus_space_map(sc->sc_iot,
344 	    sc->sc_base + HCRX_FBOFFSET, HCRX_FBLEN,
345 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE,
346 	    &sc->sc_hfb)) {
347 	    	aprint_error_dev(sc->sc_dev, "failed to map the framebuffer\n");
348 	    	return;
349 	}
350 	sc->sc_fb = bus_space_vaddr(sc->sc_iot, sc->sc_hfb);
351 
352 	if (bus_space_map(sc->sc_iot,
353 	    sc->sc_base + HCRX_REGOFFSET, HCRX_REGLEN, 0, &sc->sc_hreg)) {
354 	    	aprint_error_dev(sc->sc_dev, "failed to map registers\n");
355 	    	return;
356 	}
357 
358 	/*
359 	 * we really only need the first word so we can grab the config bits
360 	 * between the bytes
361 	 */
362 	if (bus_space_map(sc->sc_iot,
363 	    rom, 4, 0, &hrom)) {
364 	    	aprint_error_dev(sc->sc_dev, "failed to map ROM, assuming 8bit\n");
365 	    	config = 0;
366 	} else {
367 		/* alright, we got the ROM. now do the idle dance. */
368 		volatile uint32_t r = hyperfb_read4(sc, NGLE_REG_15);
369 		__USE(r);
370 		hyperfb_wait(sc);
371 		config = bus_space_read_4(sc->sc_iot, hrom, 0);
372 		bus_space_unmap(sc->sc_iot, hrom, 4);
373 	}
374 	sc->sc_24bit = ((config & HCRX_CONFIG_24BIT) != 0);
375 
376 	printf(" %s\n", sc->sc_24bit ? "HCRX24" : "HCRX");
377 #ifdef HP7300LC_CPU
378 	/*
379 	 * PCXL2: enable accel I/O for this space, see PCX-L2 ERS "ACCEL_IO".
380 	 * "pcxl2_ers.{ps,pdf}", (section / chapter . rel. page / abs. page)
381 	 * 8.7.4 / 8-12 / 92, 11.3.14 / 11-14 / 122 and 14.8 / 14-5 / 203.
382 	 */
383 	if (hppa_cpu_info->hci_cputype == hpcxl2
384 	    && ca->ca_hpa >= PCXL2_ACCEL_IO_START
385 	    && ca->ca_hpa <= PCXL2_ACCEL_IO_END)
386 		eaio_l2(PCXL2_ACCEL_IO_ADDR2MASK(ca->ca_hpa));
387 #endif /* HP7300LC_CPU */
388 
389 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
390 	sc->sc_locked = 0;
391 
392 	hyperfb_setup(sc);
393 	hyperfb_setup_fb(sc);
394 
395 	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
396 		"default",
397 		0, 0,
398 		NULL,
399 		8, 16,
400 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
401 		      WSSCREEN_RESIZE,
402 		NULL
403 	};
404 
405 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
406 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
407 
408 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
409 	    &hyperfb_accessops);
410 	sc->vd.init_screen = hyperfb_init_screen;
411 	sc->vd.show_screen_cookie = &sc->sc_gc;
412 	sc->vd.show_screen_cb = glyphcache_adapt;
413 
414 	ri = &sc->sc_console_screen.scr_ri;
415 
416 	//sc->sc_gc.gc_bitblt = hyperfb_bitblt;
417 	//sc->sc_gc.gc_blitcookie = sc;
418 	//sc->sc_gc.gc_rop = RopSrc;
419 
420 	if (sc->sc_is_console) {
421 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
422 		    &defattr);
423 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
424 
425 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
426 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
427 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
428 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
429 
430 #if 0
431 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
432 				sc->sc_scr.fbheight - sc->sc_height - 5,
433 				sc->sc_scr.fbwidth,
434 				ri->ri_font->fontwidth,
435 				ri->ri_font->fontheight,
436 				defattr);
437 #endif
438 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
439 		    defattr);
440 
441 		hyperfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
442 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
443 
444 		vcons_replay_msgbuf(&sc->sc_console_screen);
445 	} else {
446 		/*
447 		 * since we're not the console we can postpone the rest
448 		 * until someone actually allocates a screen for us
449 		 */
450 		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
451 			/* do some minimal setup to avoid weirdnesses later */
452 			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
453 			    &defattr);
454 		} else
455 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
456 
457 #if 0
458 		glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
459 				sc->sc_scr.fbheight - sc->sc_height - 5,
460 				sc->sc_scr.fbwidth,
461 				ri->ri_font->fontwidth,
462 				ri->ri_font->fontheight,
463 				defattr);
464 #endif
465 	}
466 
467 	hyperfb_restore_palette(sc);
468 
469 	/* no suspend/resume support yet */
470 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
471 		aprint_error_dev(sc->sc_dev,
472 		    "couldn't establish power handler\n");
473 
474 	aa.console = sc->sc_is_console;
475 	aa.scrdata = &sc->sc_screenlist;
476 	aa.accessops = &hyperfb_accessops;
477 	aa.accesscookie = &sc->vd;
478 
479 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
480 
481 	hyperfb_setup_fb(sc);
482 
483 }
484 
485 static void
486 hyperfb_init_screen(void *cookie, struct vcons_screen *scr,
487     int existing, long *defattr)
488 {
489 	struct hyperfb_softc *sc = cookie;
490 	struct rasops_info *ri = &scr->scr_ri;
491 
492 	ri->ri_depth = 8;
493 	ri->ri_width = 1280;
494 	ri->ri_height = 1024;
495 	ri->ri_stride = 2048;
496 	ri->ri_flg = RI_CENTER | RI_8BIT_IS_RGB /*|
497 		     RI_ENABLE_ALPHA | RI_PREFER_ALPHA*/;
498 
499 	ri->ri_bits = (void *)sc->sc_fb;
500 	rasops_init(ri, 0, 0);
501 	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
502 		      WSSCREEN_RESIZE;
503 	scr->scr_flags |= VCONS_LOADFONT;
504 
505 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
506 		    sc->sc_width / ri->ri_font->fontwidth);
507 
508 	ri->ri_hw = scr;
509 
510 	sc->sc_putchar = ri->ri_ops.putchar;
511 	ri->ri_ops.copyrows = hyperfb_copyrows;
512 	ri->ri_ops.copycols = hyperfb_copycols;
513 	ri->ri_ops.eraserows = hyperfb_eraserows;
514 	ri->ri_ops.erasecols = hyperfb_erasecols;
515 	ri->ri_ops.cursor = hyperfb_cursor;
516 	ri->ri_ops.putchar = hyperfb_putchar;
517 }
518 
519 static int
520 hyperfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
521 	struct lwp *l)
522 {
523 	struct vcons_data *vd = v;
524 	struct hyperfb_softc *sc = vd->cookie;
525 	struct wsdisplay_fbinfo *wdf;
526 	struct vcons_screen *ms = vd->active;
527 
528 	switch (cmd) {
529 	case WSDISPLAYIO_GTYPE:
530 		*(u_int *)data = WSDISPLAY_TYPE_STI;
531 		return 0;
532 
533 	case WSDISPLAYIO_GINFO:
534 		if (ms == NULL)
535 			return ENODEV;
536 		wdf = (void *)data;
537 		wdf->height = ms->scr_ri.ri_height;
538 		wdf->width = sc->sc_24bit ? ms->scr_ri.ri_width << 2 : ms->scr_ri.ri_width;
539 		wdf->depth = ms->scr_ri.ri_depth;
540 		wdf->cmsize = 256;
541 		return 0;
542 
543 	case WSDISPLAYIO_GETCMAP:
544 		return hyperfb_getcmap(sc,
545 		    (struct wsdisplay_cmap *)data);
546 
547 	case WSDISPLAYIO_PUTCMAP:
548 		return hyperfb_putcmap(sc,
549 		    (struct wsdisplay_cmap *)data);
550 	case WSDISPLAYIO_LINEBYTES:
551 		*(u_int *)data = sc->sc_24bit ? 8192 : 2048;
552 		return 0;
553 
554 	case WSDISPLAYIO_SMODE: {
555 		int new_mode = *(int*)data;
556 		if (new_mode != sc->sc_mode) {
557 			sc->sc_mode = new_mode;
558 			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
559 				hyperfb_setup(sc);
560 				hyperfb_restore_palette(sc);
561 #if 0
562 				glyphcache_wipe(&sc->sc_gc);
563 #endif
564 				hyperfb_rectfill(sc, 0, 0, sc->sc_width,
565 				    sc->sc_height, ms->scr_ri.ri_devcmap[
566 				    (ms->scr_defattr >> 16) & 0xff]);
567 				vcons_redraw_screen(ms);
568 				hyperfb_set_video(sc, 1);
569 			} else {
570 				hyperfb_setup(sc);
571 				hyperfb_rectfill(sc, 0, 0, sc->sc_width,
572 				    sc->sc_height, 0xff);
573 				hyperfb_setup_fb24(sc);
574 			}
575 		}
576 		}
577 		return 0;
578 
579 	case WSDISPLAYIO_GET_FBINFO:
580 		{
581 			struct wsdisplayio_fbinfo *fbi = data;
582 			int ret;
583 
584 			ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
585 			fbi->fbi_fbsize = sc->sc_height * 2048;
586 			if (sc->sc_24bit) {
587 				fbi->fbi_stride = 8192;
588 				fbi->fbi_bitsperpixel = 32;
589 				fbi->fbi_pixeltype = WSFB_RGB;
590 				fbi->fbi_subtype.fbi_rgbmasks.red_offset = 16;
591 				fbi->fbi_subtype.fbi_rgbmasks.red_size = 8;
592 				fbi->fbi_subtype.fbi_rgbmasks.green_offset = 8;
593 				fbi->fbi_subtype.fbi_rgbmasks.green_size = 8;
594 				fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 0;
595 				fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8;
596 				fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0;
597 				fbi->fbi_fbsize = sc->sc_height * 8192;
598 			}
599 			return ret;
600 		}
601 
602 	case WSDISPLAYIO_GCURPOS:
603 		{
604 			struct wsdisplay_curpos *cp = (void *)data;
605 
606 			cp->x = sc->sc_cursor_x;
607 			cp->y = sc->sc_cursor_y;
608 		}
609 		return 0;
610 
611 	case WSDISPLAYIO_SCURPOS:
612 		{
613 			struct wsdisplay_curpos *cp = (void *)data;
614 
615 			hyperfb_move_cursor(sc, cp->x, cp->y);
616 		}
617 		return 0;
618 
619 	case WSDISPLAYIO_GCURMAX:
620 		{
621 			struct wsdisplay_curpos *cp = (void *)data;
622 
623 			cp->x = 64;
624 			cp->y = 64;
625 		}
626 		return 0;
627 
628 	case WSDISPLAYIO_SCURSOR:
629 		{
630 			struct wsdisplay_cursor *cursor = (void *)data;
631 
632 			return hyperfb_do_cursor(sc, cursor);
633 		}
634 
635 	case WSDISPLAYIO_SVIDEO:
636 		hyperfb_set_video(sc, *(int *)data);
637 		return 0;
638 	case WSDISPLAYIO_GVIDEO:
639 		return sc->sc_video_on ?
640 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
641 	}
642 	return EPASSTHROUGH;
643 }
644 
645 static paddr_t
646 hyperfb_mmap(void *v, void *vs, off_t offset, int prot)
647 {
648 	struct vcons_data *vd = v;
649 	struct hyperfb_softc *sc = vd->cookie;
650 	paddr_t pa = -1;
651 
652 
653 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)
654 		return -1;
655 
656 	if (offset >= 0 || offset < 2048 * 1024) {
657 		/* framebuffer */
658 		pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_FBOFFSET, offset,
659 		    prot, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
660 	} else if (offset >= 0x80000000 && offset < 0x8040000) {
661 		/* blitter registers etc. */
662 		pa = bus_space_mmap(sc->sc_iot, sc->sc_base + HCRX_REGOFFSET,
663 		    offset - 0x80000000, prot, BUS_SPACE_MAP_LINEAR);
664 	}
665 
666 	return pa;
667 }
668 
669 static int
670 hyperfb_putcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm)
671 {
672 	u_char *r, *g, *b;
673 	u_int index = cm->index;
674 	u_int count = cm->count;
675 	int i, error;
676 	u_char rbuf[256], gbuf[256], bbuf[256];
677 
678 	if (cm->index >= 256 || cm->count > 256 ||
679 	    (cm->index + cm->count) > 256)
680 		return EINVAL;
681 	error = copyin(cm->red, &rbuf[index], count);
682 	if (error)
683 		return error;
684 	error = copyin(cm->green, &gbuf[index], count);
685 	if (error)
686 		return error;
687 	error = copyin(cm->blue, &bbuf[index], count);
688 	if (error)
689 		return error;
690 
691 	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
692 	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
693 	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
694 
695 	r = &sc->sc_cmap_red[index];
696 	g = &sc->sc_cmap_green[index];
697 	b = &sc->sc_cmap_blue[index];
698 
699 	for (i = 0; i < count; i++) {
700 		hyperfb_putpalreg(sc, index, *r, *g, *b);
701 		index++;
702 		r++, g++, b++;
703 	}
704 	return 0;
705 }
706 
707 static int
708 hyperfb_getcmap(struct hyperfb_softc *sc, struct wsdisplay_cmap *cm)
709 {
710 	u_int index = cm->index;
711 	u_int count = cm->count;
712 	int error;
713 
714 	if (index >= 255 || count > 256 || index + count > 256)
715 		return EINVAL;
716 
717 	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
718 	if (error)
719 		return error;
720 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
721 	if (error)
722 		return error;
723 	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
724 	if (error)
725 		return error;
726 
727 	return 0;
728 }
729 
730 static void
731 hyperfb_restore_palette(struct hyperfb_softc *sc)
732 {
733 	uint8_t cmap[768];
734 	int i, j;
735 
736 	j = 0;
737 	rasops_get_cmap(&sc->sc_console_screen.scr_ri, cmap, sizeof(cmap));
738 	for (i = 0; i < 256; i++) {
739 		sc->sc_cmap_red[i] = cmap[j];
740 		sc->sc_cmap_green[i] = cmap[j + 1];
741 		sc->sc_cmap_blue[i] = cmap[j + 2];
742 		hyperfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
743 		j += 3;
744 	}
745 }
746 
747 static int
748 hyperfb_putpalreg(struct hyperfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
749     uint8_t b)
750 {
751 
752 	mutex_enter(&sc->sc_hwlock);
753 	hyperfb_wait(sc);
754 	hyperfb_write4(sc, NGLE_REG_10, 0xbbe0f000);
755 	hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
756 	hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
757 
758 	hyperfb_wait(sc);
759 	hyperfb_write4(sc, NGLE_REG_3, 0x400 | (idx << 2));
760 	hyperfb_write4(sc, NGLE_REG_4, (r << 16) | (g << 8) | b);
761 
762 	hyperfb_write4(sc, NGLE_REG_2, 0x400);
763 	hyperfb_write4(sc, NGLE_REG_38, 0x82000100);
764 	hyperfb_setup_fb(sc);
765 	mutex_exit(&sc->sc_hwlock);
766 	return 0;
767 }
768 
769 void
770 hyperfb_setup(struct hyperfb_softc *sc)
771 {
772 	int i;
773 	uint32_t reg;
774 
775 	sc->sc_hwmode = HW_FB;
776 	sc->sc_hot_x = 0;
777 	sc->sc_hot_y = 0;
778 	sc->sc_enabled = 0;
779 	sc->sc_video_on = 1;
780 
781 	/* set Bt458 read mask register to all planes */
782 	/* XXX I'm not sure HCRX even has one of these */
783 	hyperfb_wait(sc);
784 	ngle_bt458_write(sc, 0x08, 0x04);
785 	ngle_bt458_write(sc, 0x0a, 0xff);
786 
787 	reg = hyperfb_read4(sc, NGLE_REG_32);
788 	DPRINTF("planereg %08x\n", reg);
789 	hyperfb_write4(sc, NGLE_REG_32, 0xffffffff);
790 
791 	/* hyperbowl */
792 	hyperfb_wait(sc);
793 	if(sc->sc_24bit) {
794 		/* write must happen twice because hw bug */
795 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE);
796 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE);
797 		hyperfb_write4(sc, NGLE_REG_39, HYPERBOWL_MODE2_8_24);
798 		hyperfb_write4(sc, NGLE_REG_42, 0x014c0148); /* Set lut 0 to be the direct color */
799 		hyperfb_write4(sc, NGLE_REG_43, 0x404c4048);
800 		hyperfb_write4(sc, NGLE_REG_44, 0x034c0348);
801 		hyperfb_write4(sc, NGLE_REG_45, 0x444c4448);
802 	} else {
803 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES);
804 		hyperfb_write4(sc, NGLE_REG_40, HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES);
805 
806 		hyperfb_write4(sc, NGLE_REG_42, 0);
807 		hyperfb_write4(sc, NGLE_REG_43, 0);
808 		hyperfb_write4(sc, NGLE_REG_44, 0);
809 		hyperfb_write4(sc, NGLE_REG_45, 0x444c4048);
810 	}
811 
812 	/* attr. planes */
813 	hyperfb_wait(sc);
814 	hyperfb_write4(sc, NGLE_REG_11,
815 	    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINattr, 0));
816 	hyperfb_write4(sc, NGLE_REG_14,
817 	    IBOvals(RopSrc, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 1, 0));
818 	hyperfb_write4(sc, NGLE_REG_12, 0x04000F00/*NGLE_BUFF0_CMAP0*/);
819 	hyperfb_write4(sc, NGLE_REG_8, 0xffffffff);
820 
821 	hyperfb_wait(sc);
822 	hyperfb_write4(sc, NGLE_REG_6, 0x00000000);
823 	hyperfb_write4(sc, NGLE_REG_9,
824 	    (sc->sc_width << 16) | sc->sc_height);
825 	/*
826 	 * blit into offscreen memory to force flush previous - apparently
827 	 * some chips have a bug this works around
828 	 */
829 	hyperfb_wait(sc);
830 	hyperfb_write4(sc, NGLE_REG_6, 0x05000000);
831 	hyperfb_write4(sc, NGLE_REG_9, 0x00040001);
832 
833 	/*
834 	 * on 24bit-capable hardware we:
835 	 * - make overlay colour 255 transparent
836 	 * - blit the 24bit buffer all white
837 	 * - install a linear ramp in CMAP 0
838 	 */
839 	if(sc->sc_24bit) {
840 		/* overlay transparency */
841 		hyperfb_wait_fifo(sc, 7);
842 		hyperfb_write4(sc, NGLE_REG_11, 0x13a02000);
843 		hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
844 		hyperfb_write4(sc, NGLE_REG_3, 0x000017f0);
845 		hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
846 		hyperfb_write4(sc, NGLE_REG_22, 0xffffffff);
847 		hyperfb_write4(sc, NGLE_REG_23, 0x0);
848 
849 		hyperfb_wait(sc);
850 		hyperfb_write4(sc, NGLE_REG_12, 0x00000000);
851 
852 		/* clear 24bit buffer */
853 		hyperfb_wait(sc);
854 		/* plane mask */
855 		hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
856 		hyperfb_write4(sc, NGLE_REG_8, 0xffffffff);	/* transfer data */
857 		/* bitmap op */
858 		hyperfb_write4(sc, NGLE_REG_14,
859 		    IBOvals(RopSrc, 0, BitmapExtent32, 0, DataDynamic, MaskOtc, 0, 0));
860 		/* dst bitmap access */
861 		hyperfb_write4(sc, NGLE_REG_11,
862 		    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINapp0F8, 0));
863 		hyperfb_wait_fifo(sc, 3);
864 		hyperfb_write4(sc, NGLE_REG_35, 0x00ffffff);	/* fg colour */
865 		hyperfb_write4(sc, NGLE_REG_6, 0x00000000);	/* dst xy */
866 		hyperfb_write4(sc, NGLE_REG_9,
867 		    (sc->sc_width << 16) | sc->sc_height);
868 
869 		/* write a linear ramp into CMAP0 */
870 		hyperfb_wait(sc);
871 		hyperfb_write4(sc, NGLE_REG_10, 0xbbe0f000);
872 		hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
873 		hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
874 
875 		hyperfb_wait(sc);
876 		hyperfb_write4(sc, NGLE_REG_3, 0);
877 		for (i = 0; i < 256; i++) {
878 			hyperfb_wait(sc);
879 			hyperfb_write4(sc, NGLE_REG_4, (i << 16) | (i << 8) | i);
880 		}
881 		hyperfb_write4(sc, NGLE_REG_2, 0x0);
882 		hyperfb_write4(sc, NGLE_REG_38, LBC_ENABLE | LBC_TYPE_CMAP | 0x100);
883 		hyperfb_wait(sc);
884 	}
885 
886 	hyperfb_setup_fb(sc);
887 
888 	/* make sure video output is enabled */
889 	hyperfb_wait(sc);
890 	hyperfb_write4(sc, NGLE_REG_33,
891 	    hyperfb_read4(sc, NGLE_REG_33) | 0x0a000000);
892 
893 	/* cursor mask */
894 	hyperfb_wait(sc);
895 	hyperfb_write4(sc, NGLE_REG_30, 0);
896 	for (i = 0; i < 64; i++) {
897 		hyperfb_write4(sc, NGLE_REG_31, 0xffffffff);
898 		hyperfb_write4(sc, NGLE_REG_31, 0xffffffff);
899 	}
900 
901 	/* cursor image */
902 	hyperfb_wait(sc);
903 	hyperfb_write4(sc, NGLE_REG_30, 0x80);
904 	for (i = 0; i < 64; i++) {
905 		hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00);
906 		hyperfb_write4(sc, NGLE_REG_31, 0xff00ff00);
907 	}
908 
909 	/* colour map */
910 	hyperfb_wait(sc);
911 	hyperfb_write4(sc, NGLE_REG_10, 0xBBE0F000);
912 	hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
913 	hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
914 	hyperfb_wait(sc);
915 	hyperfb_write4(sc, NGLE_REG_3, 0);
916 	hyperfb_write4(sc, NGLE_REG_4, 0x000000ff);	/* BG */
917 	hyperfb_write4(sc, NGLE_REG_4, 0x00ff0000);	/* FG */
918 	hyperfb_wait(sc);
919 	hyperfb_write4(sc, NGLE_REG_2, 0);
920 	hyperfb_write4(sc, NGLE_REG_38, LBC_ENABLE | LBC_TYPE_CURSOR | 4);
921 	hyperfb_setup_fb(sc);
922 
923 	hyperfb_move_cursor(sc, 100, 100);
924 
925 }
926 
927 static void
928 hyperfb_set_video(struct hyperfb_softc *sc, int on)
929 {
930 	uint32_t reg;
931 
932 	if (sc->sc_video_on == on)
933 		return;
934 
935 	sc->sc_video_on = on;
936 
937 	hyperfb_wait(sc);
938 	reg = hyperfb_read4(sc, NGLE_REG_33);
939 
940 	if (on) {
941 		hyperfb_write4(sc, NGLE_REG_33, reg | HCRX_VIDEO_ENABLE);
942 	} else {
943 		hyperfb_write4(sc, NGLE_REG_33, reg & ~HCRX_VIDEO_ENABLE);
944 	}
945 }
946 
947 static void
948 hyperfb_rectfill(struct hyperfb_softc *sc, int x, int y, int wi, int he,
949 		      uint32_t bg)
950 {
951 	/*
952 	 * XXX
953 	 * HCRX has the same problem as VisEG drawing rectangles less than 32
954 	 * pixels wide, but here we don't seem to have any usable offscreen
955 	 * memory, at least not as long as we're using the overlay planes.
956 	 * As a workaround, fall back to memset()-based fills for rectangles
957 	 * less than 32 pixels wide
958 	 */
959 	if (wi < 32) {
960 		int i;
961 		uint8_t *ptr = (uint8_t *)sc->sc_fb + (y << 11) + x;
962 
963 		if (sc->sc_hwmode != HW_FB)
964 			hyperfb_setup_fb(sc);
965 
966 		for (i = 0; i < he; i++) {
967 			memset(ptr, bg, wi);
968 			ptr += 2048;
969 		}
970 		return;
971 	}
972 	if (sc->sc_hwmode != HW_FILL) {
973 		hyperfb_wait_fifo(sc, 4);
974 		/* transfer data */
975 		hyperfb_write4(sc, NGLE_REG_8, 0xffffffff);
976 		/* plane mask */
977 		hyperfb_write4(sc, NGLE_REG_13, 0xff);
978 		/* bitmap op */
979 		hyperfb_write4(sc, NGLE_REG_14,
980 		    IBOvals(RopSrc, 0, BitmapExtent08, 0, DataDynamic, MaskOtc, 0, 0));
981 		/* dst bitmap access */
982 		hyperfb_write4(sc, NGLE_REG_11,
983 		    BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, 0, BINovly, 0));
984 		sc->sc_hwmode = HW_FILL;
985 	}
986 	hyperfb_wait_fifo(sc, 3);
987 	hyperfb_write4(sc, NGLE_REG_35, bg);
988 	/* dst XY */
989 	hyperfb_write4(sc, NGLE_REG_6, (x << 16) | y);
990 	/* len XY start */
991 	hyperfb_write4(sc, NGLE_REG_9, (wi << 16) | he);
992 }
993 
994 static void
995 hyperfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi,
996 			    int he, int rop)
997 {
998 	struct hyperfb_softc *sc = cookie;
999 
1000 	if (sc->sc_hwmode != HW_BLIT) {
1001 		hyperfb_wait(sc);
1002 		hyperfb_write4(sc, NGLE_REG_10, 0x13a02000);
1003 		hyperfb_write4(sc, NGLE_REG_13, 0xff);
1004 		sc->sc_hwmode = HW_BLIT;
1005 	}
1006 	hyperfb_wait_fifo(sc, 4);
1007 	hyperfb_write4(sc, NGLE_REG_14, ((rop << 8) & 0xf00) | 0x23000000);
1008 	/* IBOvals(rop, 0, BitmapExtent08, 1, DataDynamic, MaskOtc, 0, 0) */
1009 	hyperfb_write4(sc, NGLE_REG_24, (xs << 16) | ys);
1010 	hyperfb_write4(sc, NGLE_REG_7, (wi << 16) | he);
1011 	hyperfb_write4(sc, NGLE_REG_25, (xd << 16) | yd);
1012 }
1013 
1014 static void
1015 hyperfb_nuke_cursor(struct rasops_info *ri)
1016 {
1017 	struct vcons_screen *scr = ri->ri_hw;
1018 	struct hyperfb_softc *sc = scr->scr_cookie;
1019 	int wi, he, x, y;
1020 
1021 	if (ri->ri_flg & RI_CURSOR) {
1022 		wi = ri->ri_font->fontwidth;
1023 		he = ri->ri_font->fontheight;
1024 		x = ri->ri_ccol * wi + ri->ri_xorigin;
1025 		y = ri->ri_crow * he + ri->ri_yorigin;
1026 		hyperfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1027 		ri->ri_flg &= ~RI_CURSOR;
1028 	}
1029 }
1030 
1031 static void
1032 hyperfb_cursor(void *cookie, int on, int row, int col)
1033 {
1034 	struct rasops_info *ri = cookie;
1035 	struct vcons_screen *scr = ri->ri_hw;
1036 	struct hyperfb_softc *sc = scr->scr_cookie;
1037 	int x, y, wi, he;
1038 
1039 	wi = ri->ri_font->fontwidth;
1040 	he = ri->ri_font->fontheight;
1041 
1042 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1043 		if (on) {
1044 			if (ri->ri_flg & RI_CURSOR) {
1045 				hyperfb_nuke_cursor(ri);
1046 			}
1047 			x = col * wi + ri->ri_xorigin;
1048 			y = row * he + ri->ri_yorigin;
1049 			hyperfb_bitblt(sc, x, y, x, y, wi, he, RopInv);
1050 			ri->ri_flg |= RI_CURSOR;
1051 		}
1052 		ri->ri_crow = row;
1053 		ri->ri_ccol = col;
1054 	} else
1055 	{
1056 		ri->ri_crow = row;
1057 		ri->ri_ccol = col;
1058 		ri->ri_flg &= ~RI_CURSOR;
1059 	}
1060 
1061 }
1062 
1063 static void
1064 hyperfb_putchar(void *cookie, int row, int col, u_int c, long attr)
1065 {
1066 	struct rasops_info *ri = cookie;
1067 	struct wsdisplay_font *font = PICK_FONT(ri, c);
1068 	struct vcons_screen *scr = ri->ri_hw;
1069 	struct hyperfb_softc *sc = scr->scr_cookie;
1070 	int x, y, wi, he/*, rv = GC_NOPE*/;
1071 	uint32_t bg;
1072 
1073 	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1074 		return;
1075 
1076 	if (!CHAR_IN_FONT(c, font))
1077 		return;
1078 
1079 	if (row == ri->ri_crow && col == ri->ri_ccol) {
1080 		ri->ri_flg &= ~RI_CURSOR;
1081 	}
1082 
1083 	wi = font->fontwidth;
1084 	he = font->fontheight;
1085 
1086 	x = ri->ri_xorigin + col * wi;
1087 	y = ri->ri_yorigin + row * he;
1088 
1089 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1090 
1091 	if (c == 0x20) {
1092 		hyperfb_rectfill(sc, x, y, wi, he, bg);
1093 		return;
1094 	}
1095 
1096 #if 0
1097 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1098 	if (rv == GC_OK)
1099 		return;
1100 #endif
1101 	if (sc->sc_hwmode != HW_FB) hyperfb_setup_fb(sc);
1102 	sc->sc_putchar(cookie, row, col, c, attr);
1103 #if 0
1104 	if (rv == GC_ADD)
1105 		glyphcache_add(&sc->sc_gc, c, x, y);
1106 #endif
1107 }
1108 
1109 static void
1110 hyperfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1111 {
1112 	struct rasops_info *ri = cookie;
1113 	struct vcons_screen *scr = ri->ri_hw;
1114 	struct hyperfb_softc *sc = scr->scr_cookie;
1115 	int32_t xs, xd, y, width, height;
1116 
1117 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1118 		if (ri->ri_crow == row &&
1119 		   (ri->ri_ccol >= srccol && ri->ri_ccol < (srccol + ncols)) &&
1120 		   (ri->ri_flg & RI_CURSOR)) {
1121 			hyperfb_nuke_cursor(ri);
1122 		}
1123 
1124 		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1125 		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1126 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1127 		width = ri->ri_font->fontwidth * ncols;
1128 		height = ri->ri_font->fontheight;
1129 		hyperfb_bitblt(sc, xs, y, xd, y, width, height, RopSrc);
1130 		if (ri->ri_crow == row &&
1131 		   (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols)))
1132 			ri->ri_flg &= ~RI_CURSOR;
1133 	}
1134 }
1135 
1136 static void
1137 hyperfb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1138 {
1139 	struct rasops_info *ri = cookie;
1140 	struct vcons_screen *scr = ri->ri_hw;
1141 	struct hyperfb_softc *sc = scr->scr_cookie;
1142 	int32_t x, y, width, height, fg, bg, ul;
1143 
1144 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1145 		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1146 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1147 		width = ri->ri_font->fontwidth * ncols;
1148 		height = ri->ri_font->fontheight;
1149 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1150 
1151 		hyperfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1152 		if (ri->ri_crow == row &&
1153 		   (ri->ri_ccol >= startcol && ri->ri_ccol < (startcol + ncols)))
1154 			ri->ri_flg &= ~RI_CURSOR;
1155 	}
1156 }
1157 
1158 static void
1159 hyperfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1160 {
1161 	struct rasops_info *ri = cookie;
1162 	struct vcons_screen *scr = ri->ri_hw;
1163 	struct hyperfb_softc *sc = scr->scr_cookie;
1164 	int32_t x, ys, yd, width, height;
1165 
1166 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1167 		if ((ri->ri_crow >= srcrow && ri->ri_crow < (srcrow + nrows)) &&
1168 		   (ri->ri_flg & RI_CURSOR)) {
1169 			hyperfb_nuke_cursor(ri);
1170 		}
1171 		x = ri->ri_xorigin;
1172 		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1173 		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1174 		width = ri->ri_emuwidth;
1175 		height = ri->ri_font->fontheight * nrows;
1176 		hyperfb_bitblt(sc, x, ys, x, yd, width, height, RopSrc);
1177 		if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows))
1178 			ri->ri_flg &= ~RI_CURSOR;
1179 	}
1180 }
1181 
1182 static void
1183 hyperfb_eraserows(void *cookie, int row, int nrows, long fillattr)
1184 {
1185 	struct rasops_info *ri = cookie;
1186 	struct vcons_screen *scr = ri->ri_hw;
1187 	struct hyperfb_softc *sc = scr->scr_cookie;
1188 	int32_t x, y, width, height, fg, bg, ul;
1189 
1190 	if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1191 		x = ri->ri_xorigin;
1192 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1193 		width = ri->ri_emuwidth;
1194 		height = ri->ri_font->fontheight * nrows;
1195 		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1196 
1197 		hyperfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
1198 
1199 		if (ri->ri_crow >= row && ri->ri_crow < (row + nrows))
1200 			ri->ri_flg &= ~RI_CURSOR;
1201 	}
1202 }
1203 
1204 static void
1205 hyperfb_move_cursor(struct hyperfb_softc *sc, int x, int y)
1206 {
1207 	uint32_t pos;
1208 
1209 	sc->sc_cursor_x = x;
1210 	x -= sc->sc_hot_x;
1211 	sc->sc_cursor_y = y;
1212 	y -= sc->sc_hot_y;
1213 
1214 	if (x < 0) x = 0x1000 - x;
1215 	if (y < 0) y = 0x1000 - y;
1216 	pos = (x << 16) | y;
1217 	if (sc->sc_enabled) pos |= HCRX_ENABLE_CURSOR;
1218 	hyperfb_wait(sc);
1219 	hyperfb_write4(sc, NGLE_REG_29, pos);
1220 }
1221 
1222 static int
1223 hyperfb_do_cursor(struct hyperfb_softc *sc, struct wsdisplay_cursor *cur)
1224 {
1225 
1226 	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
1227 
1228 		sc->sc_enabled = cur->enable;
1229 		cur->which |= WSDISPLAY_CURSOR_DOPOS;
1230 	}
1231 	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
1232 
1233 		sc->sc_hot_x = cur->hot.x;
1234 		sc->sc_hot_y = cur->hot.y;
1235 		cur->which |= WSDISPLAY_CURSOR_DOPOS;
1236 	}
1237 	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
1238 
1239 		hyperfb_move_cursor(sc, cur->pos.x, cur->pos.y);
1240 	}
1241 	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1242 		uint32_t rgb;
1243 		uint8_t r[2], g[2], b[2];
1244 
1245 		copyin(cur->cmap.blue, b, 2);
1246 		copyin(cur->cmap.green, g, 2);
1247 		copyin(cur->cmap.red, r, 2);
1248 		mutex_enter(&sc->sc_hwlock);
1249 		hyperfb_wait(sc);
1250 		hyperfb_write4(sc, NGLE_REG_10, 0xBBE0F000);
1251 		hyperfb_write4(sc, NGLE_REG_14, 0x03000300);
1252 		hyperfb_write4(sc, NGLE_REG_13, 0xffffffff);
1253 		hyperfb_wait(sc);
1254 		hyperfb_write4(sc, NGLE_REG_3, 0);
1255 		rgb = (r[0] << 16) | (g[0] << 8) | b[0];
1256 		hyperfb_write4(sc, NGLE_REG_4, rgb);	/* BG */
1257 		rgb = (r[1] << 16) | (g[1] << 8) | b[1];
1258 		hyperfb_write4(sc, NGLE_REG_4, rgb);	/* FG */
1259 		hyperfb_write4(sc, NGLE_REG_2, 0);
1260 		hyperfb_write4(sc, NGLE_REG_38, LBC_ENABLE | LBC_TYPE_CURSOR | 4);
1261 
1262 		hyperfb_setup_fb(sc);
1263 		mutex_exit(&sc->sc_hwlock);
1264 
1265 	}
1266 	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
1267 		uint32_t buffer[128], latch, tmp;
1268 		int i;
1269 
1270 		copyin(cur->mask, buffer, 512);
1271 		hyperfb_wait(sc);
1272 		hyperfb_write4(sc, NGLE_REG_30, 0);
1273 		for (i = 0; i < 128; i += 2) {
1274 			latch = 0;
1275 			tmp = buffer[i] & 0x80808080;
1276 			latch |= tmp >> 7;
1277 			tmp = buffer[i] & 0x40404040;
1278 			latch |= tmp >> 5;
1279 			tmp = buffer[i] & 0x20202020;
1280 			latch |= tmp >> 3;
1281 			tmp = buffer[i] & 0x10101010;
1282 			latch |= tmp >> 1;
1283 			tmp = buffer[i] & 0x08080808;
1284 			latch |= tmp << 1;
1285 			tmp = buffer[i] & 0x04040404;
1286 			latch |= tmp << 3;
1287 			tmp = buffer[i] & 0x02020202;
1288 			latch |= tmp << 5;
1289 			tmp = buffer[i] & 0x01010101;
1290 			latch |= tmp << 7;
1291 			hyperfb_write4(sc, NGLE_REG_31, latch);
1292 			latch = 0;
1293 			tmp = buffer[i + 1] & 0x80808080;
1294 			latch |= tmp >> 7;
1295 			tmp = buffer[i + 1] & 0x40404040;
1296 			latch |= tmp >> 5;
1297 			tmp = buffer[i + 1] & 0x20202020;
1298 			latch |= tmp >> 3;
1299 			tmp = buffer[i + 1] & 0x10101010;
1300 			latch |= tmp >> 1;
1301 			tmp = buffer[i + 1] & 0x08080808;
1302 			latch |= tmp << 1;
1303 			tmp = buffer[i + 1] & 0x04040404;
1304 			latch |= tmp << 3;
1305 			tmp = buffer[i + 1] & 0x02020202;
1306 			latch |= tmp << 5;
1307 			tmp = buffer[i + 1] & 0x01010101;
1308 			latch |= tmp << 7;
1309 			hyperfb_write4(sc, NGLE_REG_31, latch);
1310 		}
1311 
1312 		copyin(cur->image, buffer, 512);
1313 		hyperfb_wait(sc);
1314 		hyperfb_write4(sc, NGLE_REG_30, 0x80);
1315 		for (i = 0; i < 128; i += 2) {
1316 			latch = 0;
1317 			tmp = buffer[i] & 0x80808080;
1318 			latch |= tmp >> 7;
1319 			tmp = buffer[i] & 0x40404040;
1320 			latch |= tmp >> 5;
1321 			tmp = buffer[i] & 0x20202020;
1322 			latch |= tmp >> 3;
1323 			tmp = buffer[i] & 0x10101010;
1324 			latch |= tmp >> 1;
1325 			tmp = buffer[i] & 0x08080808;
1326 			latch |= tmp << 1;
1327 			tmp = buffer[i] & 0x04040404;
1328 			latch |= tmp << 3;
1329 			tmp = buffer[i] & 0x02020202;
1330 			latch |= tmp << 5;
1331 			tmp = buffer[i] & 0x01010101;
1332 			latch |= tmp << 7;
1333 			hyperfb_write4(sc, NGLE_REG_31, latch);
1334 			latch = 0;
1335 			tmp = buffer[i + 1] & 0x80808080;
1336 			latch |= tmp >> 7;
1337 			tmp = buffer[i + 1] & 0x40404040;
1338 			latch |= tmp >> 5;
1339 			tmp = buffer[i + 1] & 0x20202020;
1340 			latch |= tmp >> 3;
1341 			tmp = buffer[i + 1] & 0x10101010;
1342 			latch |= tmp >> 1;
1343 			tmp = buffer[i + 1] & 0x08080808;
1344 			latch |= tmp << 1;
1345 			tmp = buffer[i + 1] & 0x04040404;
1346 			latch |= tmp << 3;
1347 			tmp = buffer[i + 1] & 0x02020202;
1348 			latch |= tmp << 5;
1349 			tmp = buffer[i + 1] & 0x01010101;
1350 			latch |= tmp << 7;
1351 			hyperfb_write4(sc, NGLE_REG_31, latch);
1352 		}
1353 		hyperfb_setup_fb(sc);
1354 	}
1355 
1356 	return 0;
1357 }
1358