xref: /netbsd-src/sys/dev/sbus/p9100.c (revision bf1e9b32e27832f0c493206710fb8b58a980838a)
1 /*	$NetBSD: p9100.c,v 1.23 2005/06/04 04:36:04 tsutsui Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * color display (p9100) driver.
41  *
42  * Does not handle interrupts, even though they can occur.
43  *
44  * XXX should defer colormap updates to vertical retrace interrupts
45  */
46 
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: p9100.c,v 1.23 2005/06/04 04:36:04 tsutsui Exp $");
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/buf.h>
53 #include <sys/device.h>
54 #include <sys/ioctl.h>
55 #include <sys/malloc.h>
56 #include <sys/mman.h>
57 #include <sys/tty.h>
58 #include <sys/conf.h>
59 
60 #include <machine/bus.h>
61 #include <machine/autoconf.h>
62 
63 #include <dev/sun/fbio.h>
64 #include <dev/sun/fbvar.h>
65 #include <dev/sun/btreg.h>
66 #include <dev/sun/btvar.h>
67 
68 #include <dev/sbus/p9100reg.h>
69 
70 #include <dev/sbus/sbusvar.h>
71 
72 /*#include <dev/wscons/wsdisplayvar.h>*/
73 #include <dev/wscons/wsconsio.h>
74 #include <dev/wsfont/wsfont.h>
75 #include <dev/rasops/rasops.h>
76 
77 #include "opt_wsemul.h"
78 #include "rasops_glue.h"
79 
80 #include "tctrl.h"
81 #if NTCTRL > 0
82 #include <machine/tctrl.h>
83 #include <sparc/dev/tctrlvar.h>/*XXX*/
84 #endif
85 
86 /* per-display variables */
87 struct p9100_softc {
88 	struct device	sc_dev;		/* base device */
89 	struct sbusdev	sc_sd;		/* sbus device */
90 	struct fbdevice	sc_fb;		/* frame buffer device */
91 	bus_space_tag_t	sc_bustag;
92 
93 	bus_addr_t	sc_ctl_paddr;	/* phys address description */
94 	bus_size_t	sc_ctl_psize;	/*   for device mmap() */
95 	bus_space_handle_t sc_ctl_memh;	/*   bus space handle */
96 
97 	bus_addr_t	sc_cmd_paddr;	/* phys address description */
98 	bus_size_t	sc_cmd_psize;	/*   for device mmap() */
99 	bus_space_handle_t sc_cmd_memh;	/*   bus space handle */
100 
101 	bus_addr_t	sc_fb_paddr;	/* phys address description */
102 	bus_size_t	sc_fb_psize;	/*   for device mmap() */
103 	bus_space_handle_t sc_fb_memh;	/*   bus space handle */
104 
105 	uint32_t sc_junk;
106 	uint32_t sc_mono_width;	/* for setup_mono */
107 
108 	uint32_t sc_width;
109 	uint32_t sc_height;	/* panel width / height */
110 	uint32_t sc_stride;
111 	uint32_t sc_depth;
112 	union	bt_cmap sc_cmap;	/* Brooktree color map */
113 
114 #ifdef PNOZZ_SOFT_PUTCHAR
115 	void (*putchar)(void *c, int row, int col, u_int uc, long attr);
116 #endif
117 	int sc_mode;
118 	uint32_t sc_bg;
119 	void (*switchcb)(void *, int, int);
120 	void *switchcbarg;
121 	struct callout switch_callout;
122 	LIST_HEAD(, p9100_screen) screens;
123 	struct p9100_screen *active, *wanted;
124 	const struct wsscreen_descr *currenttype;
125 
126 };
127 
128 struct p9100_screen {
129 	struct rasops_info ri;
130 	LIST_ENTRY(p9100_screen) next;
131 	struct p9100_softc *sc;
132 	const struct wsscreen_descr *type;
133 	int active;
134 	u_int16_t *chars;
135 	long *attrs;
136 	int dispoffset;
137 	int mindispoffset;
138 	int maxdispoffset;
139 
140 	int cursoron;
141 	int cursorcol;
142 	int cursorrow;
143 	int cursordrawn;
144 };
145 
146 static struct p9100_screen p9100_console_screen;
147 
148 extern const u_char rasops_cmap[768];
149 
150 struct wsscreen_descr p9100_defscreendesc = {
151 	"default",
152 	0, 0,
153 	NULL,
154 	8, 16,
155 	WSSCREEN_WSCOLORS,
156 };
157 
158 const struct wsscreen_descr *_p9100_scrlist[] = {
159 	&p9100_defscreendesc,
160 	/* XXX other formats, graphics screen? */
161 };
162 
163 struct wsscreen_list p9100_screenlist = {
164 	sizeof(_p9100_scrlist) / sizeof(struct wsscreen_descr *), _p9100_scrlist
165 };
166 
167 /* autoconfiguration driver */
168 static int	p9100_sbus_match(struct device *, struct cfdata *, void *);
169 static void	p9100_sbus_attach(struct device *, struct device *, void *);
170 
171 static void	p9100unblank(struct device *);
172 static void	p9100_shutdown(void *);
173 
174 CFATTACH_DECL(pnozz, sizeof(struct p9100_softc),
175     p9100_sbus_match, p9100_sbus_attach, NULL, NULL);
176 
177 extern struct cfdriver pnozz_cd;
178 
179 dev_type_open(p9100open);
180 dev_type_ioctl(p9100ioctl);
181 dev_type_mmap(p9100mmap);
182 
183 const struct cdevsw pnozz_cdevsw = {
184 	p9100open, nullclose, noread, nowrite, p9100ioctl,
185 	nostop, notty, nopoll, p9100mmap, nokqfilter,
186 };
187 
188 /* frame buffer generic driver */
189 static struct fbdriver p9100fbdriver = {
190 	p9100unblank, p9100open, nullclose, p9100ioctl, nopoll,
191 	p9100mmap, nokqfilter
192 };
193 
194 static void	p9100loadcmap(struct p9100_softc *, int, int);
195 static void	p9100_set_video(struct p9100_softc *, int);
196 static int	p9100_get_video(struct p9100_softc *);
197 static uint32_t p9100_ctl_read_4(struct p9100_softc *, bus_size_t);
198 static void	p9100_ctl_write_4(struct p9100_softc *, bus_size_t, uint32_t);
199 uint8_t		p9100_ramdac_read(struct p9100_softc *, bus_size_t);
200 void		p9100_ramdac_write(struct p9100_softc *, bus_size_t, uint8_t);
201 
202 static void	p9100_sync(struct p9100_softc *);
203 void 		p9100_bitblt(struct p9100_softc *, int, int, int, int, int, int, 		    uint32_t);	/* coordinates, rasop */
204 void 		p9100_rectfill(struct p9100_softc *, int, int, int, int,
205 		    uint32_t);	/* coordinates, colour */
206 static void 	p9100_init_engine(struct p9100_softc *);
207 void		p9100_setup_mono(struct p9100_softc *, int, int, int, int,
208 		    uint32_t, uint32_t);
209 void		p9100_feed_line(struct p9100_softc *, int, uint8_t *);
210 static void	p9100_set_color_reg(struct p9100_softc *, int, int32_t);
211 
212 void	p9100_cursor(void *, int, int, int);
213 int	p9100_mapchar(void *, int, u_int *);
214 void	p9100_putchar(void *, int, int, u_int, long);
215 void	p9100_copycols(void *, int, int, int, int);
216 void	p9100_erasecols(void *, int, int, int, long);
217 void	p9100_copyrows(void *, int, int, int);
218 void	p9100_eraserows(void *, int, int, long);
219 int	p9100_allocattr(void *, int, int, int, long *);
220 
221 void	p9100_scroll(void *, void *, int);
222 
223 int	p9100_putcmap(struct p9100_softc *, struct wsdisplay_cmap *);
224 int 	p9100_getcmap(struct p9100_softc *, struct wsdisplay_cmap *);
225 int	p9100_ioctl(void *, u_long, caddr_t, int, struct proc *);
226 paddr_t	p9100_mmap(void *, off_t, int);
227 int	p9100_alloc_screen(void *, const struct wsscreen_descr *, void **,
228 	    int *, int *, long *);
229 void	p9100_free_screen(void *, void *);
230 int	p9100_show_screen(void *, void *, int, void (*)(void *, int, int),
231 	    void *);
232 void	p9100_switch_screen(struct p9100_softc *);
233 void	p9100_restore_screen(struct p9100_screen *,
234 	    const struct wsscreen_descr *, u_int16_t *);
235 void	p9100_clearscreen(struct p9100_softc *);
236 
237 int	p9100_load_font(void *, void *, struct wsdisplay_font *);
238 
239 void	p9100_init_screen(struct p9100_softc *, struct p9100_screen *, int,
240 	    long *);
241 
242 int	p9100_intr(void *);
243 
244 struct wsdisplay_accessops p9100_accessops = {
245 	p9100_ioctl,
246 	p9100_mmap,
247 	p9100_alloc_screen,
248 	p9100_free_screen,
249 	p9100_show_screen,
250 	NULL,	/* load_font */
251 	NULL,	/* polls */
252 	NULL,	/* getwschar */
253 	NULL,	/* putwschar */
254 	NULL,	/* scroll */
255 	NULL,	/* getborder */
256 	NULL	/* setborder */
257 };
258 
259 /*
260  * Match a p9100.
261  */
262 static int
263 p9100_sbus_match(struct device *parent, struct cfdata *cf, void *aux)
264 {
265 	struct sbus_attach_args *sa = aux;
266 
267 	return (strcmp("p9100", sa->sa_name) == 0);
268 }
269 
270 
271 /*
272  * Attach a display.  We need to notice if it is the console, too.
273  */
274 static void
275 p9100_sbus_attach(struct device *parent, struct device *self, void *args)
276 {
277 	struct p9100_softc *sc = (struct p9100_softc *)self;
278 	struct sbus_attach_args *sa = args;
279 	struct fbdevice *fb = &sc->sc_fb;
280 	int isconsole;
281 	int node;
282 	int i, j;
283 
284 #if NWSDISPLAY > 0
285 	struct wsemuldisplaydev_attach_args aa;
286 	struct rasops_info *ri;
287 	unsigned long defattr;
288 #endif
289 
290 	/* Remember cookies for p9100_mmap() */
291 	sc->sc_bustag = sa->sa_bustag;
292 	sc->sc_ctl_paddr = sbus_bus_addr(sa->sa_bustag,
293 		sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base);
294 	sc->sc_ctl_psize = 0x8000;/*(bus_size_t)sa->sa_reg[0].oa_size;*/
295 
296 	sc->sc_cmd_paddr = sbus_bus_addr(sa->sa_bustag,
297 		sa->sa_reg[1].oa_space, sa->sa_reg[1].oa_base);
298 	sc->sc_cmd_psize = (bus_size_t)sa->sa_reg[1].oa_size;
299 
300 	sc->sc_fb_paddr = sbus_bus_addr(sa->sa_bustag,
301 		sa->sa_reg[2].oa_space, sa->sa_reg[2].oa_base);
302 	sc->sc_fb_psize = (bus_size_t)sa->sa_reg[2].oa_size;
303 
304 	fb->fb_driver = &p9100fbdriver;
305 	fb->fb_device = &sc->sc_dev;
306 	fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK;
307 #ifdef PNOZZ_EMUL_CG3
308 	fb->fb_type.fb_type = FBTYPE_SUN3COLOR;
309 #else
310 	fb->fb_type.fb_type = FBTYPE_P9100;
311 #endif
312 	fb->fb_pixels = NULL;
313 
314 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
315 #ifdef PNOZZ_SOFT_PUTCHAR
316 	sc->putchar = NULL;
317 #endif
318 
319 	LIST_INIT(&sc->screens);
320 	sc->active = NULL;
321 	sc->currenttype = &p9100_defscreendesc;
322 	callout_init(&sc->switch_callout);
323 
324 	node = sa->sa_node;
325 	isconsole = fb_is_console(node);
326 	if (!isconsole) {
327 		printf("\n%s: fatal error: PROM didn't configure device\n",
328 		    self->dv_xname);
329 		return;
330 	}
331 
332 	/*
333 	 * When the ROM has mapped in a p9100 display, the address
334 	 * maps only the video RAM, so in any case we have to map the
335 	 * registers ourselves.  We only need the video RAM if we are
336 	 * going to print characters via rconsole.
337 	 */
338 	if (sbus_bus_map(sc->sc_bustag,
339 			 sa->sa_reg[0].oa_space,
340 			 sa->sa_reg[0].oa_base,
341 			 /*
342 			  * XXX for some reason the SBus resources don't cover
343 			  * all registers, so we just map what we need
344 			  */
345 			 /*sc->sc_ctl_psize*/ 0x8000,
346 			 BUS_SPACE_MAP_LINEAR, &sc->sc_ctl_memh) != 0) {
347 		printf("%s: cannot map control registers\n", self->dv_xname);
348 		return;
349 	}
350 
351 	if (sa->sa_npromvaddrs != 0)
352 		fb->fb_pixels = (caddr_t)sa->sa_promvaddrs[0];
353 
354 	if (fb->fb_pixels == NULL) {
355 		if (sbus_bus_map(sc->sc_bustag,
356 				sa->sa_reg[2].oa_space,
357 				sa->sa_reg[2].oa_base,
358 				sc->sc_fb_psize,
359 				BUS_SPACE_MAP_LINEAR, &sc->sc_fb_memh) != 0) {
360 			printf("%s: cannot map framebuffer\n", self->dv_xname);
361 			return;
362 		}
363 		fb->fb_pixels = (char *)sc->sc_fb_memh;
364 	} else {
365 		sc->sc_fb_memh = (bus_space_handle_t) fb->fb_pixels;
366 	}
367 
368 	i = p9100_ctl_read_4(sc, 0x0004);
369 	switch ((i >> 26) & 7) {
370 	    case 5: fb->fb_type.fb_depth = 32; break;
371 	    case 7: fb->fb_type.fb_depth = 24; break;
372 	    case 3: fb->fb_type.fb_depth = 16; break;
373 	    case 2: fb->fb_type.fb_depth = 8; break;
374 	    default: {
375 		panic("pnozz: can't determine screen depth (0x%02x)", i);
376 	    }
377 	}
378 	sc->sc_depth = (fb->fb_type.fb_depth >> 3);
379 
380 	/* XXX for some reason I get a kernel trap with this */
381 	sc->sc_width = prom_getpropint(node, "width", 800);
382 	sc->sc_height = prom_getpropint(node, "height", 600);
383 
384 	sc->sc_stride = prom_getpropint(node, "linebytes", sc->sc_width *
385 	    (fb->fb_type.fb_depth >> 3));
386 
387 	p9100_init_engine(sc);
388 
389 	fb_setsize_obp(fb, fb->fb_type.fb_depth, sc->sc_width, sc->sc_height,
390 	    node);
391 
392 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
393 
394 	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
395 	printf(": rev %d, %dx%d, depth %d mem %x",
396 	       (i & 7), fb->fb_type.fb_width, fb->fb_type.fb_height,
397 	       fb->fb_type.fb_depth, (unsigned int)sc->sc_fb_psize);
398 
399 	fb->fb_type.fb_cmsize = prom_getpropint(node, "cmsize", 256);
400 	if ((1 << fb->fb_type.fb_depth) != fb->fb_type.fb_cmsize)
401 		printf(", %d entry colormap", fb->fb_type.fb_cmsize);
402 
403 	/* Initialize the default color map. */
404 	/*bt_initcmap(&sc->sc_cmap, 256);*/
405 	j = 0;
406 	for (i = 0; i < 256; i++) {
407 		sc->sc_cmap.cm_map[i][0] = rasops_cmap[j];
408 		j++;
409 		sc->sc_cmap.cm_map[i][1] = rasops_cmap[j];
410 		j++;
411 		sc->sc_cmap.cm_map[i][2] = rasops_cmap[j];
412 		j++;
413 	}
414 	p9100loadcmap(sc, 0, 256);
415 
416 	/* make sure we are not blanked */
417 	if (isconsole)
418 		p9100_set_video(sc, 1);
419 
420 	if (shutdownhook_establish(p9100_shutdown, sc) == NULL) {
421 		panic("%s: could not establish shutdown hook",
422 		      sc->sc_dev.dv_xname);
423 	}
424 
425 	if (isconsole) {
426 		printf(" (console)\n");
427 #ifdef RASTERCONSOLE
428 		/*p9100loadcmap(sc, 255, 1);*/
429 		fbrcons_init(fb);
430 #endif
431 	} else
432 		printf("\n");
433 
434 #if NWSDISPLAY > 0
435 	wsfont_init();
436 
437 	p9100_init_screen(sc, &p9100_console_screen, 1, &defattr);
438 	p9100_console_screen.active = 1;
439 	sc->active = &p9100_console_screen;
440 	ri = &p9100_console_screen.ri;
441 
442 	p9100_defscreendesc.nrows = ri->ri_rows;
443 	p9100_defscreendesc.ncols = ri->ri_cols;
444 	p9100_defscreendesc.textops = &ri->ri_ops;
445 	p9100_defscreendesc.capabilities = ri->ri_caps;
446 
447 	if(isconsole) {
448 		wsdisplay_cnattach(&p9100_defscreendesc, ri, 0, 0, defattr);
449 	}
450 
451 	sc->sc_bg = (defattr >> 16) & 0xff;
452 
453 	p9100_clearscreen(sc);
454 
455 	aa.console = isconsole;
456 	aa.scrdata = &p9100_screenlist;
457 	aa.accessops = &p9100_accessops;
458 	aa.accesscookie = sc;
459 
460 	config_found(self, &aa, wsemuldisplaydevprint);
461 #endif
462 	/* attach the fb */
463 	fb_attach(fb, isconsole);
464 
465 #if 0
466 	p9100_rectfill(sc, 10, 10, 200, 200, 0x01);
467 	p9100_rectfill(sc, 210, 10, 200, 200, 0xff);
468 	p9100_bitblt(sc, 10, 10, 110, 110, 400, 200, ROP_SRC);
469 #endif
470 #if 0
471 	p9100_setup_mono(sc, 750, 500, 32, 1, 1, 6);
472 	{
473 		uint32_t ev = 0xc3000000, odd = 0x3c000000;
474 		for (i = 0; i < 16; i++) {
475 			p9100_feed_line(sc, 1, (uint8_t*)&ev);
476 			p9100_feed_line(sc, 1, (uint8_t*)&odd);
477 		}
478 	}
479 	delay(4000000);
480 #endif
481 }
482 
483 static void
484 p9100_shutdown(arg)
485 	void *arg;
486 {
487 	struct p9100_softc *sc = arg;
488 
489 #ifdef RASTERCONSOLE
490 	sc->sc_cmap.cm_map[0][0] = 0xff;
491 	sc->sc_cmap.cm_map[0][1] = 0xff;
492 	sc->sc_cmap.cm_map[0][2] = 0xff;
493 	sc->sc_cmap.cm_map[1][0] = 0;
494 	sc->sc_cmap.cm_map[1][1] = 0;
495 	sc->sc_cmap.cm_map[1][2] = 0x00;
496 	p9100loadcmap(sc, 0, 2);
497 	sc->sc_cmap.cm_map[255][0] = 0;
498 	sc->sc_cmap.cm_map[255][1] = 0;
499 	sc->sc_cmap.cm_map[255][2] = 0;
500 	p9100loadcmap(sc, 255, 1);
501 #endif
502 	p9100_set_video(sc, 1);
503 }
504 
505 int
506 p9100open(dev_t dev, int flags, int mode, struct proc *p)
507 {
508 	int unit = minor(dev);
509 
510 	if (unit >= pnozz_cd.cd_ndevs || pnozz_cd.cd_devs[unit] == NULL)
511 		return (ENXIO);
512 	return (0);
513 }
514 
515 int
516 p9100ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
517 {
518 	struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)];
519 	struct fbgattr *fba;
520 	int error;
521 
522 	switch (cmd) {
523 
524 	case FBIOGTYPE:
525 		*(struct fbtype *)data = sc->sc_fb.fb_type;
526 		break;
527 
528 	case FBIOGATTR:
529 		fba = (struct fbgattr *)data;
530 		fba->real_type = sc->sc_fb.fb_type.fb_type;
531 		fba->owner = 0;		/* XXX ??? */
532 		fba->fbtype = sc->sc_fb.fb_type;
533 		fba->sattr.flags = 0;
534 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
535 		fba->sattr.dev_specific[0] = -1;
536 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
537 		fba->emu_types[1] = -1;
538 		break;
539 
540 	case FBIOGETCMAP:
541 #define p ((struct fbcmap *)data)
542 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
543 
544 	case FBIOPUTCMAP:
545 		/* copy to software map */
546 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
547 		if (error)
548 			return (error);
549 		/* now blast them into the chip */
550 		/* XXX should use retrace interrupt */
551 		p9100loadcmap(sc, p->index, p->count);
552 #undef p
553 		break;
554 
555 	case FBIOGVIDEO:
556 		*(int *)data = p9100_get_video(sc);
557 		break;
558 
559 	case FBIOSVIDEO:
560 		p9100_set_video(sc, *(int *)data);
561 		break;
562 
563 	default:
564 		return (ENOTTY);
565 	}
566 	return (0);
567 }
568 
569 static uint32_t
570 p9100_ctl_read_4(struct p9100_softc *sc, bus_size_t off)
571 {
572 	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
573 	return bus_space_read_4(sc->sc_bustag, sc->sc_ctl_memh, off);
574 }
575 
576 static void
577 p9100_ctl_write_4(struct p9100_softc *sc, bus_size_t off, uint32_t v)
578 {
579 	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
580 	bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, v);
581 }
582 
583 /* wait until the engine is idle */
584 static void
585 p9100_sync(struct p9100_softc *sc)
586 {
587 	while((p9100_ctl_read_4(sc, ENGINE_STATUS) &
588 	    (ENGINE_BUSY | BLITTER_BUSY)) != 0);
589 }
590 
591 static void
592 p9100_set_color_reg(struct p9100_softc *sc, int reg, int32_t col)
593 {
594 	uint32_t out;
595 
596 	switch(sc->sc_depth)
597 	{
598 		case 1:	/* 8 bit */
599 			out = (col << 8) | col;
600 			out |= out << 16;
601 			break;
602 		case 2: /* 16 bit */
603 			out = col | (col << 16);
604 			break;
605 		default:
606 			out = col;
607 	}
608 	p9100_ctl_write_4(sc, reg, out);
609 }
610 
611 /* initialize the drawing engine */
612 static void
613 p9100_init_engine(struct p9100_softc *sc)
614 {
615 	/* reset clipping rectangles */
616 	uint32_t rmax = ((sc->sc_width & 0x3fff) << 16) |
617 	    (sc->sc_height & 0x3fff);
618 
619 	p9100_ctl_write_4(sc, WINDOW_OFFSET, 0);
620 	p9100_ctl_write_4(sc, WINDOW_MIN, 0);
621 	p9100_ctl_write_4(sc, WINDOW_MAX, rmax);
622 	p9100_ctl_write_4(sc, BYTE_CLIP_MIN, 0);
623 	p9100_ctl_write_4(sc, BYTE_CLIP_MAX, rmax);
624 	p9100_ctl_write_4(sc, DRAW_MODE, 0);
625 	p9100_ctl_write_4(sc, PLANE_MASK, 0xffffffff);
626 	p9100_ctl_write_4(sc, PATTERN0, 0xffffffff);
627 	p9100_ctl_write_4(sc, PATTERN1, 0xffffffff);
628 	p9100_ctl_write_4(sc, PATTERN2, 0xffffffff);
629 	p9100_ctl_write_4(sc, PATTERN3, 0xffffffff);
630 }
631 
632 /* screen-to-screen blit */
633 void
634 p9100_bitblt(struct p9100_softc *sc, int xs, int ys, int xd, int yd, int wi,
635     int he, uint32_t rop)
636 {
637 	uint32_t src, dst, srcw, dstw, junk;
638 
639 	src = ((xs & 0x3fff) << 16) | (ys & 0x3fff);
640 	dst = ((xd & 0x3fff) << 16) | (yd & 0x3fff);
641 	srcw = (((xs + wi - 1) & 0x3fff) << 16) | ((ys + he - 1) & 0x3fff);
642 	dstw = (((xd + wi - 1) & 0x3fff) << 16) | ((yd + he - 1) & 0x3fff);
643 	p9100_sync(sc);
644 	p9100_ctl_write_4(sc, RASTER_OP, rop);
645 
646 	p9100_ctl_write_4(sc, ABS_XY0, src);
647 
648 	p9100_ctl_write_4(sc, ABS_XY1, srcw);
649 	p9100_ctl_write_4(sc, ABS_XY2, dst);
650 	p9100_ctl_write_4(sc, ABS_XY3, dstw);
651 	junk = p9100_ctl_read_4(sc, COMMAND_BLIT);
652 }
653 
654 /* solid rectangle fill */
655 void
656 p9100_rectfill(struct p9100_softc *sc, int xs, int ys, int wi, int he, uint32_t col)
657 {
658 	uint32_t src, srcw, junk;
659 
660 	src = ((xs & 0x3fff) << 16) | (ys & 0x3fff);
661 	srcw = (((xs + wi) & 0x3fff) << 16) | ((ys + he) & 0x3fff);
662 	p9100_sync(sc);
663 	p9100_set_color_reg(sc, FOREGROUND_COLOR, col);
664 	p9100_set_color_reg(sc, BACKGROUND_COLOR, col);
665 	p9100_ctl_write_4(sc, RASTER_OP, ROP_PAT);
666 	p9100_ctl_write_4(sc, COORD_INDEX, 0);
667 	p9100_ctl_write_4(sc, RECT_RTW_XY, src);
668 	p9100_ctl_write_4(sc, RECT_RTW_XY, srcw);
669 	junk=p9100_ctl_read_4(sc, COMMAND_QUAD);
670 }
671 
672 /* setup for mono->colour expansion */
673 void
674 p9100_setup_mono(struct p9100_softc *sc, int x, int y, int wi, int he,
675     uint32_t fg, uint32_t bg)
676 {
677 	p9100_sync(sc);
678 	/*
679 	 * this doesn't make any sense to me either, but for some reason the
680 	 * chip applies the foreground colour to 0 pixels
681 	 */
682 
683 	p9100_set_color_reg(sc,FOREGROUND_COLOR,bg);
684 	p9100_set_color_reg(sc,BACKGROUND_COLOR,fg);
685 
686 	p9100_ctl_write_4(sc, RASTER_OP, ROP_SRC);
687 	p9100_ctl_write_4(sc, ABS_X0, x);
688 	p9100_ctl_write_4(sc, ABS_XY1, (x << 16) | (y & 0xFFFFL));
689 	p9100_ctl_write_4(sc, ABS_X2, (x + wi));
690 	p9100_ctl_write_4(sc, ABS_Y3, he);
691 	/* now feed the data into the chip */
692 	sc->sc_mono_width = wi;
693 }
694 
695 /* write monochrome data to the screen through the blitter */
696 void
697 p9100_feed_line(struct p9100_softc *sc, int count, uint8_t *data)
698 {
699 	int i;
700 	uint32_t latch = 0, bork;
701 	int shift = 24;
702 	int to_go = sc->sc_mono_width;
703 
704 	for (i = 0; i < count; i++) {
705 		bork = data[i];
706 		latch |= (bork << shift);
707 		if (shift == 0) {
708 			/* check how many bits are significant */
709 			if (to_go > 31) {
710 				p9100_ctl_write_4(sc, (PIXEL_1 +
711 				    (31 << 2)), latch);
712 				to_go -= 32;
713 			} else
714 			{
715 				p9100_ctl_write_4(sc, (PIXEL_1 +
716 				    ((to_go - 1) << 2)), latch);
717 				to_go = 0;
718 			}
719 			latch = 0;
720 			shift = 24;
721 		} else
722 			shift -= 8;
723 		}
724 	if (shift != 24)
725 		p9100_ctl_write_4(sc, (PIXEL_1 + ((to_go - 1) << 2)), latch);
726 }
727 
728 void
729 p9100_clearscreen(struct p9100_softc *sc)
730 {
731 	p9100_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, sc->sc_bg);
732 }
733 
734 uint8_t
735 p9100_ramdac_read(struct p9100_softc *sc, bus_size_t off)
736 {
737 	sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
738 	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
739 	return ((bus_space_read_4(sc->sc_bustag,
740 	    sc->sc_ctl_memh, off) >> 16) & 0xff);
741 }
742 
743 void
744 p9100_ramdac_write(struct p9100_softc *sc, bus_size_t off, uint8_t v)
745 {
746 	sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
747 	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
748 	bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off,
749 	    ((uint32_t)v) << 16);
750 }
751 
752 /*
753  * Undo the effect of an FBIOSVIDEO that turns the video off.
754  */
755 static void
756 p9100unblank(struct device *dev)
757 {
758 	p9100_set_video((struct p9100_softc *)dev, 1);
759 }
760 
761 static void
762 p9100_set_video(struct p9100_softc *sc, int enable)
763 {
764 	u_int32_t v = p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1);
765 
766 	if (enable)
767 		v |= VIDEO_ENABLED;
768 	else
769 		v &= ~VIDEO_ENABLED;
770 	p9100_ctl_write_4(sc, SCRN_RPNT_CTL_1, v);
771 #if NTCTRL > 0
772 	/* Turn On/Off the TFT if we know how.
773 	 */
774 	tadpole_set_video(enable);
775 #endif
776 }
777 
778 static int
779 p9100_get_video(struct p9100_softc *sc)
780 {
781 	return (p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1) & VIDEO_ENABLED) != 0;
782 }
783 
784 /*
785  * Load a subset of the current (new) colormap into the IBM RAMDAC.
786  */
787 static void
788 p9100loadcmap(struct p9100_softc *sc, int start, int ncolors)
789 {
790 	int i;
791 	p9100_ramdac_write(sc, DAC_CMAP_WRIDX, start);
792 
793 	for (i=0;i<ncolors;i++) {
794 		p9100_ramdac_write(sc, DAC_CMAP_DATA,
795 		    sc->sc_cmap.cm_map[i + start][0]);
796 		p9100_ramdac_write(sc, DAC_CMAP_DATA,
797 		    sc->sc_cmap.cm_map[i + start][1]);
798 		p9100_ramdac_write(sc, DAC_CMAP_DATA,
799 		    sc->sc_cmap.cm_map[i + start][2]);
800 	}
801 }
802 
803 /*
804  * Return the address that would map the given device at the given
805  * offset, allowing for the given protection, or return -1 for error.
806  */
807 paddr_t
808 p9100mmap(dev_t dev, off_t off, int prot)
809 {
810 	struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)];
811 
812 	if (off & PGOFSET)
813 		panic("p9100mmap");
814 	if (off < 0)
815 		return (-1);
816 
817 #ifdef PNOZZ_EMUL_CG3
818 #define CG3_MMAP_OFFSET	0x04000000
819 	/* Make Xsun think we are a CG3 (SUN3COLOR)
820 	 */
821 	if (off >= CG3_MMAP_OFFSET && off < CG3_MMAP_OFFSET + sc->sc_fb_psize) {
822 		off -= CG3_MMAP_OFFSET;
823 		return (bus_space_mmap(sc->sc_bustag,
824 			sc->sc_fb_paddr,
825 			off,
826 			prot,
827 			BUS_SPACE_MAP_LINEAR));
828 	}
829 #endif
830 
831 	if (off >= sc->sc_fb_psize + sc->sc_ctl_psize + sc->sc_cmd_psize)
832 		return (-1);
833 
834 	if (off < sc->sc_fb_psize) {
835 		return (bus_space_mmap(sc->sc_bustag,
836 			sc->sc_fb_paddr,
837 			off,
838 			prot,
839 			BUS_SPACE_MAP_LINEAR));
840 	}
841 	off -= sc->sc_fb_psize;
842 	if (off < sc->sc_ctl_psize) {
843 		return (bus_space_mmap(sc->sc_bustag,
844 			sc->sc_ctl_paddr,
845 			off,
846 			prot,
847 			BUS_SPACE_MAP_LINEAR));
848 	}
849 	off -= sc->sc_ctl_psize;
850 
851 	return (bus_space_mmap(sc->sc_bustag,
852 		sc->sc_cmd_paddr,
853 		off,
854 		prot,
855 		BUS_SPACE_MAP_LINEAR));
856 }
857 
858 /* wscons stuff */
859 
860 void
861 p9100_switch_screen(struct p9100_softc *sc)
862 {
863 	struct p9100_screen *scr, *oldscr;
864 
865 	scr = sc->wanted;
866 	if (!scr) {
867 		printf("p9100_switch_screen: disappeared\n");
868 		(*sc->switchcb)(sc->switchcbarg, EIO, 0);
869 		return;
870 	}
871 	oldscr = sc->active; /* can be NULL! */
872 #ifdef DIAGNOSTIC
873 	if (oldscr) {
874 		if (!oldscr->active)
875 			panic("p9100_switch_screen: not active");
876 	}
877 #endif
878 	if (scr == oldscr)
879 		return;
880 
881 #ifdef DIAGNOSTIC
882 	if (scr->active)
883 		panic("p9100_switch_screen: active");
884 #endif
885 
886 	if (oldscr)
887 		oldscr->active = 0;
888 #ifdef notyet
889 	if (sc->currenttype != type) {
890 		p9100_set_screentype(sc, type);
891 		sc->currenttype = type;
892 	}
893 #endif
894 
895 	/* Clear the entire screen. */
896 
897 	scr->active = 1;
898 	p9100_restore_screen(scr, &p9100_defscreendesc, scr->chars);
899 
900 	sc->active = scr;
901 
902 	scr->ri.ri_ops.cursor(scr, scr->cursoron, scr->cursorrow,
903 	    scr->cursorcol);
904 
905 	sc->wanted = 0;
906 	if (sc->switchcb)
907 		(*sc->switchcb)(sc->switchcbarg, 0, 0);
908 }
909 
910 void
911 p9100_restore_screen(struct p9100_screen *scr,
912     const struct wsscreen_descr *type, u_int16_t *mem)
913 {
914 	int i, j, offset = 0;
915 	uint16_t *charptr = scr->chars;
916 	long *attrptr = scr->attrs;
917 
918 	p9100_clearscreen(scr->sc);
919 	for (i = 0; i < scr->ri.ri_rows; i++) {
920 		for (j = 0; j < scr->ri.ri_cols; j++) {
921 			p9100_putchar(scr, i, j, charptr[offset],
922 			    attrptr[offset]);
923 			offset++;
924 		}
925 	}
926 	scr->cursordrawn = 0;
927 }
928 
929 void
930 p9100_cursor(void *cookie, int on, int row, int col)
931 {
932 	struct rasops_info *ri = cookie;
933 	struct p9100_screen *scr = ri->ri_hw;
934 	struct p9100_softc *sc = scr->sc;
935 	int x, y, wi,he;
936 
937 	wi = ri->ri_font->fontwidth;
938 	he = ri->ri_font->fontheight;
939 
940 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
941 		x = scr->cursorcol * wi + ri->ri_xorigin;
942 		y = scr->cursorrow * he + ri->ri_yorigin;
943 		if (scr->cursordrawn) {
944 			p9100_bitblt(sc, x, y, x, y, wi, he, (ROP_SRC ^ 0xff));
945 			scr->cursordrawn = 0;
946 		}
947 		scr->cursorrow = row;
948 		scr->cursorcol = col;
949 		if ((scr->cursoron = on) != 0)
950 		{
951 			x = scr->cursorcol * wi + ri->ri_xorigin;
952 			y = scr->cursorrow * he + ri->ri_yorigin;
953 			p9100_bitblt(sc, x, y, x, y, wi, he, (ROP_SRC ^ 0xff));
954 			scr->cursordrawn = 1;
955 		}
956 	} else {
957 		scr->cursoron = on;
958 		scr->cursorrow = row;
959 		scr->cursorcol = col;
960 		scr->cursordrawn = 0;
961 	}
962 }
963 
964 #if 0
965 int
966 p9100_mapchar(void *cookie, int uni, u_int *index)
967 {
968 	return 0;
969 }
970 #endif
971 
972 void
973 p9100_putchar(void *cookie, int row, int col, u_int c, long attr)
974 {
975 	struct rasops_info *ri = cookie;
976 	struct p9100_screen *scr = ri->ri_hw;
977 	struct p9100_softc *sc = scr->sc;
978 	int pos;
979 
980 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
981 	     (col < ri->ri_cols)) {
982 		pos = col + row * ri->ri_cols;
983 		scr->attrs[pos] = attr;
984 		scr->chars[pos] = c;
985 
986 #ifdef PNOZZ_SOFT_PUTCHAR
987 		if ((sc->putchar != NULL) && (	scr->active) &&
988 		    (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
989 			p9100_sync(sc);
990 			sc->putchar(cookie, row, col, c, attr);
991 		}
992 #else
993 		if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
994 			int fg, bg, uc, i;
995 			uint8_t *data;
996 			int x, y, wi,he;
997 
998 			wi = ri->ri_font->fontwidth;
999 			he = ri->ri_font->fontheight;
1000 
1001 			if (!CHAR_IN_FONT(c, ri->ri_font))
1002 				return;
1003 			bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff];
1004 			fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff];
1005 			x = ri->ri_xorigin + col * wi;
1006 			y = ri->ri_yorigin + row * he;
1007 			if (c == 0x20) {
1008 				p9100_rectfill(sc, x, y, wi, he, bg);
1009 			} else {
1010 				uc = c-ri->ri_font->firstchar;
1011 				data = (uint8_t *)ri->ri_font->data + uc *
1012 				    ri->ri_fontscale;
1013 
1014 				p9100_setup_mono(sc, x, y, wi, 1, fg, bg);
1015 				for (i = 0; i < he; i++) {
1016 					p9100_feed_line(sc, ri->ri_font->stride,
1017 					    data);
1018 					data += ri->ri_font->stride;
1019 				}
1020 				/*p9100_sync(sc);*/
1021 			}
1022 		}
1023 #endif
1024 	}
1025 }
1026 
1027 void
1028 p9100_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1029 {
1030 	struct rasops_info *ri = cookie;
1031 	struct p9100_screen *scr = ri->ri_hw;
1032 	struct p9100_softc *sc = scr->sc;
1033 	int32_t xs, xd, y, width, height;
1034 	int from = srccol + row * ri->ri_cols;
1035 	int to = dstcol + row * ri->ri_cols;
1036 
1037 	memmove(&scr->attrs[to], &scr->attrs[from], ncols * sizeof(long));
1038 	memmove(&scr->chars[to], &scr->chars[from], ncols * sizeof(uint16_t));
1039 
1040 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1041 		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1042 		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1043 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1044 		width = ri->ri_font->fontwidth * ncols;
1045 		height = ri->ri_font->fontheight;
1046 		p9100_bitblt(sc, xs, y, xd, y, width, height, ROP_SRC);
1047 	}
1048 }
1049 
1050 void
1051 p9100_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
1052 {
1053 	struct rasops_info *ri = cookie;
1054 	struct p9100_screen *scr = ri->ri_hw;
1055 	struct p9100_softc *sc = scr->sc;
1056 	int32_t x, y, width, height, bg;
1057 	int start = startcol + row * ri->ri_cols;
1058 	int end = start + ncols, i;
1059 
1060 	for (i = start; i < end; i++) {
1061 		scr->attrs[i] = fillattr;
1062 		scr->chars[i] = 0x20;
1063 	}
1064 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1065 		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1066 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1067 		width = ri->ri_font->fontwidth * ncols;
1068 		height = ri->ri_font->fontheight;
1069 		bg = (fillattr >> 16) & 0xff;
1070 		p9100_rectfill(sc, x, y, width, height, bg);
1071 	}
1072 }
1073 
1074 void
1075 p9100_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1076 {
1077 	struct rasops_info *ri = cookie;
1078 	struct p9100_screen *scr = ri->ri_hw;
1079 	struct p9100_softc *sc = scr->sc;
1080 	int32_t x, ys, yd, width, height;
1081 	int from, to, len;
1082 
1083 	from = ri->ri_cols * srcrow;
1084 	to = ri->ri_cols * dstrow;
1085 	len = ri->ri_cols * nrows;
1086 
1087 	memmove(&scr->attrs[to], &scr->attrs[from], len * sizeof(long));
1088 	memmove(&scr->chars[to], &scr->chars[from], len * sizeof(uint16_t));
1089 
1090 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1091 		x = ri->ri_xorigin;
1092 		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1093 		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1094 		width = ri->ri_emuwidth;
1095 		height = ri->ri_font->fontheight * nrows;
1096 		p9100_bitblt(sc, x, ys, x, yd, width, height, ROP_SRC);
1097 	}
1098 }
1099 
1100 void
1101 p9100_eraserows(void *cookie, int row, int nrows, long fillattr)
1102 {
1103 	struct rasops_info *ri = cookie;
1104 	struct p9100_screen *scr = ri->ri_hw;
1105 	struct p9100_softc *sc = scr->sc;
1106 	int32_t x,y,width,height,bg;
1107 	int start, end, i;
1108 
1109 	start = ri->ri_cols * row;
1110 	end = ri->ri_cols * (row + nrows);
1111 
1112 	for (i = start; i < end; i++) {
1113 		scr->attrs[i] = fillattr;
1114 		scr->chars[i] = 0x20;
1115 	}
1116 
1117 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1118 		x = ri->ri_xorigin;
1119 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1120 		width = ri->ri_emuwidth;
1121 		height = ri->ri_font->fontheight * nrows;
1122 		bg = (fillattr >> 16) & 0xff;
1123 		p9100_rectfill(sc, x, y, width, height, bg);
1124 	}
1125 }
1126 
1127 int
1128 p9100_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
1129 {
1130 	if ((fg == 0) && (bg == 0))
1131 	{
1132 		fg = WS_DEFAULT_FG;
1133 		bg = WS_DEFAULT_BG;
1134 	}
1135 	if (flags & WSATTR_REVERSE) {
1136 		*attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 |
1137 		    (flags & 0xff) << 8;
1138 	} else
1139 		*attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 |
1140 		    (flags & 0xff) << 8;
1141 	return 0;
1142 }
1143 
1144 /*
1145  * wsdisplay_accessops
1146  */
1147 
1148 int
1149 p9100_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1150 {
1151 	struct p9100_softc *sc = v;
1152 	struct wsdisplay_fbinfo *wdf;
1153 	struct p9100_screen *ms = sc->active;
1154 
1155 	switch (cmd) {
1156 		case WSDISPLAYIO_GTYPE:
1157 			*(u_int *)data = WSDISPLAY_TYPE_SB_P9100;
1158 			return 0;
1159 
1160 		case FBIOGVIDEO:
1161 		case WSDISPLAYIO_GVIDEO:
1162 			*(int *)data = p9100_get_video(sc);
1163 			return 0;
1164 
1165 		case WSDISPLAYIO_SVIDEO:
1166 		case FBIOSVIDEO:
1167 			p9100_set_video(sc, *(int *)data);
1168 			return 0;
1169 
1170 		case WSDISPLAYIO_GINFO:
1171 			wdf = (void *)data;
1172 			wdf->height = ms->ri.ri_height;
1173 			wdf->width = ms->ri.ri_width;
1174 			wdf->depth = ms->ri.ri_depth;
1175 			wdf->cmsize = 256;
1176 			return 0;
1177 
1178 		case WSDISPLAYIO_GETCMAP:
1179 			return p9100_getcmap(sc, (struct wsdisplay_cmap *)data);
1180 
1181 		case WSDISPLAYIO_PUTCMAP:
1182 			return p9100_putcmap(sc, (struct wsdisplay_cmap *)data);
1183 
1184 		case WSDISPLAYIO_SMODE:
1185 			{
1186 				int new_mode = *(int*)data;
1187 				if (new_mode != sc->sc_mode)
1188 				{
1189 					sc->sc_mode = new_mode;
1190 					if (new_mode == WSDISPLAYIO_MODE_EMUL)
1191 					{
1192 						p9100_init_engine(sc);
1193 						p9100loadcmap(sc,0,256);
1194 						p9100_restore_screen(ms,
1195 						    ms->type, ms->chars);
1196 						p9100_cursor(ms, ms->cursoron,
1197 						    ms->cursorrow,
1198 						    ms->cursorcol);
1199 					}
1200 				}
1201 			}
1202 	}
1203 	return EPASSTHROUGH;
1204 }
1205 
1206 paddr_t
1207 p9100_mmap(void *v, off_t offset, int prot)
1208 {
1209 	struct p9100_softc *sc = v;
1210 	paddr_t pa;
1211 
1212 	/* 'regular' framebuffer mmap()ing */
1213 	if (offset < sc->sc_fb_psize) {
1214 		pa = bus_space_mmap(sc->sc_bustag, sc->sc_fb_paddr + offset, 0,
1215 		    prot, BUS_SPACE_MAP_LINEAR);
1216 		return pa;
1217 	}
1218 
1219 	if ((offset >= sc->sc_fb_paddr) && (offset < (sc->sc_fb_paddr +
1220 	    sc->sc_fb_psize))) {
1221 		pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot,
1222 		    BUS_SPACE_MAP_LINEAR);
1223 		return pa;
1224 	}
1225 
1226 	if ((offset >= sc->sc_ctl_paddr) && (offset < (sc->sc_ctl_paddr +
1227 	    sc->sc_ctl_psize))) {
1228 		pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot,
1229 		    BUS_SPACE_MAP_LINEAR);
1230 		return pa;
1231 	}
1232 
1233 	return -1;
1234 }
1235 
1236 void
1237 p9100_init_screen(struct p9100_softc *sc, struct p9100_screen *scr,
1238     int existing, long *defattr)
1239 {
1240 	struct rasops_info *ri = &scr->ri;
1241 	int cnt;
1242 
1243 	scr->sc = sc;
1244 	/*scr->type = type;*/
1245 	scr->dispoffset = 0;
1246 	scr->cursorcol = 0;
1247 	scr->cursorrow = 0;
1248 	scr->cursordrawn=0;
1249 
1250 	ri->ri_depth = sc->sc_depth << 3;
1251 	ri->ri_width = sc->sc_width;
1252 	ri->ri_height = sc->sc_height;
1253 	ri->ri_stride = sc->sc_stride;
1254 	ri->ri_flg = RI_CENTER;
1255 
1256 	ri->ri_bits = bus_space_vaddr(sc->sc_bustag, sc->sc_fb_memh);
1257 
1258 #ifdef DEBUG_P9100
1259 	printf("addr: %08lx\n",(ulong)ri->ri_bits);
1260 #endif
1261 	rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
1262 	ri->ri_caps = WSSCREEN_WSCOLORS;
1263 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
1264 		    sc->sc_width / ri->ri_font->fontwidth);
1265 
1266 	p9100_allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr);
1267 
1268 	/*
1269 	 * we allocate both chars and attributes in one chunk, attributes first
1270 	 * because they have the (potentially) bigger alignment
1271 	 */
1272 	cnt=ri->ri_rows * ri->ri_cols;
1273 	scr->attrs = (long *)malloc(cnt * (sizeof(long) + sizeof(uint16_t)),
1274 	    M_DEVBUF, M_WAITOK);
1275 	scr->chars = (uint16_t *)&scr->attrs[cnt];
1276 
1277 	/* enable acceleration */
1278 	ri->ri_hw = scr;
1279 	ri->ri_ops.copyrows = p9100_copyrows;
1280 	ri->ri_ops.copycols = p9100_copycols;
1281 	ri->ri_ops.eraserows = p9100_eraserows;
1282 	ri->ri_ops.erasecols = p9100_erasecols;
1283 	ri->ri_ops.cursor = p9100_cursor;
1284 	ri->ri_ops.allocattr = p9100_allocattr;
1285 #ifdef PNOZZ_SOFT_PUTCHAR
1286 	if (sc->putchar == NULL)
1287 		sc->putchar=ri->ri_ops.putchar;
1288 #endif
1289 	ri->ri_ops.putchar = p9100_putchar;
1290 
1291 	if (existing) {
1292 		scr->active = 1;
1293 	} else {
1294 		scr->active = 0;
1295 	}
1296 
1297 	p9100_eraserows(&scr->ri, 0, ri->ri_rows, *defattr);
1298 
1299 	LIST_INSERT_HEAD(&sc->screens, scr, next);
1300 }
1301 
1302 int
1303 p9100_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1304     int *curxp, int *curyp, long *defattrp)
1305 {
1306 	struct p9100_softc *sc = v;
1307 	struct p9100_screen *scr;
1308 
1309 	scr = malloc(sizeof(struct p9100_screen), M_DEVBUF, M_WAITOK | M_ZERO);
1310 	p9100_init_screen(sc, scr, 0, defattrp);
1311 
1312 	if (sc->active == NULL) {
1313 		scr->active = 1;
1314 		sc->active = scr;
1315 		sc->currenttype = type;
1316 	}
1317 
1318 	*cookiep = scr;
1319 	*curxp = scr->cursorcol;
1320 	*curyp = scr->cursorrow;
1321 	return 0;
1322 }
1323 
1324 void
1325 p9100_free_screen(void *v, void *cookie)
1326 {
1327 	struct p9100_softc *sc = v;
1328 	struct p9100_screen *scr = cookie;
1329 
1330 	LIST_REMOVE(scr, next);
1331 	if (scr != &p9100_console_screen) {
1332 		free(scr->attrs, M_DEVBUF);
1333 		free(scr, M_DEVBUF);
1334 	} else
1335 		panic("p9100_free_screen: console");
1336 
1337 	if (sc->active == scr)
1338 		sc->active = 0;
1339 }
1340 
1341 int
1342 p9100_show_screen(void *v, void *cookie, int waitok,
1343     void (*cb)(void *, int, int), void *cbarg)
1344 {
1345 	struct p9100_softc *sc = v;
1346 	struct p9100_screen *scr, *oldscr;
1347 
1348 	scr = cookie;
1349 	oldscr = sc->active;
1350 	if (scr == oldscr)
1351 		return 0;
1352 
1353 	sc->wanted = scr;
1354 	sc->switchcb = cb;
1355 	sc->switchcbarg = cbarg;
1356 	if (cb) {
1357 		callout_reset(&sc->switch_callout, 0,
1358 		    (void(*)(void *))p9100_switch_screen, sc);
1359 		return EAGAIN;
1360 	}
1361 
1362 	p9100_switch_screen(sc);
1363 	return 0;
1364 }
1365 
1366 int
1367 p9100_putcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm)
1368 {
1369 	u_int index = cm->index;
1370 	u_int count = cm->count;
1371 	int i, error;
1372 	u_char rbuf[256], gbuf[256], bbuf[256];
1373 	u_char *r, *g, *b;
1374 
1375 	printf("putcmap: %d %d\n",index, count);
1376 	if (cm->index >= 256 || cm->count > 256 ||
1377 	    (cm->index + cm->count) > 256)
1378 		return EINVAL;
1379 	error = copyin(cm->red, &rbuf[index], count);
1380 	if (error)
1381 		return error;
1382 	error = copyin(cm->green, &gbuf[index], count);
1383 	if (error)
1384 		return error;
1385 	error = copyin(cm->blue, &bbuf[index], count);
1386 	if (error)
1387 		return error;
1388 
1389 	r = &rbuf[index];
1390 	g = &gbuf[index];
1391 	b = &bbuf[index];
1392 
1393 	for (i = 0; i < count; i++) {
1394 		sc->sc_cmap.cm_map[index][0] = *r;
1395 		sc->sc_cmap.cm_map[index][1] = *g;
1396 		sc->sc_cmap.cm_map[index][2] = *b;
1397 		index++;
1398 		r++, g++, b++;
1399 	}
1400 	p9100loadcmap(sc, 0, 256);
1401 	return 0;
1402 }
1403 
1404 int
1405 p9100_getcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm)
1406 {
1407 	u_int index = cm->index;
1408 	u_int count = cm->count;
1409 	int error, i;
1410 	uint8_t red[256],green[256],blue[256];
1411 
1412 	if (index >= 255 || count > 256 || index + count > 256)
1413 		return EINVAL;
1414 
1415 	i = index;
1416 	while (i < (index + count)) {
1417 		red[i] = sc->sc_cmap.cm_map[i][0];
1418 		green[i] = sc->sc_cmap.cm_map[i][1];
1419 		blue[i] = sc->sc_cmap.cm_map[i][2];
1420 		i++;
1421 	}
1422 	error = copyout(&red[index],   cm->red,   count);
1423 	if (error)
1424 		return error;
1425 	error = copyout(&green[index], cm->green, count);
1426 	if (error)
1427 		return error;
1428 	error = copyout(&blue[index],  cm->blue,  count);
1429 	if (error)
1430 		return error;
1431 
1432 	return 0;
1433 }
1434 
1435 #if 0
1436 int
1437 p9100_load_font(void *v, void *cookie, struct wsdisplay_font *data)
1438 {
1439 
1440 	return 0;
1441 }
1442 #endif
1443 
1444 int
1445 p9100_intr(void *arg)
1446 {
1447 	/*p9100_softc *sc=arg;
1448 	printf(".");*/
1449 	return 1;
1450 }
1451