gpx.c revision 1.2 1 /* $NetBSD: gpx.c,v 1.2 2024/02/03 16:18:10 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 struct gpx_screen {
182 struct rasops_info ss_ri;
183 int ss_console;
184 u_int ss_depth;
185 u_int ss_gpr; /* font glyphs per row */
186 struct adder *ss_adder;
187 void *ss_vdac;
188 uint8_t ss_cmap[256 * 3];
189 #if 0
190 struct dc503reg *ss_cursor;
191 uint16_t ss_curcmd;
192 #endif
193 };
194
195 struct gpx_softc {
196 device_t sc_dev;
197 struct gpx_screen *sc_scr;
198 int sc_nscreens;
199 };
200
201 static int gpx_match(device_t, cfdata_t, void *);
202 static void gpx_attach(device_t, device_t, void *);
203
204 static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
205 static paddr_t gpx_mmap(void *, void *, off_t, int);
206 static int gpx_alloc_screen(void *, const struct wsscreen_descr *,
207 void **, int *, int *, long *);
208 static void gpx_free_screen(void *, void *);
209 static int gpx_show_screen(void *, void *, int,
210 void (*) (void *, int, int), void *);
211
212 static void gpx_putchar(void *, int, int, u_int, long);
213 static void gpx_copycols(void *, int, int, int, int);
214 static void gpx_erasecols(void *, int, int, int, long);
215 static void gpx_copyrows(void *, int, int, int);
216 static void gpx_eraserows(void *, int, int, long);
217 static void gpx_do_cursor(struct rasops_info *);
218
219 static int gpx_wait(struct gpx_screen *, int);
220 static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t);
221 static void gpx_reset_viper(struct gpx_screen *);
222 static void gpx_clear_screen(struct gpx_screen *);
223 static int gpx_setup_screen(struct gpx_screen *);
224 static void gpx_upload_font(struct gpx_screen *);
225 static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int);
226 static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int);
227 static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *);
228 static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *);
229 static void gpx_loadcmap(struct gpx_screen *, int, int);
230 static void gpx_resetcmap(struct gpx_screen *);
231
232 /* for console */
233 struct gpx_screen gpx_consscr;
234
235 CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc),
236 gpx_match, gpx_attach, NULL, NULL);
237
238 struct wsscreen_descr gpx_stdscreen = {
239 "std",
240 };
241
242 const struct wsscreen_descr *_gpx_scrlist[] = {
243 &gpx_stdscreen,
244 };
245
246 const struct wsscreen_list gpx_screenlist = {
247 sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *),
248 _gpx_scrlist,
249 };
250
251 const struct wsdisplay_accessops gpx_accessops = {
252 .ioctl = gpx_ioctl,
253 .mmap = gpx_mmap,
254 .alloc_screen = gpx_alloc_screen,
255 .free_screen = gpx_free_screen,
256 .show_screen = gpx_show_screen,
257 .load_font = NULL
258 };
259
260 /*
261 * Autoconf glue
262 */
263
264 static 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 static 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 static 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 static paddr_t
476 gpx_mmap(void *v, void *vs, off_t offset, int prot)
477 {
478
479 return -1;
480 }
481
482 static 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 static void
502 gpx_free_screen(void *v, void *cookie)
503 {
504 struct gpx_softc *sc = v;
505
506 sc->sc_nscreens--;
507 }
508
509 static 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 static 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 continue;
542 gpx_viper_write(ss, SRC1_OCR_B,
543 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
544 gpx_viper_write(ss, DST_OCR_B,
545 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
546 gpx_viper_write(ss, MASK_1, 0xffff);
547 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
548 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
549 ss->ss_adder->x_clip_min = 0;
550 ss->ss_adder->x_clip_max = GPX_WIDTH;
551 ss->ss_adder->y_clip_min = 0;
552 ss->ss_adder->y_clip_max = GPX_VISHEIGHT;
553 /* load DESTINATION origin and vectors */
554 ss->ss_adder->fast_dest_dy = 0;
555 ss->ss_adder->slow_dest_dx = 0;
556 ss->ss_adder->error_1 = 0;
557 ss->ss_adder->error_2 = 0;
558 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
559 gpx_wait(ss, RASTEROP_COMPLETE);
560 ss->ss_adder->destination_x = dx;
561 ss->ss_adder->fast_dest_dx = font->fontwidth;
562 ss->ss_adder->destination_y = dy;
563 ss->ss_adder->slow_dest_dy = font->fontheight;
564 /* load SOURCE origin and vectors */
565 ss->ss_adder->source_1_x = sx;
566 ss->ss_adder->source_1_y = sy;
567 ss->ss_adder->source_1_dx = font->fontwidth;
568 ss->ss_adder->source_1_dy = font->fontheight;
569 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
570
571 if (ul != 0) {
572 gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth,
573 1, attr, LF_R3); /* fg fill */
574 }
575 }
576
577 static void
578 gpx_copycols(void *v, int row, int src, int dst, int cnt)
579 {
580 struct rasops_info *ri = v;
581 struct gpx_screen *ss = ri->ri_hw;
582 struct wsdisplay_font *font = ri->ri_font;
583 int sx, y, dx, w, h;
584
585 sx = ri->ri_xorigin + src * font->fontwidth;
586 dx = ri->ri_xorigin + dst * font->fontwidth;
587 w = cnt * font->fontwidth;
588 y = ri->ri_yorigin + row * font->fontheight;
589 h = font->fontheight;
590
591 gpx_copyrect(ss, sx, y, dx, y, w, h);
592 }
593
594 static void
595 gpx_erasecols(void *v, int row, int col, int cnt, long attr)
596 {
597 struct rasops_info *ri = v;
598 struct gpx_screen *ss = ri->ri_hw;
599 struct wsdisplay_font *font = ri->ri_font;
600 int x, y, dx, dy;
601
602 x = ri->ri_xorigin + col * font->fontwidth;
603 dx = cnt * font->fontwidth;
604 y = ri->ri_yorigin + row * font->fontheight;
605 dy = font->fontheight;
606
607 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
608 }
609
610 static void
611 gpx_copyrows(void *v, int src, int dst, int cnt)
612 {
613 struct rasops_info *ri = v;
614 struct gpx_screen *ss = ri->ri_hw;
615 struct wsdisplay_font *font = ri->ri_font;
616 int x, sy, dy, w, h;
617
618 x = ri->ri_xorigin;
619 w = ri->ri_emustride;
620 sy = ri->ri_yorigin + src * font->fontheight;
621 dy = ri->ri_yorigin + dst * font->fontheight;
622 h = cnt * font->fontheight;
623
624 gpx_copyrect(ss, x, sy, x, dy, w, h);
625 }
626
627 static void
628 gpx_eraserows(void *v, int row, int cnt, long attr)
629 {
630 struct rasops_info *ri = v;
631 struct gpx_screen *ss = ri->ri_hw;
632 struct wsdisplay_font *font = ri->ri_font;
633 int x, y, dx, dy;
634
635 x = ri->ri_xorigin;
636 dx = ri->ri_emustride;
637 y = ri->ri_yorigin + row * font->fontheight;
638 dy = cnt * font->fontheight;
639
640 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
641 }
642
643 static void
644 gpx_do_cursor(struct rasops_info *ri)
645 {
646 struct gpx_screen *ss = ri->ri_hw;
647 int x, y, w, h;
648
649 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
650 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
651 w = ri->ri_font->fontwidth;
652 h = ri->ri_font->fontheight;
653
654 gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4); /* invert */
655 }
656
657 /*
658 * low-level programming routines
659 */
660
661 static int
662 gpx_wait(struct gpx_screen *ss, int bits)
663 {
664 int i;
665
666 ss->ss_adder->status = 0;
667 for (i = 100000; i != 0; i--) {
668 if ((ss->ss_adder->status & bits) == bits)
669 break;
670 DELAY(1);
671 }
672
673 return i == 0;
674 }
675
676 static int
677 gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val)
678 {
679 if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 &&
680 gpx_wait(ss, TX_READY) == 0) {
681 ss->ss_adder->id_data = val;
682 ss->ss_adder->command = ID_LOAD | reg;
683 return 0;
684 }
685 #ifdef DEBUG
686 if (ss->ss_console == 0) /* don't make things worse! */
687 printf("gpx_viper_write failure, reg %x val %x\n", reg, val);
688 #endif
689 return 1;
690 }
691
692 /* Initialize the damned beast. Straight from qdss. */
693 static void
694 gpx_reset_viper(struct gpx_screen *ss)
695 {
696 int i;
697
698 ss->ss_adder->interrupt_enable = 0;
699 ss->ss_adder->command = CANCEL;
700 /* set monitor timing */
701 ss->ss_adder->x_scan_count_0 = 0x2800;
702 ss->ss_adder->x_scan_count_1 = 0x1020;
703 ss->ss_adder->x_scan_count_2 = 0x003a;
704 ss->ss_adder->x_scan_count_3 = 0x38f0;
705 ss->ss_adder->x_scan_count_4 = 0x6128;
706 ss->ss_adder->x_scan_count_5 = 0x093a;
707 ss->ss_adder->x_scan_count_6 = 0x313c;
708 ss->ss_adder->sync_phase_adj = 0x0100;
709 ss->ss_adder->x_scan_conf = 0x00c8;
710 /*
711 * got a bug in second pass ADDER! lets take care of it...
712 *
713 * normally, just use the code in the following bug fix code, but to
714 * make repeated demos look pretty, load the registers as if there was
715 * no bug and then test to see if we are getting sync
716 */
717 ss->ss_adder->y_scan_count_0 = 0x135f;
718 ss->ss_adder->y_scan_count_1 = 0x3363;
719 ss->ss_adder->y_scan_count_2 = 0x2366;
720 ss->ss_adder->y_scan_count_3 = 0x0388;
721 /*
722 * if no sync, do the bug fix code
723 */
724 if (gpx_wait(ss, FRAME_SYNC) != 0) {
725 /*
726 * First load all Y scan registers with very short frame and
727 * wait for scroll service. This guarantees at least one SYNC
728 * to fix the pass 2 Adder initialization bug (synchronizes
729 * XCINCH with DMSEEDH)
730 */
731 ss->ss_adder->y_scan_count_0 = 0x01;
732 ss->ss_adder->y_scan_count_1 = 0x01;
733 ss->ss_adder->y_scan_count_2 = 0x01;
734 ss->ss_adder->y_scan_count_3 = 0x01;
735 /* delay at least 1 full frame time */
736 gpx_wait(ss, FRAME_SYNC);
737 gpx_wait(ss, FRAME_SYNC);
738 /*
739 * now load the REAL sync values (in reverse order just to
740 * be safe).
741 */
742 ss->ss_adder->y_scan_count_3 = 0x0388;
743 ss->ss_adder->y_scan_count_2 = 0x2366;
744 ss->ss_adder->y_scan_count_1 = 0x3363;
745 ss->ss_adder->y_scan_count_0 = 0x135f;
746 }
747 /* zero the index registers */
748 ss->ss_adder->x_index_pending = 0;
749 ss->ss_adder->y_index_pending = 0;
750 ss->ss_adder->x_index_new = 0;
751 ss->ss_adder->y_index_new = 0;
752 ss->ss_adder->x_index_old = 0;
753 ss->ss_adder->y_index_old = 0;
754 ss->ss_adder->pause = 0;
755 /* set rasterop mode to normal pen down */
756 ss->ss_adder->rasterop_mode =
757 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
758 /* set the rasterop registers to default values */
759 ss->ss_adder->source_1_dx = 1;
760 ss->ss_adder->source_1_dy = 1;
761 ss->ss_adder->source_1_x = 0;
762 ss->ss_adder->source_1_y = 0;
763 ss->ss_adder->destination_x = 0;
764 ss->ss_adder->destination_y = 0;
765 ss->ss_adder->fast_dest_dx = 1;
766 ss->ss_adder->fast_dest_dy = 0;
767 ss->ss_adder->slow_dest_dx = 0;
768 ss->ss_adder->slow_dest_dy = 1;
769 ss->ss_adder->error_1 = 0;
770 ss->ss_adder->error_2 = 0;
771 /* scale factor = UNITY */
772 ss->ss_adder->fast_scale = UNITY;
773 ss->ss_adder->slow_scale = UNITY;
774 /* set the source 2 parameters */
775 ss->ss_adder->source_2_x = 0;
776 ss->ss_adder->source_2_y = 0;
777 ss->ss_adder->source_2_size = 0x0022;
778 /* initialize plane addresses for eight vipers */
779 for (i = 0; i < 8; i++) {
780 gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i);
781 gpx_viper_write(ss, PLANE_ADDRESS, i);
782 }
783 /* initialize the external registers. */
784 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
785 gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff);
786 /* initialize resolution mode */
787 gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c); /* bus width = 16 */
788 gpx_viper_write(ss, RESOLUTION_MODE, 0x0000); /* one bit/pixel */
789 /* initialize viper registers */
790 gpx_viper_write(ss, SCROLL_CONSTANT,
791 SCROLL_ENABLE | VIPER_LEFT | VIPER_UP);
792 gpx_viper_write(ss, SCROLL_FILL, 0x0000);
793 /* set clipping and scrolling limits to full screen */
794 gpx_wait(ss, ADDRESS_COMPLETE);
795 ss->ss_adder->x_clip_min = 0;
796 ss->ss_adder->x_clip_max = GPX_WIDTH;
797 ss->ss_adder->y_clip_min = 0;
798 ss->ss_adder->y_clip_max = GPX_HEIGHT;
799 ss->ss_adder->scroll_x_min = 0;
800 ss->ss_adder->scroll_x_max = GPX_WIDTH;
801 ss->ss_adder->scroll_y_min = 0;
802 ss->ss_adder->scroll_y_max = GPX_HEIGHT;
803 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */
804 gpx_wait(ss, FRAME_SYNC);
805 ss->ss_adder->x_index_pending = 0;
806 ss->ss_adder->y_index_pending = 0;
807 ss->ss_adder->x_index_new = 0;
808 ss->ss_adder->y_index_new = 0;
809 ss->ss_adder->x_index_old = 0;
810 ss->ss_adder->y_index_old = 0;
811 gpx_wait(ss, ADDRESS_COMPLETE);
812 gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000);
813 gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000);
814 /* set source and the mask register to all ones */
815 gpx_viper_write(ss, SOURCE, 0xffff);
816 gpx_viper_write(ss, MASK_1, 0xffff);
817 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
818 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
819 /* initialize Operand Control Register banks for fill command */
820 gpx_viper_write(ss, SRC1_OCR_A,
821 EXT_NONE | INT_M1_M2 | NO_ID | WAIT);
822 gpx_viper_write(ss, SRC2_OCR_A,
823 EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
824 gpx_viper_write(ss, DST_OCR_A,
825 EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
826 gpx_viper_write(ss, SRC1_OCR_B,
827 EXT_NONE | INT_SOURCE | NO_ID | WAIT);
828 gpx_viper_write(ss, SRC2_OCR_B,
829 EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT);
830 gpx_viper_write(ss, DST_OCR_B,
831 EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
832
833 /*
834 * Init Logic Unit Function registers.
835 */
836 /* putchar */
837 gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
838 /* erase{cols,rows} */
839 gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS);
840 /* underline */
841 gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES);
842 /* cursor */
843 gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D);
844 }
845
846 /* Clear the whole screen. Straight from qdss. */
847 static void
848 gpx_clear_screen(struct gpx_screen *ss)
849 {
850
851 ss->ss_adder->x_limit = GPX_WIDTH;
852 ss->ss_adder->y_limit = GPX_HEIGHT;
853 ss->ss_adder->y_offset_pending = 0;
854 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */
855 gpx_wait(ss, FRAME_SYNC);
856 ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
857 gpx_wait(ss, FRAME_SYNC);
858 gpx_wait(ss, FRAME_SYNC);
859 ss->ss_adder->y_offset_pending = GPX_VISHEIGHT;
860 gpx_wait(ss, FRAME_SYNC);
861 gpx_wait(ss, FRAME_SYNC);
862 ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
863 gpx_wait(ss, FRAME_SYNC);
864 gpx_wait(ss, FRAME_SYNC);
865 ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT;
866 gpx_wait(ss, FRAME_SYNC);
867 gpx_wait(ss, FRAME_SYNC);
868 ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
869 gpx_wait(ss, FRAME_SYNC);
870 gpx_wait(ss, FRAME_SYNC);
871 ss->ss_adder->y_offset_pending = 0; /* back to normal */
872 gpx_wait(ss, FRAME_SYNC);
873 gpx_wait(ss, FRAME_SYNC);
874 ss->ss_adder->x_limit = GPX_WIDTH;
875 ss->ss_adder->y_limit = GPX_VISHEIGHT;
876 }
877
878 static int
879 gpx_setup_screen(struct gpx_screen *ss)
880 {
881 struct rasops_info *ri = &ss->ss_ri;
882 int cookie;
883
884 memset(ri, 0, sizeof(*ri));
885 ri->ri_depth = 8; /* masquerade as a 8 bit device for rasops */
886 ri->ri_width = GPX_WIDTH;
887 ri->ri_height = GPX_VISHEIGHT;
888 ri->ri_stride = GPX_WIDTH;
889 ri->ri_flg = RI_CENTER; /* no RI_CLEAR as ri_bits is NULL! */
890 ri->ri_hw = ss;
891 if (ss == &gpx_consscr)
892 ri->ri_flg |= RI_NO_AUTO;
893
894 /*
895 * We can not let rasops select our font, because we need to use
896 * a font with right-to-left bit order on this frame buffer.
897 */
898 wsfont_init();
899 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
900 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
901 if (cookie < 0)
902 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L,
903 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
904 if (cookie < 0)
905 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
906 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
907 if (cookie < 0)
908 return -1;
909 if (wsfont_lock(cookie, &ri->ri_font) != 0)
910 return -1;
911 ri->ri_wsfcookie = cookie;
912
913 /*
914 * Ask for an unholy big display, rasops will trim this to more
915 * reasonable values.
916 */
917 if (rasops_init(ri, 160, 160) != 0)
918 return -1;
919
920 /*
921 * Override the rasops emulops.
922 */
923 ri->ri_ops.copyrows = gpx_copyrows;
924 ri->ri_ops.copycols = gpx_copycols;
925 ri->ri_ops.eraserows = gpx_eraserows;
926 ri->ri_ops.erasecols = gpx_erasecols;
927 ri->ri_ops.putchar = gpx_putchar;
928 ri->ri_do_cursor = gpx_do_cursor;
929
930 gpx_stdscreen.ncols = ri->ri_cols;
931 gpx_stdscreen.nrows = ri->ri_rows;
932 gpx_stdscreen.textops = &ri->ri_ops;
933 gpx_stdscreen.fontwidth = ri->ri_font->fontwidth;
934 gpx_stdscreen.fontheight = ri->ri_font->fontheight;
935 gpx_stdscreen.capabilities = ri->ri_caps;
936
937 /*
938 * Initialize RAMDAC.
939 */
940 if (ss->ss_depth == 8) {
941 struct ramdac8 *rd = ss->ss_vdac;
942 rd->address = BT_CR;
943 rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4;
944 } else {
945 struct ramdac4 *rd = ss->ss_vdac;
946 rd->control = RAMDAC4_INIT;
947 }
948
949 /*
950 * Put the ADDER and VIPER in a good state.
951 */
952 gpx_reset_viper(ss);
953
954 /*
955 * Initialize colormap.
956 */
957 gpx_resetcmap(ss);
958
959 /*
960 * Clear display (including non-visible area), in 864 lines chunks.
961 */
962 gpx_clear_screen(ss);
963
964 /*
965 * Copy our font to the offscreen area.
966 */
967 gpx_upload_font(ss);
968
969 #if 0
970 ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI;
971 #endif
972
973 return 0;
974 }
975
976 /*
977 * Copy the selected wsfont to non-visible frame buffer area.
978 * This is necessary since the only way to send data to the frame buffer
979 * is through the ID interface, which is slow and needs 16 bit wide data.
980 * Adapted from qdss.
981 */
982 static void
983 gpx_upload_font(struct gpx_screen *ss)
984 {
985 struct rasops_info *ri = &ss->ss_ri;
986 struct wsdisplay_font *font = ri->ri_font;
987 uint8_t *fontbits, *fb;
988 u_int remaining, nchars, row;
989 u_int i, j;
990 uint16_t data;
991
992 /* setup VIPER operand control registers */
993
994 gpx_viper_write(ss, MASK_1, 0xffff);
995 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
996 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
997
998 gpx_viper_write(ss, SRC1_OCR_B,
999 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
1000 gpx_viper_write(ss, SRC2_OCR_B,
1001 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
1002 gpx_viper_write(ss, DST_OCR_B,
1003 EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1004
1005 ss->ss_adder->rasterop_mode =
1006 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
1007 gpx_wait(ss, RASTEROP_COMPLETE);
1008
1009 /*
1010 * Load font data. The font is uploaded in 8 or 16 bit wide cells, on
1011 * as many ``lines'' as necessary at the end of the display.
1012 */
1013 ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars);
1014 if ((ss->ss_gpr & 1) != 0)
1015 ss->ss_gpr--;
1016 fontbits = font->data;
1017 for (row = 1, remaining = font->numchars; remaining != 0;
1018 row++, remaining -= nchars) {
1019 nchars = MIN(ss->ss_gpr, remaining);
1020
1021 ss->ss_adder->destination_x = 0;
1022 ss->ss_adder->destination_y =
1023 GPX_HEIGHT - row * font->fontheight;
1024 ss->ss_adder->fast_dest_dx = nchars * 16;
1025 ss->ss_adder->slow_dest_dy = font->fontheight;
1026
1027 /* setup for processor to bitmap xfer */
1028 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
1029 ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/
1030
1031 /* iteratively do the processor to bitmap xfer */
1032 for (i = font->fontheight; i != 0; i--) {
1033 fb = fontbits;
1034 fontbits += font->stride;
1035 /* PTOB a scan line */
1036 for (j = nchars; j != 0; j--) {
1037 /* PTOB one scan of a char cell */
1038 if (font->stride == 1) {
1039 data = *fb;
1040 fb += font->fontheight;
1041 /*
1042 * Do not access past font memory if
1043 * it has an odd number of characters
1044 * and this is the last pair.
1045 */
1046 if (j != 1 || (nchars & 1) == 0 ||
1047 remaining != nchars) {
1048 data |= ((uint16_t)*fb) << 8;
1049 fb += font->fontheight;
1050 }
1051 } else {
1052 data =
1053 fb[0] | (((uint16_t)fb[1]) << 8);
1054 fb += font->fontheight * font->stride;
1055 }
1056
1057 gpx_wait(ss, TX_READY);
1058 ss->ss_adder->id_data = data;
1059 }
1060 }
1061 fontbits += (nchars - 1) * font->stride * font->fontheight;
1062 }
1063 }
1064
1065 static void
1066 gpx_copyrect(struct gpx_screen *ss,
1067 int sx, int sy, int dx, int dy, int w, int h)
1068 {
1069
1070 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
1071 continue;
1072 gpx_viper_write(ss, MASK_1, 0xffff);
1073 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
1074 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
1075 gpx_viper_write(ss, SRC1_OCR_B,
1076 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1077 gpx_viper_write(ss, DST_OCR_B,
1078 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1079 ss->ss_adder->fast_dest_dy = 0;
1080 ss->ss_adder->slow_dest_dx = 0;
1081 ss->ss_adder->error_1 = 0;
1082 ss->ss_adder->error_2 = 0;
1083 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1084 gpx_wait(ss, RASTEROP_COMPLETE);
1085 ss->ss_adder->destination_x = dx;
1086 ss->ss_adder->fast_dest_dx = w;
1087 ss->ss_adder->destination_y = dy;
1088 ss->ss_adder->slow_dest_dy = h;
1089 ss->ss_adder->source_1_x = sx;
1090 ss->ss_adder->source_1_dx = w;
1091 ss->ss_adder->source_1_y = sy;
1092 ss->ss_adder->source_1_dy = h;
1093 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
1094 }
1095
1096 /*
1097 * Fill a rectangle with the given attribute and function (i.e. rop).
1098 */
1099 static void
1100 gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr,
1101 u_int function)
1102 {
1103 int fg, bg;
1104
1105 rasops_unpack_attr(attr, &fg, &bg, NULL);
1106
1107 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
1108 continue;
1109 gpx_viper_write(ss, MASK_1, 0xffff);
1110 gpx_viper_write(ss, SOURCE, 0xffff);
1111 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
1112 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
1113 gpx_viper_write(ss, SRC1_OCR_B,
1114 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1115 gpx_viper_write(ss, DST_OCR_B,
1116 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1117 ss->ss_adder->fast_dest_dx = 0;
1118 ss->ss_adder->fast_dest_dy = 0;
1119 ss->ss_adder->slow_dest_dx = 0;
1120 ss->ss_adder->error_1 = 0;
1121 ss->ss_adder->error_2 = 0;
1122 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1123 gpx_wait(ss, RASTEROP_COMPLETE);
1124 ss->ss_adder->destination_x = x;
1125 ss->ss_adder->fast_dest_dx = dx;
1126 ss->ss_adder->destination_y = y;
1127 ss->ss_adder->slow_dest_dy = dy;
1128 ss->ss_adder->source_1_x = x;
1129 ss->ss_adder->source_1_dx = dx;
1130 ss->ss_adder->source_1_y = y;
1131 ss->ss_adder->source_1_dy = dy;
1132 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function;
1133 }
1134
1135 /*
1136 * Colormap handling routines
1137 */
1138
1139 static int
1140 gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1141 {
1142 u_int index = cm->index, count = cm->count, i;
1143 u_int colcount = 1 << ss->ss_depth;
1144 int error;
1145 uint8_t ramp[256], *c, *r;
1146
1147 if (index >= colcount || count > colcount - index)
1148 return EINVAL;
1149
1150 /* extract reds */
1151 c = ss->ss_cmap + 0 + index * 3;
1152 for (i = count, r = ramp; i != 0; i--)
1153 *r++ = *c << (8 - ss->ss_depth), c += 3;
1154 if ((error = copyout(ramp, cm->red, count)) != 0)
1155 return error;
1156
1157 /* extract greens */
1158 c = ss->ss_cmap + 1 + index * 3;
1159 for (i = count, r = ramp; i != 0; i--)
1160 *r++ = *c << (8 - ss->ss_depth), c += 3;
1161 if ((error = copyout(ramp, cm->green, count)) != 0)
1162 return error;
1163
1164 /* extract blues */
1165 c = ss->ss_cmap + 2 + index * 3;
1166 for (i = count, r = ramp; i != 0; i--)
1167 *r++ = *c << (8 - ss->ss_depth), c += 3;
1168 if ((error = copyout(ramp, cm->blue, count)) != 0)
1169 return error;
1170
1171 return 0;
1172 }
1173
1174 static int
1175 gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1176 {
1177 u_int index = cm->index, count = cm->count;
1178 u_int colcount = 1 << ss->ss_depth;
1179 int i, error;
1180 uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;
1181
1182 if (index >= colcount || count > colcount - index)
1183 return EINVAL;
1184
1185 if ((error = copyin(cm->red, r, count)) != 0)
1186 return error;
1187 if ((error = copyin(cm->green, g, count)) != 0)
1188 return error;
1189 if ((error = copyin(cm->blue, b, count)) != 0)
1190 return error;
1191
1192 nr = r, ng = g, nb = b;
1193 c = ss->ss_cmap + index * 3;
1194 for (i = count; i != 0; i--) {
1195 *c++ = *nr++ >> (8 - ss->ss_depth);
1196 *c++ = *ng++ >> (8 - ss->ss_depth);
1197 *c++ = *nb++ >> (8 - ss->ss_depth);
1198 }
1199
1200 return 0;
1201 }
1202
1203 static void
1204 gpx_loadcmap(struct gpx_screen *ss, int from, int count)
1205 {
1206 uint8_t *cmap = ss->ss_cmap;
1207 int i, color12;
1208
1209 gpx_wait(ss, FRAME_SYNC);
1210 if (ss->ss_depth == 8) {
1211 struct ramdac8 *rd = ss->ss_vdac;
1212
1213 cmap += from * 3;
1214 rd->address = from;
1215 for (i = 0; i < count * 3; i++)
1216 rd->cmapdata = *cmap++;
1217 } else {
1218 struct ramdac4 *rd = ss->ss_vdac;
1219
1220 cmap = ss->ss_cmap + from;
1221 for (i = from; i < from + count; i++) {
1222 color12 = (*cmap++ >> 4) << 0;
1223 color12 |= (*cmap++ >> 4) << 8;
1224 color12 |= (*cmap++ >> 4) << 4;
1225 rd->colormap[i] = color12;
1226 }
1227 }
1228 }
1229
1230 static void
1231 gpx_resetcmap(struct gpx_screen *ss)
1232 {
1233
1234 if (ss->ss_depth == 8)
1235 memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap));
1236 else {
1237 memcpy(ss->ss_cmap, rasops_cmap, 8 * 3);
1238 memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3);
1239 }
1240 gpx_loadcmap(ss, 0, 1 << ss->ss_depth);
1241
1242 /*
1243 * On the 4bit RAMDAC, make the hardware cursor black on black
1244 */
1245 if (ss->ss_depth != 8) {
1246 struct ramdac4 *rd = ss->ss_vdac;
1247
1248 rd->cursormap[0] = rd->cursormap[1] =
1249 rd->cursormap[2] = rd->cursormap[3] = 0x0000;
1250 }
1251 }
1252
1253 /*
1254 * Console support code
1255 */
1256
1257 cons_decl(gpx);
1258
1259 /*
1260 * Called very early to setup the glass tty as console.
1261 * Because it's called before the VM system is initialized, virtual memory
1262 * for the framebuffer can be stolen directly without disturbing anything.
1263 */
1264 void
1265 gpxcnprobe(struct consdev *cndev)
1266 {
1267 extern vaddr_t virtual_avail;
1268 extern const struct cdevsw wsdisplay_cdevsw;
1269 volatile struct adder *adder;
1270 vaddr_t tmp;
1271 int depth;
1272 u_short status;
1273
1274 switch (vax_boardtype) {
1275 case VAX_BTYP_410:
1276 case VAX_BTYP_420:
1277 case VAX_BTYP_43:
1278 if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0)
1279 break; /* doesn't use graphics console */
1280
1281 if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
1282 break; /* no color option */
1283
1284 /* Check for hardware */
1285 tmp = virtual_avail;
1286 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1);
1287 adder = (struct adder *)tmp;
1288 adder->status = 0;
1289 status = adder->status;
1290 iounaccess(tmp, 1);
1291 if (status == offsetof(struct adder, status))
1292 return;
1293
1294 /* Check for a recognized color depth */
1295 tmp = virtual_avail;
1296 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1297 depth = *(uint16_t *)
1298 (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0;
1299 iounaccess(tmp, 1);
1300 if (depth != 0x00f0 && depth != 0x0080)
1301 return;
1302
1303 cndev->cn_pri = CN_INTERNAL;
1304 cndev->cn_dev =
1305 makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
1306 break;
1307
1308 default:
1309 break;
1310 }
1311 }
1312
1313 /*
1314 * Called very early to setup the glass tty as console.
1315 * Because it's called before the VM system is initialized, virtual memory
1316 * for the framebuffer can be stolen directly without disturbing anything.
1317 */
1318 void
1319 gpxcninit(struct consdev *cndev)
1320 {
1321 struct gpx_screen *ss = &gpx_consscr;
1322 extern vaddr_t virtual_avail;
1323 vaddr_t ova;
1324 long defattr;
1325 struct rasops_info *ri;
1326
1327 ova = virtual_avail;
1328
1329 ioaccess(virtual_avail,
1330 vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1331 ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail +
1332 (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8;
1333
1334 ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1);
1335 ss->ss_adder = (struct adder *)virtual_avail;
1336 virtual_avail += VAX_NBPG;
1337
1338 ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1);
1339 ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET));
1340 virtual_avail += VAX_NBPG;
1341
1342 #if 0
1343 ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1);
1344 ss->ss_cursor = (struct dc503reg *)virtual_avail;
1345 virtual_avail += VAX_NBPG;
1346 #endif
1347
1348 virtual_avail = round_page(virtual_avail);
1349
1350 /* this had better not fail */
1351 if (gpx_setup_screen(ss) != 0) {
1352 #if 0
1353 iounaccess((vaddr_t)ss->ss_cursor, 1);
1354 #endif
1355 iounaccess((vaddr_t)ss->ss_vdac, 1);
1356 iounaccess((vaddr_t)ss->ss_adder, 1);
1357 virtual_avail = ova;
1358 return;
1359 }
1360
1361 ri = &ss->ss_ri;
1362 ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
1363 wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr);
1364 cn_tab->cn_pri = CN_INTERNAL;
1365
1366 #if NDZKBD > 0
1367 dzkbd_cnattach(0); /* Connect keyboard and screen together */
1368 #endif
1369 }
1370