xref: /netbsd-src/sys/arch/vax/vsa/gpx.c (revision 15a984a0d95c8f96abe9717ee6241762c55dc106)
1 /*	$NetBSD: gpx.c,v 1.1 2023/02/06 13:13:05 tsutsui Exp $ */
2 /*	$OpenBSD: gpx.c,v 1.25 2014/12/23 21:39:12 miod Exp $	*/
3 /*
4  * Copyright (c) 2006 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice, this permission notice, and the disclaimer below
9  * appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 /*-
20  * Copyright (c) 1988 Regents of the University of California.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  *
47  *	@(#)qd.c	7.1 (Berkeley) 6/28/91
48  */
49 
50 /************************************************************************
51 *									*
52 *			Copyright (c) 1985-1988 by			*
53 *		Digital Equipment Corporation, Maynard, MA		*
54 *			All rights reserved.				*
55 *									*
56 *   This software is furnished under a license and may be used and	*
57 *   copied  only  in accordance with the terms of such license and	*
58 *   with the  inclusion  of  the  above  copyright  notice.   This	*
59 *   software  or  any  other copies thereof may not be provided or	*
60 *   otherwise made available to any other person.  No title to and	*
61 *   ownership of the software is hereby transferred.			*
62 *									*
63 *   The information in this software is subject to change  without	*
64 *   notice  and should not be construed as a commitment by Digital	*
65 *   Equipment Corporation.						*
66 *									*
67 *   Digital assumes no responsibility for the use  or  reliability	*
68 *   of its software on equipment which is not supplied by Digital.	*
69 *									*
70 *************************************************************************/
71 
72 /*
73  * Driver for the GPX color option on VAXstation 3100, based on the
74  * MicroVAX II qdss driver.
75  *
76  * The frame buffer memory itself is not directly accessible (unlike
77  * the on-board monochrome smg frame buffer), and writes through the
78  * Dragon chip can only happen in multiples of 16 pixels, horizontally.
79  *
80  * Because of this limitation, the font image is copied to offscreen
81  * memory (which there is plenty of), and screen to screen blt operations
82  * are done for everything.
83  */
84 
85 #include "dzkbd.h"
86 #include "wsdisplay.h"
87 
88 #include <sys/param.h>
89 #include <sys/device.h>
90 #include <sys/systm.h>
91 #include <sys/kmem.h>
92 #include <sys/conf.h>
93 
94 #include <machine/sid.h>
95 #include <machine/cpu.h>
96 #include <machine/ka420.h>
97 #include <machine/scb.h>
98 #include <machine/vsbus.h>
99 #include <machine/qdreg.h>
100 
101 #include <dev/cons.h>
102 
103 #include <dev/dec/dzreg.h>
104 #include <dev/dec/dzvar.h>
105 #include <dev/dec/dzkbdvar.h>
106 
107 #include <dev/wscons/wsconsio.h>
108 #include <dev/wscons/wscons_callbacks.h>
109 #include <dev/wscons/wsdisplayvar.h>
110 #include <dev/rasops/rasops.h>
111 #include <dev/wsfont/wsfont.h>
112 
113 #if 0
114 #include <dev/ic/bt458reg.h>
115 #include <dev/ic/dc503reg.h>
116 #endif
117 
118 #define	GPXADDR		0x3c000000	/* base address on VAXstation 3100 */
119 
120 #define	GPX_ADDER_OFFSET	0x0000
121 #define	GPX_VDAC_OFFSET		0x0300
122 #define	GPX_CURSOR_OFFSET	0x0400	/* DC503 */
123 #define	GPX_READBACK_OFFSET	0x0500
124 
125 #define	GPX_WIDTH	1024
126 #define	GPX_VISHEIGHT	864
127 #define	GPX_HEIGHT	2048
128 
129 /* XXX these should be in <dev/ic/bt458reg.h> */
130 /*
131  * Brooktree Bt451, Bt457, Bt458 register definitions
132  */
133 #define BT_OV0	0x00		/* overlay 0 */
134 #define BT_OV1	0x01		/* overlay 1 */
135 #define BT_OV2	0x02		/* overlay 2 */
136 #define BT_OV3	0x03		/* overlay 3 */
137 #define BT_RMR	0x04		/* read mask */
138 #define BT_BMR	0x05		/* blink mask */
139 #define BT_CR	0x06		/* control */
140 #define BT_CTR	0x07		/* control/test */
141 
142 #define BTCR_MPLX_5		0x80	/* multiplex select, 5:1 */
143 #define BTCR_MPLX_4		0x00	/* multiplex select, 4:1 */
144 #define BTCR_RAMENA		0x40	/* use color palette RAM */
145 #define BTCR_BLINK_M		0x30	/* blink mask */
146 #define BTCR_BLINK_1648		0x00	/*  16 on, 48 off */
147 #define BTCR_BLINK_1616		0x10	/*  16 on, 16 off */
148 #define BTCR_BLINK_3232		0x20	/*  32 on, 32 off */
149 #define BTCR_BLINK_6464		0x30	/*  64 on, 64 off */
150 #define BTCR_BLINKENA_OV1	0x08	/* OV1 blink enable */
151 #define BTCR_BLINKENA_OV0	0x04	/* OV0 blink enable */
152 #define BTCR_DISPENA_OV1	0x02	/* OV1 display enable */
153 #define BTCR_DISPENA_OV0	0x01	/* OV0 display enable */
154 
155 #define BTCTR_R_ENA		0x01	/* red channel enable */
156 #define BTCTR_G_ENA		0x02	/* green channel enable */
157 #define BTCTR_B_ENA		0x04	/* blue channel enable */
158 #define BTCTR_NIB_M		0x08	/* nibble mask: */
159 #define BTCTR_NIB_LOW		0x08	/*  low */
160 #define BTCTR_NIB_HIGH		0x00	/*  high */
161 
162 /* 4 plane option RAMDAC */
163 struct	ramdac4 {
164 	uint16_t	colormap[16];
165 	uint8_t		unknown[0x20];
166 	uint16_t	cursormap[4];
167 	uint8_t		unknown2[0x18];
168 	uint16_t	control;
169 #define	RAMDAC4_INIT	0x0047
170 #define	RAMDAC4_ENABLE	0x0002
171 };
172 
173 /* 8 plane option RAMDAC - Bt458 or compatible */
174 struct	ramdac8 {
175 	uint16_t	address;
176 	uint16_t	cmapdata;
177 	uint16_t	control;
178 	uint16_t	omapdata;
179 };
180 
181 static int gpx_match(device_t, cfdata_t, void *);
182 static void gpx_attach(device_t, device_t, void *);
183 
184 struct	gpx_screen {
185 	struct rasops_info ss_ri;
186 	int		ss_console;
187 	u_int		ss_depth;
188 	u_int		ss_gpr;		/* font glyphs per row */
189 	struct adder	*ss_adder;
190 	void		*ss_vdac;
191 	uint8_t		ss_cmap[256 * 3];
192 #if 0
193 	struct dc503reg	*ss_cursor;
194 	uint16_t	ss_curcmd;
195 #endif
196 };
197 
198 /* for console */
199 struct gpx_screen gpx_consscr;
200 
201 struct	gpx_softc {
202 	device_t sc_dev;
203 	struct gpx_screen *sc_scr;
204 	int	sc_nscreens;
205 };
206 
207 CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc),
208     gpx_match, gpx_attach, NULL, NULL);
209 
210 struct wsscreen_descr gpx_stdscreen = {
211 	"std",
212 };
213 
214 const struct wsscreen_descr *_gpx_scrlist[] = {
215 	&gpx_stdscreen,
216 };
217 
218 const struct wsscreen_list gpx_screenlist = {
219 	sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *),
220 	_gpx_scrlist,
221 };
222 
223 static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
224 static paddr_t gpx_mmap(void *, void *, off_t, int);
225 static int gpx_alloc_screen(void *, const struct wsscreen_descr *,
226     void **, int *, int *, long *);
227 static void gpx_free_screen(void *, void *);
228 static int gpx_show_screen(void *, void *, int,
229     void (*) (void *, int, int), void *);
230 
231 const struct wsdisplay_accessops gpx_accessops = {
232 	.ioctl = gpx_ioctl,
233 	.mmap = gpx_mmap,
234 	.alloc_screen = gpx_alloc_screen,
235 	.free_screen = gpx_free_screen,
236 	.show_screen = gpx_show_screen,
237 	.load_font = NULL
238 };
239 
240 static void gpx_clear_screen(struct gpx_screen *);
241 static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int);
242 static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int);
243 static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *);
244 static void gpx_loadcmap(struct gpx_screen *, int, int);
245 static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *);
246 static void gpx_resetcmap(struct gpx_screen *);
247 static void gpx_reset_viper(struct gpx_screen *);
248 static int gpx_setup_screen(struct gpx_screen *);
249 static void gpx_upload_font(struct gpx_screen *);
250 static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t);
251 static int gpx_wait(struct gpx_screen *, int);
252 
253 static void gpx_copycols(void *, int, int, int, int);
254 static void gpx_copyrows(void *, int, int, int);
255 static void gpx_do_cursor(struct rasops_info *);
256 static void gpx_erasecols(void *, int, int, int, long);
257 static void gpx_eraserows(void *, int, int, long);
258 static void gpx_putchar(void *, int, int, u_int, long);
259 
260 /*
261  * Autoconf glue
262  */
263 
264 int
265 gpx_match(device_t parent, cfdata_t match, void *aux)
266 {
267 	struct vsbus_attach_args *va = aux;
268 	volatile struct adder *adder;
269 	vaddr_t tmp;
270 	u_int depth;
271 	u_short status;
272 
273 	switch (vax_boardtype) {
274 	default:
275 		return 0;
276 
277 	case VAX_BTYP_410:
278 	case VAX_BTYP_420:
279 	case VAX_BTYP_43:
280 		if (va->va_paddr != GPXADDR)
281 			return 0;
282 
283 		/* not present on microvaxes */
284 		if ((vax_confdata & KA420_CFG_MULTU) != 0)
285 			return 0;
286 
287 		if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
288 			return 0;
289 		break;
290 	}
291 
292 	/* Check for hardware */
293 	adder = (volatile struct adder *)
294 	    vax_map_physmem(va->va_paddr + GPX_ADDER_OFFSET, 1);
295 	if (adder == NULL)
296 		return 0;
297 	adder->status = 0;
298 	status = adder->status;
299 	vax_unmap_physmem((vaddr_t)adder, 1);
300 	if (status == offsetof(struct adder, status))
301 		return 0;
302 
303 	/* Check for a recognized color depth */
304 	tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
305 	if (tmp == 0L)
306 		return 0;
307 	depth = (*(volatile uint16_t *)tmp) & 0x00f0;
308 	vax_unmap_physmem(tmp, 1);
309 	if (depth != 0x00f0 && depth != 0x0080)
310 		return 0;
311 
312 	/* when already running as console, always fake things */
313 	if ((vax_confdata & KA420_CFG_L3CON) == 0
314 #if NWSDISPLAY > 0
315 	    && cn_tab->cn_putc == wsdisplay_cnputc
316 #endif
317 	) {
318 		struct vsbus_softc *sc = device_private(parent);
319 		sc->sc_mask = 0x08;
320 		scb_fake(0x44, 0x15);
321 	} else {
322 		adder = (struct adder *)vax_map_physmem(va->va_paddr +
323 		    GPX_ADDER_OFFSET, 1);
324 		if (adder == NULL)
325 			return 0;
326 		adder->interrupt_enable = FRAME_SYNC;
327 		DELAY(100000);	/* enough to get a retrace interrupt */
328 		adder->interrupt_enable = 0;
329 		vax_unmap_physmem((vaddr_t)adder, 1);
330 	}
331 	return 20;
332 }
333 
334 void
335 gpx_attach(device_t parent, device_t self, void *aux)
336 {
337 	struct gpx_softc *sc = device_private(self);
338 	struct vsbus_attach_args *va = aux;
339 	struct gpx_screen *scr;
340 	struct wsemuldisplaydev_attach_args aa;
341 	int console;
342 	vaddr_t tmp;
343 
344 	sc->sc_dev = self;
345 	console =
346 #if NWSDISPLAY > 0
347 	    (vax_confdata & KA420_CFG_L3CON) == 0 &&
348 	    cn_tab->cn_putc == wsdisplay_cnputc;
349 #else
350 	    (vax_confdata & KA420_CFG_L3CON) == 0;
351 #endif
352 	if (console) {
353 		scr = &gpx_consscr;
354 		sc->sc_nscreens = 1;
355 	} else {
356 		scr = kmem_zalloc(sizeof(*scr), KM_SLEEP);
357 
358 		tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
359 		if (tmp == 0L) {
360 			printf(": can not probe depth\n");
361 			goto bad1;
362 		}
363 		scr->ss_depth = (*(uint16_t *)tmp & 0x00f0) == 0x00f0 ? 4 : 8;
364 		vax_unmap_physmem(tmp, 1);
365 
366 		scr->ss_adder = (struct adder *)vax_map_physmem(va->va_paddr +
367 		    GPX_ADDER_OFFSET, 1);
368 		if (scr->ss_adder == NULL) {
369 			aprint_error(": can not map frame buffer registers\n");
370 			goto bad1;
371 		}
372 
373 		scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr +
374 		    GPX_VDAC_OFFSET, 1);
375 		if (scr->ss_vdac == NULL) {
376 			aprint_error(": can not map RAMDAC\n");
377 			goto bad2;
378 		}
379 
380 #if 0
381 		scr->ss_cursor =
382 		    (struct dc503reg *)vax_map_physmem(va->va_paddr +
383 		    GPX_CURSOR_OFFSET, 1);
384 		if (scr->ss_cursor == NULL) {
385 			aprint_error(": can not map cursor chip\n");
386 			goto bad3;
387 		}
388 #endif
389 
390 		if (gpx_setup_screen(scr) != 0) {
391 			aprint_error(": initialization failed\n");
392 			goto bad4;
393 		}
394 	}
395 	sc->sc_scr = scr;
396 
397 	aprint_normal("\n");
398 	aprint_normal_dev(self, "%dx%d %d plane color framebuffer\n",
399 	    GPX_WIDTH, GPX_VISHEIGHT, scr->ss_depth);
400 
401 	aa.console = console;
402 	aa.scrdata = &gpx_screenlist;
403 	aa.accessops = &gpx_accessops;
404 	aa.accesscookie = sc;
405 
406 	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
407 
408 	return;
409 
410  bad4:
411 #if 0
412 	vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1);
413  bad3:
414 #endif
415 	vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1);
416  bad2:
417 	vax_unmap_physmem((vaddr_t)scr->ss_adder, 1);
418  bad1:
419 	kmem_free(scr, sizeof(*scr));
420 }
421 
422 /*
423  * wsdisplay accessops
424  */
425 
426 int
427 gpx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
428 {
429 	struct gpx_softc *sc = v;
430 	struct gpx_screen *ss = sc->sc_scr;
431 	struct wsdisplay_fbinfo *wdf;
432 	struct wsdisplay_cmap *cm;
433 	int error;
434 
435 	switch (cmd) {
436 	case WSDISPLAYIO_GTYPE:
437 		*(u_int *)data = WSDISPLAY_TYPE_GPX;
438 		break;
439 
440 	case WSDISPLAYIO_GINFO:
441 		wdf = (struct wsdisplay_fbinfo *)data;
442 		wdf->height = ss->ss_ri.ri_height;
443 		wdf->width = ss->ss_ri.ri_width;
444 		wdf->depth = ss->ss_depth;
445 		wdf->cmsize = 1 << ss->ss_depth;
446 		break;
447 
448 	case WSDISPLAYIO_GETCMAP:
449 		cm = (struct wsdisplay_cmap *)data;
450 		error = gpx_getcmap(ss, cm);
451 		if (error != 0)
452 			return error;
453 		break;
454 	case WSDISPLAYIO_PUTCMAP:
455 		cm = (struct wsdisplay_cmap *)data;
456 		error = gpx_putcmap(ss, cm);
457 		if (error != 0)
458 			return error;
459 		gpx_loadcmap(ss, cm->index, cm->count);
460 		break;
461 
462 	case WSDISPLAYIO_GVIDEO:
463 	case WSDISPLAYIO_SVIDEO:
464 		break;
465 
466 	case WSDISPLAYIO_LINEBYTES:	/* no linear mapping */
467 		return -1;
468 
469 	default:
470 		return EPASSTHROUGH;
471 	}
472 	return 0;
473 }
474 
475 paddr_t
476 gpx_mmap(void *v, void *vs, off_t offset, int prot)
477 {
478 
479 	return -1;
480 }
481 
482 int
483 gpx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
484     int *curxp, int *curyp, long *defattrp)
485 {
486 	struct gpx_softc *sc = v;
487 	struct gpx_screen *ss = sc->sc_scr;
488 	struct rasops_info *ri = &ss->ss_ri;
489 
490 	if (sc->sc_nscreens > 0)
491 		return ENOMEM;
492 
493 	*cookiep = ri;
494 	*curxp = *curyp = 0;
495 	ri->ri_ops.allocattr(ri, 0, 0, 0, defattrp);
496 	sc->sc_nscreens++;
497 
498 	return 0;
499 }
500 
501 void
502 gpx_free_screen(void *v, void *cookie)
503 {
504 	struct gpx_softc *sc = v;
505 
506 	sc->sc_nscreens--;
507 }
508 
509 int
510 gpx_show_screen(void *v, void *cookie, int waitok,
511     void (*cb)(void *, int, int), void *cbarg)
512 {
513 
514 	return 0;
515 }
516 
517 /*
518  * wsdisplay emulops
519  */
520 
521 void
522 gpx_putchar(void *v, int row, int col, u_int uc, long attr)
523 {
524 	struct rasops_info *ri = v;
525 	struct gpx_screen *ss = ri->ri_hw;
526 	struct wsdisplay_font *font = ri->ri_font;
527 	int dx, dy, sx, sy, fg, bg, ul;
528 
529 	rasops_unpack_attr(attr, &fg, &bg, &ul);
530 
531 	/* find where to output the glyph... */
532 	dx = col * font->fontwidth + ri->ri_xorigin;
533 	dy = row * font->fontheight + ri->ri_yorigin;
534 	/* ... and where to pick it from */
535 	uc -= font->firstchar;
536 	sx = (uc % ss->ss_gpr) * font->stride * NBBY;
537 	sy = GPX_HEIGHT - (1 + uc / ss->ss_gpr) * font->fontheight;
538 
539 	/* setup VIPER operand control registers */
540 	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
541 	gpx_viper_write(ss, SRC1_OCR_B,
542 	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
543 	gpx_viper_write(ss, DST_OCR_B,
544 	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
545 	gpx_viper_write(ss, MASK_1, 0xffff);
546 	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
547 	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
548 	ss->ss_adder->x_clip_min = 0;
549 	ss->ss_adder->x_clip_max = GPX_WIDTH;
550 	ss->ss_adder->y_clip_min = 0;
551 	ss->ss_adder->y_clip_max = GPX_VISHEIGHT;
552 	/* load DESTINATION origin and vectors */
553 	ss->ss_adder->fast_dest_dy = 0;
554 	ss->ss_adder->slow_dest_dx = 0;
555 	ss->ss_adder->error_1 = 0;
556 	ss->ss_adder->error_2 = 0;
557 	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
558 	gpx_wait(ss, RASTEROP_COMPLETE);
559 	ss->ss_adder->destination_x = dx;
560 	ss->ss_adder->fast_dest_dx = font->fontwidth;
561 	ss->ss_adder->destination_y = dy;
562 	ss->ss_adder->slow_dest_dy = font->fontheight;
563 	/* load SOURCE origin and vectors */
564 	ss->ss_adder->source_1_x = sx;
565 	ss->ss_adder->source_1_y = sy;
566 	ss->ss_adder->source_1_dx = font->fontwidth;
567 	ss->ss_adder->source_1_dy = font->fontheight;
568 	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
569 
570 	if (ul != 0) {
571 		gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth,
572 		    1, attr, LF_R3);	/* fg fill */
573 	}
574 }
575 
576 void
577 gpx_copycols(void *v, int row, int src, int dst, int cnt)
578 {
579 	struct rasops_info *ri = v;
580 	struct gpx_screen *ss = ri->ri_hw;
581 	struct wsdisplay_font *font = ri->ri_font;
582 	int sx, y, dx, w, h;
583 
584 	sx = ri->ri_xorigin + src * font->fontwidth;
585 	dx = ri->ri_xorigin + dst * font->fontwidth;
586 	w = cnt * font->fontwidth;
587 	y = ri->ri_yorigin + row * font->fontheight;
588 	h = font->fontheight;
589 
590 	gpx_copyrect(ss, sx, y, dx, y, w, h);
591 }
592 
593 void
594 gpx_erasecols(void *v, int row, int col, int cnt, long attr)
595 {
596 	struct rasops_info *ri = v;
597 	struct gpx_screen *ss = ri->ri_hw;
598 	struct wsdisplay_font *font = ri->ri_font;
599 	int x, y, dx, dy;
600 
601 	x = ri->ri_xorigin + col * font->fontwidth;
602 	dx = cnt * font->fontwidth;
603 	y = ri->ri_yorigin + row * font->fontheight;
604 	dy = font->fontheight;
605 
606 	gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
607 }
608 
609 void
610 gpx_copyrows(void *v, int src, int dst, int cnt)
611 {
612 	struct rasops_info *ri = v;
613 	struct gpx_screen *ss = ri->ri_hw;
614 	struct wsdisplay_font *font = ri->ri_font;
615 	int x, sy, dy, w, h;
616 
617 	x = ri->ri_xorigin;
618 	w = ri->ri_emustride;
619 	sy = ri->ri_yorigin + src * font->fontheight;
620 	dy = ri->ri_yorigin + dst * font->fontheight;
621 	h = cnt * font->fontheight;
622 
623 	gpx_copyrect(ss, x, sy, x, dy, w, h);
624 }
625 
626 void
627 gpx_eraserows(void *v, int row, int cnt, long attr)
628 {
629 	struct rasops_info *ri = v;
630 	struct gpx_screen *ss = ri->ri_hw;
631 	struct wsdisplay_font *font = ri->ri_font;
632 	int x, y, dx, dy;
633 
634 	x = ri->ri_xorigin;
635 	dx = ri->ri_emustride;
636 	y = ri->ri_yorigin + row * font->fontheight;
637 	dy = cnt * font->fontheight;
638 
639 	gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
640 }
641 
642 void
643 gpx_do_cursor(struct rasops_info *ri)
644 {
645 	struct gpx_screen *ss = ri->ri_hw;
646 	int x, y, w, h;
647 
648 	x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
649 	y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
650 	w = ri->ri_font->fontwidth;
651 	h = ri->ri_font->fontheight;
652 
653 	gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4);	/* invert */
654 }
655 
656 /*
657  * low-level programming routines
658  */
659 
660 int
661 gpx_wait(struct gpx_screen *ss, int bits)
662 {
663 	int i;
664 
665 	ss->ss_adder->status = 0;
666 	for (i = 100000; i != 0; i--) {
667 		if ((ss->ss_adder->status & bits) == bits)
668 			break;
669 		DELAY(1);
670 	}
671 
672 	return i == 0;
673 }
674 
675 int
676 gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val)
677 {
678 	if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 &&
679 	    gpx_wait(ss, TX_READY) == 0) {
680 		ss->ss_adder->id_data = val;
681 		ss->ss_adder->command = ID_LOAD | reg;
682 		return 0;
683 	}
684 #ifdef DEBUG
685 	if (ss->ss_console == 0)	/* don't make things worse! */
686 		printf("gpx_viper_write failure, reg %x val %x\n", reg, val);
687 #endif
688 	return 1;
689 }
690 
691 /* Initialize the damned beast. Straight from qdss. */
692 void
693 gpx_reset_viper(struct gpx_screen *ss)
694 {
695 	int i;
696 
697 	ss->ss_adder->interrupt_enable = 0;
698 	ss->ss_adder->command = CANCEL;
699 	/* set monitor timing */
700 	ss->ss_adder->x_scan_count_0 = 0x2800;
701 	ss->ss_adder->x_scan_count_1 = 0x1020;
702 	ss->ss_adder->x_scan_count_2 = 0x003a;
703 	ss->ss_adder->x_scan_count_3 = 0x38f0;
704 	ss->ss_adder->x_scan_count_4 = 0x6128;
705 	ss->ss_adder->x_scan_count_5 = 0x093a;
706 	ss->ss_adder->x_scan_count_6 = 0x313c;
707 	ss->ss_adder->sync_phase_adj = 0x0100;
708 	ss->ss_adder->x_scan_conf = 0x00c8;
709 	/*
710 	 * got a bug in second pass ADDER! lets take care of it...
711 	 *
712 	 * normally, just use the code in the following bug fix code, but to
713 	 * make repeated demos look pretty, load the registers as if there was
714 	 * no bug and then test to see if we are getting sync
715 	 */
716 	ss->ss_adder->y_scan_count_0 = 0x135f;
717 	ss->ss_adder->y_scan_count_1 = 0x3363;
718 	ss->ss_adder->y_scan_count_2 = 0x2366;
719 	ss->ss_adder->y_scan_count_3 = 0x0388;
720 	/*
721 	 * if no sync, do the bug fix code
722 	 */
723 	if (gpx_wait(ss, FRAME_SYNC) != 0) {
724 		/*
725 		 * First load all Y scan registers with very short frame and
726 		 * wait for scroll service.  This guarantees at least one SYNC
727 		 * to fix the pass 2 Adder initialization bug (synchronizes
728 		 * XCINCH with DMSEEDH)
729 		 */
730 		ss->ss_adder->y_scan_count_0 = 0x01;
731 		ss->ss_adder->y_scan_count_1 = 0x01;
732 		ss->ss_adder->y_scan_count_2 = 0x01;
733 		ss->ss_adder->y_scan_count_3 = 0x01;
734 		/* delay at least 1 full frame time */
735 		gpx_wait(ss, FRAME_SYNC);
736 		gpx_wait(ss, FRAME_SYNC);
737 		/*
738 		 * now load the REAL sync values (in reverse order just to
739 		 * be safe).
740 		 */
741 		ss->ss_adder->y_scan_count_3 = 0x0388;
742 		ss->ss_adder->y_scan_count_2 = 0x2366;
743 		ss->ss_adder->y_scan_count_1 = 0x3363;
744 		ss->ss_adder->y_scan_count_0 = 0x135f;
745 	}
746 	/* zero the index registers */
747 	ss->ss_adder->x_index_pending = 0;
748 	ss->ss_adder->y_index_pending = 0;
749 	ss->ss_adder->x_index_new = 0;
750 	ss->ss_adder->y_index_new = 0;
751 	ss->ss_adder->x_index_old = 0;
752 	ss->ss_adder->y_index_old = 0;
753 	ss->ss_adder->pause = 0;
754 	/* set rasterop mode to normal pen down */
755 	ss->ss_adder->rasterop_mode =
756 	    DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
757 	/* set the rasterop registers to default values */
758 	ss->ss_adder->source_1_dx = 1;
759 	ss->ss_adder->source_1_dy = 1;
760 	ss->ss_adder->source_1_x = 0;
761 	ss->ss_adder->source_1_y = 0;
762 	ss->ss_adder->destination_x = 0;
763 	ss->ss_adder->destination_y = 0;
764 	ss->ss_adder->fast_dest_dx = 1;
765 	ss->ss_adder->fast_dest_dy = 0;
766 	ss->ss_adder->slow_dest_dx = 0;
767 	ss->ss_adder->slow_dest_dy = 1;
768 	ss->ss_adder->error_1 = 0;
769 	ss->ss_adder->error_2 = 0;
770 	/* scale factor = UNITY */
771 	ss->ss_adder->fast_scale = UNITY;
772 	ss->ss_adder->slow_scale = UNITY;
773 	/* set the source 2 parameters */
774 	ss->ss_adder->source_2_x = 0;
775 	ss->ss_adder->source_2_y = 0;
776 	ss->ss_adder->source_2_size = 0x0022;
777 	/* initialize plane addresses for eight vipers */
778 	for (i = 0; i < 8; i++) {
779 		gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i);
780 		gpx_viper_write(ss, PLANE_ADDRESS, i);
781 	}
782 	/* initialize the external registers. */
783 	gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
784 	gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff);
785 	/* initialize resolution mode */
786 	gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c);	/* bus width = 16 */
787 	gpx_viper_write(ss, RESOLUTION_MODE, 0x0000);	/* one bit/pixel */
788 	/* initialize viper registers */
789 	gpx_viper_write(ss, SCROLL_CONSTANT,
790 	    SCROLL_ENABLE | VIPER_LEFT | VIPER_UP);
791 	gpx_viper_write(ss, SCROLL_FILL, 0x0000);
792 	/* set clipping and scrolling limits to full screen */
793 	gpx_wait(ss, ADDRESS_COMPLETE);
794 	ss->ss_adder->x_clip_min = 0;
795 	ss->ss_adder->x_clip_max = GPX_WIDTH;
796 	ss->ss_adder->y_clip_min = 0;
797 	ss->ss_adder->y_clip_max = GPX_HEIGHT;
798 	ss->ss_adder->scroll_x_min = 0;
799 	ss->ss_adder->scroll_x_max = GPX_WIDTH;
800 	ss->ss_adder->scroll_y_min = 0;
801 	ss->ss_adder->scroll_y_max = GPX_HEIGHT;
802 	gpx_wait(ss, FRAME_SYNC);	/* wait at LEAST 1 full frame */
803 	gpx_wait(ss, FRAME_SYNC);
804 	ss->ss_adder->x_index_pending = 0;
805 	ss->ss_adder->y_index_pending = 0;
806 	ss->ss_adder->x_index_new = 0;
807 	ss->ss_adder->y_index_new = 0;
808 	ss->ss_adder->x_index_old = 0;
809 	ss->ss_adder->y_index_old = 0;
810 	gpx_wait(ss, ADDRESS_COMPLETE);
811 	gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000);
812 	gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000);
813 	/* set source and the mask register to all ones */
814 	gpx_viper_write(ss, SOURCE, 0xffff);
815 	gpx_viper_write(ss, MASK_1, 0xffff);
816 	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
817 	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
818 	/* initialize Operand Control Register banks for fill command */
819 	gpx_viper_write(ss, SRC1_OCR_A, EXT_NONE | INT_M1_M2  | NO_ID | WAIT);
820 	gpx_viper_write(ss, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
821 	gpx_viper_write(ss, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
822 	gpx_viper_write(ss, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
823 	gpx_viper_write(ss, SRC2_OCR_B, EXT_NONE | INT_M1_M2  | NO_ID | NO_WAIT);
824 	gpx_viper_write(ss, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
825 
826 	/*
827 	 * Init Logic Unit Function registers.
828 	 */
829 	/* putchar */
830 	gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
831 	/* erase{cols,rows} */
832 	gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS);
833 	/* underline */
834 	gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES);
835 	/* cursor */
836 	gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D);
837 }
838 
839 /* Clear the whole screen. Straight from qdss. */
840 void
841 gpx_clear_screen(struct gpx_screen *ss)
842 {
843 
844 	ss->ss_adder->x_limit = GPX_WIDTH;
845 	ss->ss_adder->y_limit = GPX_HEIGHT;
846 	ss->ss_adder->y_offset_pending = 0;
847 	gpx_wait(ss, FRAME_SYNC);	/* wait at LEAST 1 full frame */
848 	gpx_wait(ss, FRAME_SYNC);
849 	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
850 	gpx_wait(ss, FRAME_SYNC);
851 	gpx_wait(ss, FRAME_SYNC);
852 	ss->ss_adder->y_offset_pending = GPX_VISHEIGHT;
853 	gpx_wait(ss, FRAME_SYNC);
854 	gpx_wait(ss, FRAME_SYNC);
855 	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
856 	gpx_wait(ss, FRAME_SYNC);
857 	gpx_wait(ss, FRAME_SYNC);
858 	ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT;
859 	gpx_wait(ss, FRAME_SYNC);
860 	gpx_wait(ss, FRAME_SYNC);
861 	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
862 	gpx_wait(ss, FRAME_SYNC);
863 	gpx_wait(ss, FRAME_SYNC);
864 	ss->ss_adder->y_offset_pending = 0;	 /* back to normal */
865 	gpx_wait(ss, FRAME_SYNC);
866 	gpx_wait(ss, FRAME_SYNC);
867 	ss->ss_adder->x_limit = GPX_WIDTH;
868 	ss->ss_adder->y_limit = GPX_VISHEIGHT;
869 }
870 
871 int
872 gpx_setup_screen(struct gpx_screen *ss)
873 {
874 	struct rasops_info *ri = &ss->ss_ri;
875 	int cookie;
876 
877 	memset(ri, 0, sizeof(*ri));
878 	ri->ri_depth = 8;	/* masquerade as a 8 bit device for rasops */
879 	ri->ri_width = GPX_WIDTH;
880 	ri->ri_height = GPX_VISHEIGHT;
881 	ri->ri_stride = GPX_WIDTH;
882 	ri->ri_flg = RI_CENTER;		/* no RI_CLEAR as ri_bits is NULL! */
883 	ri->ri_hw = ss;
884 	if (ss == &gpx_consscr)
885 		ri->ri_flg |= RI_NO_AUTO;
886 
887 	/*
888 	 * We can not let rasops select our font, because we need to use
889 	 * a font with right-to-left bit order on this frame buffer.
890 	 */
891 	wsfont_init();
892 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
893 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
894 	if (cookie < 0)
895 		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L,
896 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
897 	if (cookie < 0)
898 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
899 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
900 	if (cookie < 0)
901 		return -1;
902 	if (wsfont_lock(cookie, &ri->ri_font) != 0)
903 		return -1;
904 	ri->ri_wsfcookie = cookie;
905 
906 	/*
907 	 * Ask for an unholy big display, rasops will trim this to more
908 	 * reasonable values.
909 	 */
910 	if (rasops_init(ri, 160, 160) != 0)
911 		return -1;
912 
913 	/*
914 	 * Override the rasops emulops.
915 	 */
916 	ri->ri_ops.copyrows = gpx_copyrows;
917 	ri->ri_ops.copycols = gpx_copycols;
918 	ri->ri_ops.eraserows = gpx_eraserows;
919 	ri->ri_ops.erasecols = gpx_erasecols;
920 	ri->ri_ops.putchar = gpx_putchar;
921 	ri->ri_do_cursor = gpx_do_cursor;
922 
923 	gpx_stdscreen.ncols = ri->ri_cols;
924 	gpx_stdscreen.nrows = ri->ri_rows;
925 	gpx_stdscreen.textops = &ri->ri_ops;
926 	gpx_stdscreen.fontwidth = ri->ri_font->fontwidth;
927 	gpx_stdscreen.fontheight = ri->ri_font->fontheight;
928 	gpx_stdscreen.capabilities = ri->ri_caps;
929 
930 	/*
931 	 * Initialize RAMDAC.
932 	 */
933 	if (ss->ss_depth == 8) {
934 		struct ramdac8 *rd = ss->ss_vdac;
935 		rd->address = BT_CR;
936 		rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4;
937 	} else {
938 		struct ramdac4 *rd = ss->ss_vdac;
939 		rd->control = RAMDAC4_INIT;
940 	}
941 
942 	/*
943 	 * Put the ADDER and VIPER in a good state.
944 	 */
945 	gpx_reset_viper(ss);
946 
947 	/*
948 	 * Initialize colormap.
949 	 */
950 	gpx_resetcmap(ss);
951 
952 	/*
953 	 * Clear display (including non-visible area), in 864 lines chunks.
954 	 */
955 	gpx_clear_screen(ss);
956 
957 	/*
958 	 * Copy our font to the offscreen area.
959 	 */
960 	gpx_upload_font(ss);
961 
962 #if 0
963 	ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI;
964 #endif
965 
966 	return 0;
967 }
968 
969 /*
970  * Copy the selected wsfont to non-visible frame buffer area.
971  * This is necessary since the only way to send data to the frame buffer
972  * is through the ID interface, which is slow and needs 16 bit wide data.
973  * Adapted from qdss.
974  */
975 void
976 gpx_upload_font(struct gpx_screen *ss)
977 {
978 	struct rasops_info *ri = &ss->ss_ri;
979 	struct wsdisplay_font *font = ri->ri_font;
980 	uint8_t *fontbits, *fb;
981 	u_int remaining, nchars, row;
982 	u_int i, j;
983 	uint16_t data;
984 
985 	/* setup VIPER operand control registers */
986 
987 	gpx_viper_write(ss, MASK_1, 0xffff);
988 	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
989 	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
990 
991 	gpx_viper_write(ss, SRC1_OCR_B,
992 	    EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
993 	gpx_viper_write(ss, SRC2_OCR_B,
994 	    EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
995 	gpx_viper_write(ss, DST_OCR_B,
996 	    EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
997 
998 	ss->ss_adder->rasterop_mode =
999 	    DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
1000 	gpx_wait(ss, RASTEROP_COMPLETE);
1001 
1002 	/*
1003 	 * Load font data. The font is uploaded in 8 or 16 bit wide cells, on
1004 	 * as many ``lines'' as necessary at the end of the display.
1005 	 */
1006 	ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars);
1007 	if (ss->ss_gpr & 1)
1008 		ss->ss_gpr--;
1009 	fontbits = font->data;
1010 	for (row = 1, remaining = font->numchars; remaining != 0;
1011 	    row++, remaining -= nchars) {
1012 		nchars = MIN(ss->ss_gpr, remaining);
1013 
1014 		ss->ss_adder->destination_x = 0;
1015 		ss->ss_adder->destination_y =
1016 		    GPX_HEIGHT - row * font->fontheight;
1017 		ss->ss_adder->fast_dest_dx = nchars * 16;
1018 		ss->ss_adder->slow_dest_dy = font->fontheight;
1019 
1020 		/* setup for processor to bitmap xfer */
1021 		gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
1022 		ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/
1023 
1024 		/* iteratively do the processor to bitmap xfer */
1025 		for (i = font->fontheight; i != 0; i--) {
1026 			fb = fontbits;
1027 			fontbits += font->stride;
1028 			/* PTOB a scan line */
1029 			for (j = nchars; j != 0; j--) {
1030 				/* PTOB one scan of a char cell */
1031 				if (font->stride == 1) {
1032 					data = *fb;
1033 					fb += font->fontheight;
1034 					/*
1035 					 * Do not access past font memory if
1036 					 * it has an odd number of characters
1037 					 * and this is the last pair.
1038 					 */
1039 					if (j != 1 || (nchars & 1) == 0 ||
1040 					    remaining != nchars) {
1041 						data |= ((uint16_t)*fb) << 8;
1042 						fb += font->fontheight;
1043 					}
1044 				} else {
1045 					data =
1046 					    fb[0] | (((uint16_t)fb[1]) << 8);
1047 					fb += font->fontheight * font->stride;
1048 				}
1049 
1050 				gpx_wait(ss, TX_READY);
1051 				ss->ss_adder->id_data = data;
1052 			}
1053 		}
1054 		fontbits += (nchars - 1) * font->stride * font->fontheight;
1055 	}
1056 }
1057 
1058 void
1059 gpx_copyrect(struct gpx_screen *ss,
1060     int sx, int sy, int dx, int dy, int w, int h)
1061 {
1062 
1063 	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
1064 		continue;
1065 	gpx_viper_write(ss, MASK_1, 0xffff);
1066 	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
1067 	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
1068 	gpx_viper_write(ss, SRC1_OCR_B,
1069 	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1070 	gpx_viper_write(ss, DST_OCR_B,
1071 	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1072 	ss->ss_adder->fast_dest_dy = 0;
1073 	ss->ss_adder->slow_dest_dx = 0;
1074 	ss->ss_adder->error_1 = 0;
1075 	ss->ss_adder->error_2 = 0;
1076 	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1077 	gpx_wait(ss, RASTEROP_COMPLETE);
1078 	ss->ss_adder->destination_x = dx;
1079 	ss->ss_adder->fast_dest_dx = w;
1080 	ss->ss_adder->destination_y = dy;
1081 	ss->ss_adder->slow_dest_dy = h;
1082 	ss->ss_adder->source_1_x = sx;
1083 	ss->ss_adder->source_1_dx = w;
1084 	ss->ss_adder->source_1_y = sy;
1085 	ss->ss_adder->source_1_dy = h;
1086 	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
1087 }
1088 
1089 /*
1090  * Fill a rectangle with the given attribute and function (i.e. rop).
1091  */
1092 void
1093 gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr,
1094     u_int function)
1095 {
1096 	int fg, bg;
1097 
1098 	rasops_unpack_attr(attr, &fg, &bg, NULL);
1099 
1100 	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
1101 	gpx_viper_write(ss, MASK_1, 0xffff);
1102 	gpx_viper_write(ss, SOURCE, 0xffff);
1103 	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
1104 	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
1105 	gpx_viper_write(ss, SRC1_OCR_B,
1106 	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1107 	gpx_viper_write(ss, DST_OCR_B,
1108 	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1109 	ss->ss_adder->fast_dest_dx = 0;
1110 	ss->ss_adder->fast_dest_dy = 0;
1111 	ss->ss_adder->slow_dest_dx = 0;
1112 	ss->ss_adder->error_1 = 0;
1113 	ss->ss_adder->error_2 = 0;
1114 	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1115 	gpx_wait(ss, RASTEROP_COMPLETE);
1116 	ss->ss_adder->destination_x = x;
1117 	ss->ss_adder->fast_dest_dx = dx;
1118 	ss->ss_adder->destination_y = y;
1119 	ss->ss_adder->slow_dest_dy = dy;
1120 	ss->ss_adder->source_1_x = x;
1121 	ss->ss_adder->source_1_dx = dx;
1122 	ss->ss_adder->source_1_y = y;
1123 	ss->ss_adder->source_1_dy = dy;
1124 	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function;
1125 }
1126 
1127 /*
1128  * Colormap handling routines
1129  */
1130 
1131 int
1132 gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1133 {
1134 	u_int index = cm->index, count = cm->count, i;
1135 	u_int colcount = 1 << ss->ss_depth;
1136 	int error;
1137 	uint8_t ramp[256], *c, *r;
1138 
1139 	if (index >= colcount || count > colcount - index)
1140 		return EINVAL;
1141 
1142 	/* extract reds */
1143 	c = ss->ss_cmap + 0 + index * 3;
1144 	for (i = count, r = ramp; i != 0; i--)
1145 		*r++ = *c << (8 - ss->ss_depth), c += 3;
1146 	if ((error = copyout(ramp, cm->red, count)) != 0)
1147 		return error;
1148 
1149 	/* extract greens */
1150 	c = ss->ss_cmap + 1 + index * 3;
1151 	for (i = count, r = ramp; i != 0; i--)
1152 		*r++ = *c << (8 - ss->ss_depth), c += 3;
1153 	if ((error = copyout(ramp, cm->green, count)) != 0)
1154 		return error;
1155 
1156 	/* extract blues */
1157 	c = ss->ss_cmap + 2 + index * 3;
1158 	for (i = count, r = ramp; i != 0; i--)
1159 		*r++ = *c << (8 - ss->ss_depth), c += 3;
1160 	if ((error = copyout(ramp, cm->blue, count)) != 0)
1161 		return error;
1162 
1163 	return 0;
1164 }
1165 
1166 int
1167 gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1168 {
1169 	u_int index = cm->index, count = cm->count;
1170 	u_int colcount = 1 << ss->ss_depth;
1171 	int i, error;
1172 	uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;
1173 
1174 	if (index >= colcount || count > colcount - index)
1175 		return EINVAL;
1176 
1177 	if ((error = copyin(cm->red, r, count)) != 0)
1178 		return error;
1179 	if ((error = copyin(cm->green, g, count)) != 0)
1180 		return error;
1181 	if ((error = copyin(cm->blue, b, count)) != 0)
1182 		return error;
1183 
1184 	nr = r, ng = g, nb = b;
1185 	c = ss->ss_cmap + index * 3;
1186 	for (i = count; i != 0; i--) {
1187 		*c++ = *nr++ >> (8 - ss->ss_depth);
1188 		*c++ = *ng++ >> (8 - ss->ss_depth);
1189 		*c++ = *nb++ >> (8 - ss->ss_depth);
1190 	}
1191 
1192 	return 0;
1193 }
1194 
1195 void
1196 gpx_loadcmap(struct gpx_screen *ss, int from, int count)
1197 {
1198 	uint8_t *cmap = ss->ss_cmap;
1199 	int i, color12;
1200 
1201 	gpx_wait(ss, FRAME_SYNC);
1202 	if (ss->ss_depth == 8) {
1203 		struct ramdac8 *rd = ss->ss_vdac;
1204 
1205 		cmap += from * 3;
1206 		rd->address = from;
1207 		for (i = 0; i < count * 3; i++)
1208 			rd->cmapdata = *cmap++;
1209 	} else {
1210 		struct ramdac4 *rd = ss->ss_vdac;
1211 
1212 		cmap = ss->ss_cmap + from;
1213 		for (i = from; i < from + count; i++) {
1214 			color12  = (*cmap++ >> 4) << 0;
1215 			color12 |= (*cmap++ >> 4) << 8;
1216 			color12 |= (*cmap++ >> 4) << 4;
1217 			rd->colormap[i] = color12;
1218 		}
1219 	}
1220 }
1221 
1222 void
1223 gpx_resetcmap(struct gpx_screen *ss)
1224 {
1225 
1226 	if (ss->ss_depth == 8)
1227 		memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap));
1228 	else {
1229 		memcpy(ss->ss_cmap, rasops_cmap, 8 * 3);
1230 		memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3);
1231 	}
1232 	gpx_loadcmap(ss, 0, 1 << ss->ss_depth);
1233 
1234 	/*
1235 	 * On the 4bit RAMDAC, make the hardware cursor black on black
1236 	 */
1237 	if (ss->ss_depth != 8) {
1238 		struct ramdac4 *rd = ss->ss_vdac;
1239 
1240 		rd->cursormap[0] = rd->cursormap[1] =
1241 		    rd->cursormap[2] = rd->cursormap[3] = 0x0000;
1242 	}
1243 }
1244 
1245 /*
1246  * Console support code
1247  */
1248 
1249 cons_decl(gpx);
1250 
1251 /*
1252  * Called very early to setup the glass tty as console.
1253  * Because it's called before the VM system is initialized, virtual memory
1254  * for the framebuffer can be stolen directly without disturbing anything.
1255  */
1256 void
1257 gpxcnprobe(struct consdev *cndev)
1258 {
1259 	extern vaddr_t virtual_avail;
1260 	extern const struct cdevsw wsdisplay_cdevsw;
1261 	volatile struct adder *adder;
1262 	vaddr_t tmp;
1263 	int depth;
1264 	u_short status;
1265 
1266 	switch (vax_boardtype) {
1267 	case VAX_BTYP_410:
1268 	case VAX_BTYP_420:
1269 	case VAX_BTYP_43:
1270 		if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0)
1271 			break; /* doesn't use graphics console */
1272 
1273 		if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
1274 			break; /* no color option */
1275 
1276 		/* Check for hardware */
1277 		tmp = virtual_avail;
1278 		ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1);
1279 		adder = (struct adder *)tmp;
1280 		adder->status = 0;
1281 		status = adder->status;
1282 		iounaccess(tmp, 1);
1283 		if (status == offsetof(struct adder, status))
1284 			return;
1285 
1286 		/* Check for a recognized color depth */
1287 		tmp = virtual_avail;
1288 		ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1289 		depth = *(uint16_t *)
1290 		    (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0;
1291 		iounaccess(tmp, 1);
1292 		if (depth != 0x00f0 && depth != 0x0080)
1293 			return;
1294 
1295 		cndev->cn_pri = CN_INTERNAL;
1296 		cndev->cn_dev =
1297 		    makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
1298 		break;
1299 
1300 	default:
1301 		break;
1302 	}
1303 }
1304 
1305 /*
1306  * Called very early to setup the glass tty as console.
1307  * Because it's called before the VM system is initialized, virtual memory
1308  * for the framebuffer can be stolen directly without disturbing anything.
1309  */
1310 void
1311 gpxcninit(struct consdev *cndev)
1312 {
1313 	struct gpx_screen *ss = &gpx_consscr;
1314 	extern vaddr_t virtual_avail;
1315 	vaddr_t ova;
1316 	long defattr;
1317 	struct rasops_info *ri;
1318 
1319 	ova = virtual_avail;
1320 
1321 	ioaccess(virtual_avail,
1322 	    vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1323 	ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail +
1324 	    (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8;
1325 
1326 	ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1);
1327 	ss->ss_adder = (struct adder *)virtual_avail;
1328 	virtual_avail += VAX_NBPG;
1329 
1330 	ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1);
1331 	ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET));
1332 	virtual_avail += VAX_NBPG;
1333 
1334 #if 0
1335 	ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1);
1336 	ss->ss_cursor = (struct dc503reg *)virtual_avail;
1337 	virtual_avail += VAX_NBPG;
1338 #endif
1339 
1340 	virtual_avail = round_page(virtual_avail);
1341 
1342 	/* this had better not fail */
1343 	if (gpx_setup_screen(ss) != 0) {
1344 #if 0
1345 		iounaccess((vaddr_t)ss->ss_cursor, 1);
1346 #endif
1347 		iounaccess((vaddr_t)ss->ss_vdac, 1);
1348 		iounaccess((vaddr_t)ss->ss_adder, 1);
1349 		virtual_avail = ova;
1350 		return;
1351 	}
1352 
1353 	ri = &ss->ss_ri;
1354 	ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
1355 	wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr);
1356 	cn_tab->cn_pri = CN_INTERNAL;
1357 
1358 #if NDZKBD > 0
1359 	dzkbd_cnattach(0); /* Connect keyboard and screen together */
1360 #endif
1361 }
1362