summaryrefslogtreecommitdiff
path: root/sys/arch/vax/vsa
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2006-07-28 21:07:06 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2006-07-28 21:07:06 +0000
commit7284eb679b3a6d016d87827d8d7e6ea7f9919f3e (patch)
treec2ec391aaa57b7798440136101e19d076bdc5eea /sys/arch/vax/vsa
parent4b4b84020b83a67e01bd1ebe5b3ea456197b3e06 (diff)
Driver for the color frame buffer option on VAXstation 3100 models 3x/4x.
Still a few rough edges to polish, but nevertheless usable; 4bpp flavour untested.
Diffstat (limited to 'sys/arch/vax/vsa')
-rw-r--r--sys/arch/vax/vsa/gpx.c1113
1 files changed, 1113 insertions, 0 deletions
diff --git a/sys/arch/vax/vsa/gpx.c b/sys/arch/vax/vsa/gpx.c
new file mode 100644
index 00000000000..e823ab47635
--- /dev/null
+++ b/sys/arch/vax/vsa/gpx.c
@@ -0,0 +1,1113 @@
+/* $OpenBSD: gpx.c,v 1.1 2006/07/28 21:07:05 miod Exp $ */
+/*
+ * Copyright (c) 2006 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice, this permission notice, and the disclaimer below
+ * appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*-
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)qd.c 7.1 (Berkeley) 6/28/91
+ */
+
+/************************************************************************
+* *
+* Copyright (c) 1985-1988 by *
+* Digital Equipment Corporation, Maynard, MA *
+* All rights reserved. *
+* *
+* This software is furnished under a license and may be used and *
+* copied only in accordance with the terms of such license and *
+* with the inclusion of the above copyright notice. This *
+* software or any other copies thereof may not be provided or *
+* otherwise made available to any other person. No title to and *
+* ownership of the software is hereby transferred. *
+* *
+* The information in this software is subject to change without *
+* notice and should not be construed as a commitment by Digital *
+* Equipment Corporation. *
+* *
+* Digital assumes no responsibility for the use or reliability *
+* of its software on equipment which is not supplied by Digital. *
+* *
+*************************************************************************/
+
+/*
+ * Driver for the GPX color option on VAXstation 3100, based on the
+ * MicroVAX II qdss driver.
+ *
+ * The frame buffer memory itself is not directly accessible (unlike
+ * the on-board monochrome smg frame buffer), and writes through the
+ * Dragon chip can only happen in multiples of 16 pixels, horizontally.
+ *
+ * Because of this limitation, the font image is copied to offscreen
+ * memory (which there is plenty of), and screen to screen blt operations
+ * are done for everything.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+
+#include <machine/sid.h>
+#include <machine/cpu.h>
+#include <machine/ka420.h>
+#include <machine/scb.h>
+#include <machine/vsbus.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wscons_callbacks.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+#include <dev/wsfont/wsfont.h>
+
+#include <dev/ic/bt458reg.h>
+/* #include <dev/ic/dc503reg.h> */
+#include <vax/qbus/qdreg.h>
+
+#define GPXADDR 0x3c000000 /* base address on VAXstation 3100 */
+
+#define GPX_ADDER_OFFSET 0x0000
+#define GPX_VDAC_OFFSET 0x0300
+#define GPX_CURSOR_OFFSET 0x0400
+#define GPX_READBACK_OFFSET 0x0500
+
+#define GPX_WIDTH 1024
+#define GPX_VISHEIGHT 864
+#define GPX_HEIGHT 2048
+
+/* 4 plane option RAMDAC */
+struct ramdac4 {
+ u_int16_t colormap[16];
+ u_int8_t unknown[0x40];
+ u_int16_t control;
+#define RAMDAC4_INIT 0x0047
+#define RAMDAC4_ENABLE 0x0002
+};
+
+/* 8 plane option RAMDAC - Bt458 or compatible */
+struct ramdac8 {
+ u_int16_t address;
+ u_int16_t cmapdata;
+ u_int16_t control;
+ u_int16_t omapdata;
+};
+
+int gpx_match(struct device *, void *, void *);
+void gpx_attach(struct device *, struct device *, void *);
+
+struct gpx_screen {
+ struct rasops_info ss_ri;
+ int ss_console;
+ u_int ss_depth;
+ u_int ss_gpr; /* font glyphs per row */
+ struct adder *ss_adder;
+ void *ss_vdac;
+ /* struct dc503reg *ss_cursor; */
+};
+
+/* for console */
+struct gpx_screen gpx_consscr;
+
+struct gpx_softc {
+ struct device sc_dev;
+ struct gpx_screen *sc_scr;
+ int sc_nscreens;
+};
+
+struct cfattach gpx_ca = {
+ sizeof(struct gpx_softc), gpx_match, gpx_attach,
+};
+
+struct cfdriver gpx_cd = {
+ NULL, "gpx", DV_DULL
+};
+
+struct wsscreen_descr gpx_stdscreen = {
+ "std",
+};
+
+const struct wsscreen_descr *_gpx_scrlist[] = {
+ &gpx_stdscreen,
+};
+
+const struct wsscreen_list gpx_screenlist = {
+ sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *),
+ _gpx_scrlist,
+};
+
+int gpx_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t gpx_mmap(void *, off_t, int);
+int gpx_alloc_screen(void *, const struct wsscreen_descr *,
+ void **, int *, int *, long *);
+void gpx_free_screen(void *, void *);
+int gpx_show_screen(void *, void *, int,
+ void (*) (void *, int, int), void *);
+void gpx_burner(void *, u_int, u_int);
+
+const struct wsdisplay_accessops gpx_accessops = {
+ gpx_ioctl,
+ gpx_mmap,
+ gpx_alloc_screen,
+ gpx_free_screen,
+ gpx_show_screen,
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ gpx_burner
+};
+
+void gpx_clear_screen(struct gpx_screen *);
+void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int);
+void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int);
+void gpx_reset_viper(struct gpx_screen *);
+int gpx_setup_screen(struct gpx_screen *);
+void gpx_upload_font(struct gpx_screen *);
+int gpx_viper_write(struct gpx_screen *, u_int, u_int16_t);
+int gpx_wait(struct gpx_screen *, int);
+
+void gpx_copycols(void *, int, int, int, int);
+void gpx_copyrows(void *, int, int, int);
+void gpx_do_cursor(struct rasops_info *);
+void gpx_erasecols(void *, int, int, int, long);
+void gpx_eraserows(void *, int, int, long);
+void gpx_putchar(void *, int, int, u_int, long);
+
+/*
+ * Autoconf glue
+ */
+
+int
+gpx_match(struct device *parent, void *vcf, void *aux)
+{
+ struct vsbus_attach_args *va = aux;
+ struct adder *adder;
+ vaddr_t tmp;
+ u_int depth;
+
+ switch (vax_boardtype) {
+ default:
+ return (0);
+
+ case VAX_BTYP_410:
+ case VAX_BTYP_420:
+ case VAX_BTYP_43:
+ if (va->va_paddr != GPXADDR)
+ return (0);
+
+ /* not present on microvaxes */
+ if ((vax_confdata & KA420_CFG_MULTU) != 0)
+ return (0);
+
+ if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
+ return (0);
+ break;
+ }
+
+ /* Check for a recognized color depth */
+ tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
+ if (tmp == 0L)
+ return (0);
+ depth = (*(u_int16_t *)tmp) & 0x00f0;
+ vax_unmap_physmem(tmp, 1);
+ if (depth != 0x00f0 && depth != 0x0080)
+ return (0);
+
+ adder = (struct adder *)vax_map_physmem(va->va_paddr +
+ GPX_ADDER_OFFSET, 1);
+ if (adder == NULL)
+ return (0);
+ adder->interrupt_enable = VSYNC;
+ DELAY(100000); /* enough to get a retrace interrupt */
+ adder->interrupt_enable = 0;
+ vax_unmap_physmem((vaddr_t)adder, 1);
+ return (20);
+}
+
+void
+gpx_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gpx_softc *sc = (struct gpx_softc *)self;
+ struct vsbus_attach_args *va = aux;
+ struct gpx_screen *scr;
+ struct wsemuldisplaydev_attach_args aa;
+ int console;
+ vaddr_t tmp;
+
+ console = (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) == 0;
+ if (console) {
+ scr = &gpx_consscr;
+ sc->sc_nscreens = 1;
+ } else {
+ scr = malloc(sizeof(struct gpx_screen), M_DEVBUF, M_NOWAIT);
+ if (scr == NULL) {
+ printf(": can not allocate memory\n");
+ return;
+ }
+
+ tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
+ if (tmp == 0L) {
+ printf(": can not probe depth\n");
+ free(scr, M_DEVBUF);
+ return;
+ }
+ scr->ss_depth = (*(u_int16_t *)tmp & 0x00f0) == 0x00f0 ? 4 : 8;
+ vax_unmap_physmem(tmp, 1);
+
+ scr->ss_adder = (struct adder *)vax_map_physmem(va->va_paddr +
+ GPX_ADDER_OFFSET, 1);
+ if (scr->ss_adder == NULL) {
+ printf(": can not map frame buffer registers\n");
+ free(scr, M_DEVBUF);
+ return;
+ }
+
+ scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr +
+ GPX_VDAC_OFFSET, 1);
+ if (scr->ss_vdac == NULL) {
+ printf(": can not map RAMDAC\n");
+ vax_unmap_physmem((vaddr_t)scr->ss_adder, 1);
+ free(scr, M_DEVBUF);
+ return;
+ }
+
+ if (gpx_setup_screen(scr) != 0) {
+ printf(": initialization failed\n");
+ vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1);
+ vax_unmap_physmem((vaddr_t)scr->ss_adder, 1);
+ free(scr, M_DEVBUF);
+ return;
+ }
+ }
+ sc->sc_scr = scr;
+
+ printf("\n%s: %dx%d %d plane color framebuffer\n",
+ self->dv_xname, GPX_WIDTH, GPX_VISHEIGHT, scr->ss_depth);
+
+ aa.console = console;
+ aa.scrdata = &gpx_screenlist;
+ aa.accessops = &gpx_accessops;
+ aa.accesscookie = sc;
+
+ config_found(self, &aa, wsemuldisplaydevprint);
+}
+
+/*
+ * wsdisplay accessops
+ */
+
+int
+gpx_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct gpx_softc *sc = v;
+ struct gpx_screen *ss = sc->sc_scr;
+ struct wsdisplay_fbinfo *wdf;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_GPX;
+ break;
+
+ case WSDISPLAYIO_GINFO:
+ wdf = (struct wsdisplay_fbinfo *)data;
+ wdf->height = ss->ss_ri.ri_height;
+ wdf->width = ss->ss_ri.ri_width;
+ wdf->depth = ss->ss_depth;
+ wdf->cmsize = 1 << ss->ss_depth;
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ case WSDISPLAYIO_PUTCMAP:
+ break; /* XXX TBD */
+
+ case WSDISPLAYIO_GVIDEO:
+ case WSDISPLAYIO_SVIDEO:
+ break;
+
+ case WSDISPLAYIO_LINEBYTES: /* no linear mapping */
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+paddr_t
+gpx_mmap(void *v, off_t offset, int prot)
+{
+ return (-1);
+}
+
+int
+gpx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+ int *curxp, int *curyp, long *defattrp)
+{
+ struct gpx_softc *sc = v;
+ struct gpx_screen *ss = sc->sc_scr;
+ struct rasops_info *ri = &ss->ss_ri;
+
+ if (sc->sc_nscreens > 0)
+ return (ENOMEM);
+
+ *cookiep = ri;
+ *curxp = *curyp = 0;
+ ri->ri_ops.alloc_attr(ri, 0, 0, 0, defattrp);
+ sc->sc_nscreens++;
+
+ return (0);
+}
+
+void
+gpx_free_screen(void *v, void *cookie)
+{
+ struct gpx_softc *sc = v;
+
+ sc->sc_nscreens--;
+}
+
+int
+gpx_show_screen(void *v, void *cookie, int waitok,
+ void (*cb)(void *, int, int), void *cbarg)
+{
+ return (0);
+}
+
+void
+gpx_burner(void *v, u_int on, u_int flags)
+{
+ struct gpx_softc *sc = v;
+ struct gpx_screen *ss = sc->sc_scr;
+
+ if (ss->ss_depth == 8) {
+ struct ramdac8 *rd = ss->ss_vdac;
+ rd->address = BT_CR;
+ if (on)
+ rd->cmapdata = BTCR_RAMENA | BTCR_BLINK_1648 |
+ BTCR_MPLX_4 | BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1;
+ else
+ /* fade colormap to black as well? */
+ rd->cmapdata = BTCR_BLINK_1648 | BTCR_MPLX_4;
+ } else {
+ struct ramdac4 *rd = ss->ss_vdac;
+ if (on)
+ rd->control = RAMDAC4_INIT;
+ else
+ rd->control = RAMDAC4_INIT & ~RAMDAC4_ENABLE;
+ }
+}
+
+/*
+ * wsdisplay emulops
+ */
+
+void
+gpx_putchar(void *v, int row, int col, u_int uc, long attr)
+{
+ struct rasops_info *ri = v;
+ struct gpx_screen *ss = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int dx, dy, sx, sy, fg, bg;
+
+ rasops_unpack_attr(attr, &fg, &bg, NULL);
+
+ /* find where to output the glyph... */
+ dx = col * font->fontwidth + ri->ri_xorigin;
+ dy = row * font->fontheight + ri->ri_yorigin;
+ /* ... and where to pick it from */
+ uc -= font->firstchar;
+ sx = (uc % ss->ss_gpr) * font->fontwidth;
+ sy = GPX_HEIGHT - (1 + uc / ss->ss_gpr) * font->fontheight;
+
+ /* setup VIPER operand control registers */
+ while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
+ gpx_viper_write(ss, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, MASK_1, 0xffff);
+ gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
+ gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
+ ss->ss_adder->x_clip_min = 0;
+ ss->ss_adder->x_clip_max = GPX_WIDTH;
+ ss->ss_adder->y_clip_min = 0;
+ ss->ss_adder->y_clip_max = GPX_VISHEIGHT;
+ /* load DESTINATION origin and vectors */
+ ss->ss_adder->fast_dest_dy = 0;
+ ss->ss_adder->slow_dest_dx = 0;
+ ss->ss_adder->error_1 = 0;
+ ss->ss_adder->error_2 = 0;
+ ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ gpx_wait(ss, RASTEROP_COMPLETE);
+ ss->ss_adder->destination_x = dx;
+ ss->ss_adder->fast_dest_dx = font->fontwidth;
+ ss->ss_adder->destination_y = dy;
+ ss->ss_adder->slow_dest_dy = font->fontheight;
+ /* load SOURCE origin and vectors */
+ ss->ss_adder->source_1_x = sx;
+ ss->ss_adder->source_1_y = sy;
+ ss->ss_adder->source_1_dx = font->fontwidth;
+ ss->ss_adder->source_1_dy = font->fontheight;
+ ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
+}
+
+void
+gpx_copycols(void *v, int row, int src, int dst, int cnt)
+{
+ struct rasops_info *ri = v;
+ struct gpx_screen *ss = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int sx, y, dx, w, h;
+
+ sx = ri->ri_xorigin + src * font->fontwidth;
+ dx = ri->ri_xorigin + dst * font->fontwidth;
+ w = cnt * font->fontwidth;
+ y = ri->ri_yorigin + row * font->fontheight;
+ h = font->fontheight;
+
+ gpx_copyrect(ss, sx, y, dx, y, w, h);
+}
+
+void
+gpx_erasecols(void *v, int row, int col, int cnt, long attr)
+{
+ struct rasops_info *ri = v;
+ struct gpx_screen *ss = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int x, y, dx, dy;
+
+ x = ri->ri_xorigin + col * font->fontwidth;
+ dx = cnt * font->fontwidth;
+ y = ri->ri_yorigin + row * font->fontheight;
+ dy = font->fontheight;
+
+ gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
+}
+
+void
+gpx_copyrows(void *v, int src, int dst, int cnt)
+{
+ struct rasops_info *ri = v;
+ struct gpx_screen *ss = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int x, sy, dy, w, h;
+
+ x = ri->ri_xorigin;
+ w = ri->ri_emustride;
+ sy = ri->ri_yorigin + src * font->fontheight;
+ dy = ri->ri_yorigin + dst * font->fontheight;
+ h = cnt * font->fontheight;
+
+ gpx_copyrect(ss, x, sy, x, dy, w, h);
+}
+
+void
+gpx_eraserows(void *v, int row, int cnt, long attr)
+{
+ struct rasops_info *ri = v;
+ struct gpx_screen *ss = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int x, y, dx, dy;
+
+ x = ri->ri_xorigin;
+ dx = ri->ri_emustride;
+ y = ri->ri_yorigin + row * font->fontheight;
+ dy = cnt * font->fontheight;
+
+ gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
+}
+
+void
+gpx_do_cursor(struct rasops_info *ri)
+{
+ struct gpx_screen *ss = ri->ri_hw;
+ int x, y, w, h;
+
+ x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
+ y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
+ w = ri->ri_font->fontwidth;
+ h = ri->ri_font->fontheight;
+
+ gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4); /* invert */
+}
+
+/*
+ * low-level programming routines
+ */
+
+int
+gpx_wait(struct gpx_screen *ss, int bits)
+{
+ int i;
+
+ ss->ss_adder->status = 0;
+ for (i = 100000; i != 0; i--) {
+ if ((ss->ss_adder->status & bits) == bits)
+ break;
+ DELAY(1);
+ }
+
+ return (i == 0);
+}
+
+int
+gpx_viper_write(struct gpx_screen *ss, u_int reg, u_int16_t val)
+{
+ if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 &&
+ gpx_wait(ss, TX_READY) == 0) {
+ ss->ss_adder->id_data = val;
+ ss->ss_adder->command = ID_LOAD | reg;
+ return (0);
+ }
+#ifdef DEBUG
+ if (ss->ss_console == 0) /* don't make things worse! */
+ printf("gpx_viper_write failure, reg %x val %x\n", reg, val);
+#endif
+ return (1);
+}
+
+/* Initialize the damned beast. Straight from qdss. */
+void
+gpx_reset_viper(struct gpx_screen *ss)
+{
+ int i;
+
+ ss->ss_adder->command = CANCEL;
+ /* set monitor timing */
+ ss->ss_adder->x_scan_count_0 = 0x2800;
+ ss->ss_adder->x_scan_count_1 = 0x1020;
+ ss->ss_adder->x_scan_count_2 = 0x003a;
+ ss->ss_adder->x_scan_count_3 = 0x38f0;
+ ss->ss_adder->x_scan_count_4 = 0x6128;
+ ss->ss_adder->x_scan_count_5 = 0x093a;
+ ss->ss_adder->x_scan_count_6 = 0x313c;
+ ss->ss_adder->sync_phase_adj = 0x0100;
+ ss->ss_adder->x_scan_conf = 0x00c8;
+ /*
+ * got a bug in secound pass ADDER! lets take care of it...
+ *
+ * normally, just use the code in the following bug fix code, but to
+ * make repeated demos look pretty, load the registers as if there was
+ * no bug and then test to see if we are getting sync
+ */
+ ss->ss_adder->y_scan_count_0 = 0x135f;
+ ss->ss_adder->y_scan_count_1 = 0x3363;
+ ss->ss_adder->y_scan_count_2 = 0x2366;
+ ss->ss_adder->y_scan_count_3 = 0x0388;
+ /*
+ * if no sync, do the bug fix code
+ */
+ if (gpx_wait(ss, FRAME_SYNC) != 0) {
+ /*
+ * First load all Y scan registers with very short frame and
+ * wait for scroll service. This guarantees at least one SYNC
+ * to fix the pass 2 Adder initialization bug (synchronizes
+ * XCINCH with DMSEEDH)
+ */
+ ss->ss_adder->y_scan_count_0 = 0x01;
+ ss->ss_adder->y_scan_count_1 = 0x01;
+ ss->ss_adder->y_scan_count_2 = 0x01;
+ ss->ss_adder->y_scan_count_3 = 0x01;
+ /* delay at least 1 full frame time */
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ /*
+ * now load the REAL sync values (in reverse order just to
+ * be safe).
+ */
+ ss->ss_adder->y_scan_count_3 = 0x0388;
+ ss->ss_adder->y_scan_count_2 = 0x2366;
+ ss->ss_adder->y_scan_count_1 = 0x3363;
+ ss->ss_adder->y_scan_count_0 = 0x135f;
+ }
+ /* zero the index registers */
+ ss->ss_adder->x_index_pending = 0;
+ ss->ss_adder->y_index_pending = 0;
+ ss->ss_adder->x_index_new = 0;
+ ss->ss_adder->y_index_new = 0;
+ ss->ss_adder->x_index_old = 0;
+ ss->ss_adder->y_index_old = 0;
+ ss->ss_adder->pause = 0;
+ /* set rasterop mode to normal pen down */
+ ss->ss_adder->rasterop_mode =
+ DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+ /* set the rasterop registers to default values */
+ ss->ss_adder->source_1_dx = 1;
+ ss->ss_adder->source_1_dy = 1;
+ ss->ss_adder->source_1_x = 0;
+ ss->ss_adder->source_1_y = 0;
+ ss->ss_adder->destination_x = 0;
+ ss->ss_adder->destination_y = 0;
+ ss->ss_adder->fast_dest_dx = 1;
+ ss->ss_adder->fast_dest_dy = 0;
+ ss->ss_adder->slow_dest_dx = 0;
+ ss->ss_adder->slow_dest_dy = 1;
+ ss->ss_adder->error_1 = 0;
+ ss->ss_adder->error_2 = 0;
+ /* scale factor = UNITY */
+ ss->ss_adder->fast_scale = UNITY;
+ ss->ss_adder->slow_scale = UNITY;
+ /* set the source 2 parameters */
+ ss->ss_adder->source_2_x = 0;
+ ss->ss_adder->source_2_y = 0;
+ ss->ss_adder->source_2_size = 0x0022;
+ /* initialize plane addresses for eight vipers */
+ for (i = 0; i < 7; i++) {
+ gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i);
+ gpx_viper_write(ss, PLANE_ADDRESS, i);
+ }
+ /* initialize the external registers. */
+ gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
+ gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff);
+ /* initialize resolution mode */
+ gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c); /* bus width = 16 */
+ gpx_viper_write(ss, RESOLUTION_MODE, 0x0000); /* one bit/pixel */
+ /* initialize viper registers */
+ gpx_viper_write(ss, SCROLL_CONSTANT,
+ SCROLL_ENABLE | VIPER_LEFT | VIPER_UP);
+ gpx_viper_write(ss, SCROLL_FILL, 0x0000);
+ /* set clipping and scrolling limits to full screen */
+ gpx_wait(ss, ADDRESS_COMPLETE);
+ ss->ss_adder->x_clip_min = 0;
+ ss->ss_adder->x_clip_max = GPX_WIDTH;
+ ss->ss_adder->y_clip_min = 0;
+ ss->ss_adder->y_clip_max = GPX_HEIGHT;
+ ss->ss_adder->scroll_x_min = 0;
+ ss->ss_adder->scroll_x_max = GPX_WIDTH;
+ ss->ss_adder->scroll_y_min = 0;
+ ss->ss_adder->scroll_y_max = GPX_HEIGHT;
+ gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->x_index_pending = 0;
+ ss->ss_adder->y_index_pending = 0;
+ ss->ss_adder->x_index_new = 0;
+ ss->ss_adder->y_index_new = 0;
+ ss->ss_adder->x_index_old = 0;
+ ss->ss_adder->y_index_old = 0;
+ gpx_wait(ss, ADDRESS_COMPLETE);
+ gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000);
+ gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000);
+ /* set source and the mask register to all ones */
+ gpx_viper_write(ss, SOURCE, 0xffff);
+ gpx_viper_write(ss, MASK_1, 0xffff);
+ gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ /* initialize Operand Control Register banks for fill command */
+ gpx_viper_write(ss, SRC1_OCR_A, EXT_NONE | INT_M1_M2 | NO_ID | WAIT);
+ gpx_viper_write(ss, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
+ gpx_viper_write(ss, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+ gpx_viper_write(ss, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
+ gpx_viper_write(ss, SRC2_OCR_B, EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT);
+ gpx_viper_write(ss, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+
+ /*
+ * Init Logic Unit Function registers.
+ */
+ /* putchar */
+ gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ /* erase{cols,rows} */
+ gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ONES);
+ /* cursor */
+ gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_D_XOR_S);
+}
+
+/* Clear the whole screen. Straight from qdss. */
+void
+gpx_clear_screen(struct gpx_screen *ss)
+{
+ ss->ss_adder->x_limit = GPX_WIDTH;
+ ss->ss_adder->y_limit = GPX_HEIGHT;
+ ss->ss_adder->y_offset_pending = 0;
+ gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_offset_pending = GPX_VISHEIGHT;
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT;
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->y_offset_pending = 0; /* back to normal */
+ gpx_wait(ss, FRAME_SYNC);
+ gpx_wait(ss, FRAME_SYNC);
+ ss->ss_adder->x_limit = GPX_WIDTH;
+ ss->ss_adder->y_limit = GPX_VISHEIGHT;
+}
+
+int
+gpx_setup_screen(struct gpx_screen *ss)
+{
+ struct rasops_info *ri = &ss->ss_ri;
+ const u_char *cmap;
+ int i, color12;
+
+ bzero(ri, sizeof(*ri));
+ ri->ri_depth = 8; /* masquerade as a 8 bit device for rasops */
+ ri->ri_width = GPX_WIDTH;
+ ri->ri_height = GPX_VISHEIGHT;
+ ri->ri_stride = GPX_WIDTH;
+ ri->ri_flg = RI_CENTER; /* no RI_CLEAR as ri_bits is NULL! */
+ ri->ri_hw = ss;
+
+ /*
+ * We can not let rasops select our font, because we need to use
+ * a font with right-to-left bit order on this frame buffer.
+ */
+ wsfont_init();
+ if ((ri->ri_wsfcookie = wsfont_find(NULL, 8, 15, 0)) <= 0)
+ return (-1);
+ if (wsfont_lock(ri->ri_wsfcookie, &ri->ri_font,
+ WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0)
+ return (-1);
+
+ /*
+ * Ask for an unholy big display, rasops will trim this to more
+ * reasonable values.
+ */
+ if (rasops_init(ri, 160, 160) != 0)
+ return (-1);
+
+ /*
+ * Override the rasops emulops.
+ */
+ ri->ri_ops.copyrows = gpx_copyrows;
+ ri->ri_ops.copycols = gpx_copycols;
+ ri->ri_ops.eraserows = gpx_eraserows;
+ ri->ri_ops.erasecols = gpx_erasecols;
+ ri->ri_ops.putchar = gpx_putchar;
+ ri->ri_do_cursor = gpx_do_cursor;
+
+ gpx_stdscreen.ncols = ri->ri_cols;
+ gpx_stdscreen.nrows = ri->ri_rows;
+ gpx_stdscreen.textops = &ri->ri_ops;
+ gpx_stdscreen.fontwidth = ri->ri_font->fontwidth;
+ gpx_stdscreen.fontheight = ri->ri_font->fontheight;
+ gpx_stdscreen.capabilities = ri->ri_caps & ~WSSCREEN_UNDERLINE;
+
+ /*
+ * Initialize RAMDAC.
+ */
+ if (ss->ss_depth == 8) {
+ struct ramdac8 *rd = ss->ss_vdac;
+ rd->address = BT_CR;
+ rd->cmapdata = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4 |
+ BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1;
+ } else {
+ struct ramdac4 *rd = ss->ss_vdac;
+ rd->control = RAMDAC4_INIT;
+ }
+
+ /*
+ * Put the ADDER and VIPER in a good state.
+ */
+ gpx_reset_viper(ss);
+
+ /*
+ * Initialize colormap.
+ */
+ gpx_wait(ss, FRAME_SYNC);
+ cmap = rasops_cmap;
+ if (ss->ss_depth == 8) {
+ struct ramdac8 *rd = ss->ss_vdac;
+ rd->address = 0;
+ for (i = 0; i < 256 * 3; i++)
+ rd->cmapdata = *cmap++;
+ } else {
+ struct ramdac4 *rd = ss->ss_vdac;
+ for (i = 0; i < 16; i++) {
+ color12 = (*cmap++ >> 4) << 8;
+ color12 |= (*cmap++ >> 4) << 4;
+ color12 |= (*cmap++ >> 4) << 0;
+ rd->colormap[i] = color12;
+ }
+ }
+
+ /*
+ * Clear display (including non-visible area), in 864 lines chunks.
+ */
+ gpx_clear_screen(ss);
+
+ /*
+ * Copy our font to the offscreen area.
+ */
+ gpx_upload_font(ss);
+
+ return (0);
+}
+
+/*
+ * Copy the selected wsfont to non-visible frame buffer area.
+ * This is necessary since the only way to send data to the frame buffer
+ * is through the ID interface, which is slow and needs 16 bit wide data.
+ * Adapted from qdss.
+ */
+void
+gpx_upload_font(struct gpx_screen *ss)
+{
+ struct rasops_info *ri = &ss->ss_ri;
+ struct wsdisplay_font *font = ri->ri_font;
+ u_int8_t *fontbits, *fb;
+ u_int remaining, nchars, row;
+ u_int i, j;
+ u_int16_t data;
+
+ /* setup VIPER operand control registers */
+
+ gpx_viper_write(ss, MASK_1, 0xffff);
+ gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+
+ gpx_viper_write(ss, SRC1_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, SRC2_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, DST_OCR_B,
+ EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+
+ ss->ss_adder->rasterop_mode =
+ DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+ gpx_wait(ss, RASTEROP_COMPLETE);
+
+ /*
+ * Load font data. The 8x15 font fits on two ``lines'' at the end
+ * of the display (this also assumes the font has an even number
+ * of glyphs; if it doesn't, the last glyph will render as empty).
+ */
+ ss->ss_gpr = MIN(GPX_WIDTH / font->fontwidth, font->numchars);
+ if (ss->ss_gpr & 1)
+ ss->ss_gpr--;
+ fontbits = font->data;
+ for (row = 1, remaining = font->numchars; remaining > 1;
+ row++, remaining -= nchars) {
+ nchars = MIN(ss->ss_gpr, remaining);
+ if (nchars & 1)
+ nchars--;
+
+ ss->ss_adder->destination_x = 0;
+ ss->ss_adder->destination_y =
+ GPX_HEIGHT - row * font->fontheight;
+ ss->ss_adder->fast_dest_dx = nchars * font->fontwidth;
+ ss->ss_adder->slow_dest_dy = font->fontheight;
+
+ /* setup for processor to bitmap xfer */
+ gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
+ ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/
+
+ /* iteratively do the processor to bitmap xfer */
+ for (i = font->fontheight; i != 0; i--) {
+ fb = fontbits++;
+ /* PTOB a scan line */
+ for (j = nchars >> 1; j != 0; j--) {
+ /* PTOB one scan of a char cell */
+ data = *fb;
+ fb += font->fontheight;
+ data |= ((u_int16_t)*fb) << 8;
+ fb += font->fontheight;
+
+ gpx_wait(ss, TX_READY);
+ ss->ss_adder->id_data = data;
+ }
+ }
+ fontbits += (nchars - 1) * font->fontheight;
+ }
+}
+
+void
+gpx_copyrect(struct gpx_screen *ss,
+ int sx, int sy, int dx, int dy, int w, int h)
+{
+ while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
+ gpx_viper_write(ss, MASK_1, 0xffff);
+ gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ gpx_viper_write(ss, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ ss->ss_adder->fast_dest_dy = 0;
+ ss->ss_adder->slow_dest_dx = 0;
+ ss->ss_adder->error_1 = 0;
+ ss->ss_adder->error_2 = 0;
+ ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ ss->ss_adder->destination_x = dx;
+ ss->ss_adder->fast_dest_dx = w;
+ ss->ss_adder->destination_y = dy;
+ ss->ss_adder->slow_dest_dy = h;
+ ss->ss_adder->source_1_x = sx;
+ ss->ss_adder->source_1_dx = w;
+ ss->ss_adder->source_1_y = sy;
+ ss->ss_adder->source_1_dy = h;
+ ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
+}
+
+/*
+ * Fill a rectangle with the given attribute and function (i.e. rop).
+ */
+void
+gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr,
+ u_int function)
+{
+ int fg, bg;
+
+ rasops_unpack_attr(attr, &fg, &bg, NULL);
+
+ while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
+ gpx_viper_write(ss, MASK_1, 0xffff);
+ gpx_viper_write(ss, SOURCE, 0xffff);
+ /* the swap of bg and fg is intentional */
+ gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, bg);
+ gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, fg);
+ gpx_viper_write(ss, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ gpx_viper_write(ss, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ ss->ss_adder->fast_dest_dx = 0;
+ ss->ss_adder->fast_dest_dy = 0;
+ ss->ss_adder->slow_dest_dx = 0;
+ ss->ss_adder->error_1 = 0;
+ ss->ss_adder->error_2 = 0;
+ ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ ss->ss_adder->destination_x = x;
+ ss->ss_adder->fast_dest_dx = dx;
+ ss->ss_adder->destination_y = y;
+ ss->ss_adder->slow_dest_dy = dy;
+ ss->ss_adder->source_1_x = x;
+ ss->ss_adder->source_1_dx = dx;
+ ss->ss_adder->source_1_y = y;
+ ss->ss_adder->source_1_dy = dy;
+ ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function;
+}
+
+/*
+ * Console support code
+ */
+
+#include <dev/cons.h>
+cons_decl(gpx);
+
+#include "dzkbd.h"
+
+#include <vax/qbus/dzreg.h>
+#include <vax/qbus/dzvar.h>
+#include <vax/dec/dzkbdvar.h>
+
+/*
+ * Called very early to setup the glass tty as console.
+ * Because it's called before the VM system is initialized, virtual memory
+ * for the framebuffer can be stolen directly without disturbing anything.
+ */
+void
+gpxcnprobe(cndev)
+ struct consdev *cndev;
+{
+ struct gpx_screen *ss = &gpx_consscr;
+ extern vaddr_t virtual_avail;
+ extern int getmajor(void *); /* conf.c */
+ vaddr_t tmp;
+ int depth;
+
+ switch (vax_boardtype) {
+ case VAX_BTYP_410:
+ case VAX_BTYP_420:
+ case VAX_BTYP_43:
+ /* not present on microvaxes */
+ if ((vax_confdata & KA420_CFG_MULTU) != 0)
+ break;
+
+ if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
+ break; /* doesn't use graphics console */
+
+ /* Check for a recognized color depth */
+ tmp = virtual_avail;
+ ioaccess(tmp, GPXADDR + GPX_READBACK_OFFSET, 1);
+ depth = (*(u_int16_t *)tmp) & 0x00f0;
+ if (depth != 0x00f0 && depth != 0x0080)
+ break;
+
+ ss->ss_depth = depth == 0x00f0 ? 4 : 8;
+
+ ss->ss_adder = (struct adder *)virtual_avail;
+ virtual_avail += VAX_NBPG;
+ ioaccess((vaddr_t)ss->ss_adder, GPXADDR + GPX_ADDER_OFFSET, 1);
+
+ ss->ss_vdac = (void *)virtual_avail;
+ virtual_avail += VAX_NBPG;
+ ioaccess((vaddr_t)ss->ss_vdac, GPXADDR + GPX_VDAC_OFFSET, 1);
+
+ cndev->cn_pri = CN_INTERNAL;
+ cndev->cn_dev = makedev(getmajor(wsdisplayopen), 0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+gpxcninit(struct consdev *cndev)
+{
+ struct gpx_screen *ss = &gpx_consscr;
+ long defattr;
+ struct rasops_info *ri;
+ extern void lkccninit(struct consdev *);
+ extern int lkccngetc(dev_t);
+ extern int dz_vsbus_lk201_cnattach(int);
+
+ /* mappings have been done in gpxcnprobe() */
+ if (gpx_setup_screen(ss) != 0)
+ return;
+
+ ri = &ss->ss_ri;
+ ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
+ wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr);
+
+#if NDZKBD > 0
+ dzkbd_cnattach(0); /* Connect keyboard and screen together */
+#endif
+}