Module Name: src Committed By: martin Date: Sun Feb 12 12:27:26 UTC 2023
Modified Files: src/sys/arch/vax/conf [netbsd-10]: GENERIC INSTALL VAX780 files.vax src/sys/arch/vax/include [netbsd-10]: qdreg.h src/sys/arch/vax/vax [netbsd-10]: conf.c src/sys/arch/vax/vsa [netbsd-10]: smg.c Added Files: src/sys/arch/vax/vsa [netbsd-10]: gpx.c Log Message: Pull up following revision(s) (requested by tsutsui in ticket #79): sys/arch/vax/conf/GENERIC: revision 1.217 sys/arch/vax/conf/VAX780: revision 1.34 sys/arch/vax/conf/files.vax: revision 1.126 sys/arch/vax/vsa/smg.c: revision 1.63 sys/arch/vax/include/qdreg.h: revision 1.7 sys/arch/vax/vax/conf.c: revision 1.69 sys/arch/vax/conf/INSTALL: revision 1.76 sys/arch/vax/vsa/gpx.c: revision 1.1 Add a support for gpx(4) color framebuffer found on VAXstation 3100. Ported from OpenBSD/vax. Note smg(4) monochrome onboard framebuffer driver is also changed attached only if gpx(4) is not installed or flags 1 is specified in config files, as OpenBSD did. Tested on my VAXstation 3100/m30 with and without 8bpp gpx(4). Revied on port-vax@ and "Please go ahead!" from ragge@. https://mail-index.netbsd.org/port-vax/2023/01/thread1.html#004147 To generate a diff of this commit: cvs rdiff -u -r1.216 -r1.216.4.1 src/sys/arch/vax/conf/GENERIC cvs rdiff -u -r1.75 -r1.75.24.1 src/sys/arch/vax/conf/INSTALL cvs rdiff -u -r1.33 -r1.33.4.1 src/sys/arch/vax/conf/VAX780 cvs rdiff -u -r1.125 -r1.125.30.1 src/sys/arch/vax/conf/files.vax cvs rdiff -u -r1.6 -r1.6.4.1 src/sys/arch/vax/include/qdreg.h cvs rdiff -u -r1.68 -r1.68.48.1 src/sys/arch/vax/vax/conf.c cvs rdiff -u -r0 -r1.1.2.2 src/sys/arch/vax/vsa/gpx.c cvs rdiff -u -r1.61.6.1 -r1.61.6.2 src/sys/arch/vax/vsa/smg.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/vax/conf/GENERIC diff -u src/sys/arch/vax/conf/GENERIC:1.216 src/sys/arch/vax/conf/GENERIC:1.216.4.1 --- src/sys/arch/vax/conf/GENERIC:1.216 Thu Sep 29 10:10:10 2022 +++ src/sys/arch/vax/conf/GENERIC Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.216 2022/09/29 10:10:10 riastradh Exp $ +# $NetBSD: GENERIC,v 1.216.4.1 2023/02/12 12:27:26 martin Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/vax/conf/std.vax" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.216 $" +#ident "GENERIC-$Revision: 1.216.4.1 $" # Here are all different supported CPU types listed. #options VAX8800 # VAX 8500, 8530, 8550, 8700, 8800 @@ -185,6 +185,7 @@ si1 at vsbus0 csr 0x200c0180 # VS2000/3 asc0 at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr asc0 at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr smg0 at vsbus0 csr 0x200f0000 # Small monochrome display ctlr. +gpx0 at vsbus0 csr 0x3c000000 # VS3100 GPX display option #clr0 at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics spx0 at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90. lcg0 at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics @@ -271,6 +272,7 @@ uk* at scsibus? target? lun? # VAXstation graphics support wsdisplay* at smg0 +wsdisplay* at gpx0 wsdisplay* at spx0 wsdisplay* at lcg0 #wsdisplay* at clr0 Index: src/sys/arch/vax/conf/INSTALL diff -u src/sys/arch/vax/conf/INSTALL:1.75 src/sys/arch/vax/conf/INSTALL:1.75.24.1 --- src/sys/arch/vax/conf/INSTALL:1.75 Mon Jan 20 18:38:21 2020 +++ src/sys/arch/vax/conf/INSTALL Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -# $NetBSD: INSTALL,v 1.75 2020/01/20 18:38:21 thorpej Exp $ +# $NetBSD: INSTALL,v 1.75.24.1 2023/02/12 12:27:26 martin Exp $ # # INSTALL kernel; all supported devices but nothing fancy. # @@ -139,6 +139,7 @@ si1 at vsbus0 csr 0x200c0180 # VS2000/3 asc0 at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr asc0 at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr smg0 at vsbus0 csr 0x200f0000 # Small monochrome display ctlr. +gpx0 at vsbus0 csr 0x3c000000 # VS3100 GPX display option #clr0 at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics spx0 at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90. #lcg0 at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics @@ -217,6 +218,7 @@ cd* at scsibus? target? lun? # VAXstation graphics support wsdisplay* at smg0 +wsdisplay* at gpx0 wsdisplay* at spx0 #wsdisplay* at lcg0 #wsdisplay* at clr0 Index: src/sys/arch/vax/conf/VAX780 diff -u src/sys/arch/vax/conf/VAX780:1.33 src/sys/arch/vax/conf/VAX780:1.33.4.1 --- src/sys/arch/vax/conf/VAX780:1.33 Sun Aug 7 02:52:30 2022 +++ src/sys/arch/vax/conf/VAX780 Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -# $NetBSD: VAX780,v 1.33 2022/08/07 02:52:30 simonb Exp $ +# $NetBSD: VAX780,v 1.33.4.1 2023/02/12 12:27:26 martin Exp $ # # 11/780,750,730 machine description file # @@ -171,6 +171,7 @@ ubi0 at mainbus0 # 11/730 direct unibu #asc0 at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr #asc0 at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr #smg0 at vsbus0 csr 0x200f0000 # Small monochrome display ctlr. +#gpx0 at vsbus0 csr 0x3c000000 # VS3100 GPX display option #clr0 at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics #spx0 at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90. #lcg0 at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics @@ -251,6 +252,7 @@ mt* at mscpbus? drive? # MSCP tape # VAXstation graphics support #wsdisplay* at smg0 +#wsdisplay* at gpx0 #wsdisplay* at spx0 #wsdisplay* at lcg0 #wsdisplay* at clr0 Index: src/sys/arch/vax/conf/files.vax diff -u src/sys/arch/vax/conf/files.vax:1.125 src/sys/arch/vax/conf/files.vax:1.125.30.1 --- src/sys/arch/vax/conf/files.vax:1.125 Sat Dec 29 11:30:12 2018 +++ src/sys/arch/vax/conf/files.vax Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -# $NetBSD: files.vax,v 1.125 2018/12/29 11:30:12 maxv Exp $ +# $NetBSD: files.vax,v 1.125.30.1 2023/02/12 12:27:26 martin Exp $ # # new style config file for vax architecture # @@ -149,7 +149,7 @@ attach cpu at xmi with cpu_xmi attach mem at xmi with mem_xmi attach dz at vsbus with dz_vsbus -file arch/vax/vsa/dz_vsbus.c dz_vsbus | smg +file arch/vax/vsa/dz_vsbus.c dz_vsbus | smg | gpx attach lkkbd at dz with dzkbd file dev/dec/dzkbd.c dzkbd needs-flag @@ -190,6 +190,11 @@ device smg: displaydev, wsemuldisplaydev attach smg at vsbus file arch/vax/vsa/smg.c smg needs-flag +# GPX framebuffer on VS3100. +device gpx: displaydev, wsemuldisplaydev, rasops8 +attach gpx at vsbus +file arch/vax/vsa/gpx.c gpx needs-flag + # Monochrome QVSS framebuffer on qbus (VCB01) device qv {}: displaydev, wsemuldisplaydev attach qv at uba Index: src/sys/arch/vax/include/qdreg.h diff -u src/sys/arch/vax/include/qdreg.h:1.6 src/sys/arch/vax/include/qdreg.h:1.6.4.1 --- src/sys/arch/vax/include/qdreg.h:1.6 Tue Aug 17 22:00:31 2021 +++ src/sys/arch/vax/include/qdreg.h Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: qdreg.h,v 1.6 2021/08/17 22:00:31 andvar Exp $ */ +/* $NetBSD: qdreg.h,v 1.6.4.1 2023/02/12 12:27:26 martin Exp $ */ /*- * Copyright (c) 1982, 1986 The Regents of the University of California. * All rights reserved. @@ -172,10 +172,12 @@ /* VIPER logical function unit codes */ #define LF_ZEROS 0x0000 +#define LF_NOT_D 0x0003 #define LF_D_XOR_S 0x0006 -#define LF_SOURCE 0x000A -#define LF_D_OR_S 0x000E -#define LF_ONES 0x000F +#define LF_SOURCE 0x000a +#define LF_D 0x000c +#define LF_D_OR_S 0x000d +#define LF_ONES 0x000f #define INV_M1_M2 0x0030 #define FULL_SRC_RESOLUTION 0X00C0 /* makes second pass like first pass */ Index: src/sys/arch/vax/vax/conf.c diff -u src/sys/arch/vax/vax/conf.c:1.68 src/sys/arch/vax/vax/conf.c:1.68.48.1 --- src/sys/arch/vax/vax/conf.c:1.68 Sun Jul 5 02:10:53 2015 +++ src/sys/arch/vax/vax/conf.c Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: conf.c,v 1.68 2015/07/05 02:10:53 matt Exp $ */ +/* $NetBSD: conf.c,v 1.68.48.1 2023/02/12 12:27:26 martin Exp $ */ /*- * Copyright (c) 1982, 1986 The Regents of the University of California. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.68 2015/07/05 02:10:53 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.68.48.1 2023/02/12 12:27:26 martin Exp $"); #include "opt_cputype.h" @@ -45,12 +45,28 @@ __KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.6 */ #include <dev/cons.h> +#include "gpx.h" #include "lcg.h" #include "qv.h" #include "smg.h" #include "spx.h" #include "wskbd.h" +#if NGPX > 0 +#if NWSKBD > 0 +#define gpxcngetc wskbd_cngetc +#else +static int +gpxcngetc(dev_t dev) +{ + return 0; +} +#endif + +#define gpxcnputc wsdisplay_cnputc +#define gpxcnpollc nullcnpollc +#endif /* NGPX > 0 */ + #if NLCG > 0 #if NWSKBD > 0 #define lcgcngetc wskbd_cngetc @@ -110,6 +126,7 @@ spxcngetc(dev_t dev) cons_decl(gen); cons_decl(dz); +cons_decl(gpx); cons_decl(qd); cons_decl(lcg); cons_decl(qv); @@ -133,6 +150,9 @@ struct consdev constab[]={ cons_init(qd), #endif #endif +#if NGPX + cons_init(gpx), +#endif #if NLCG cons_init(lcg), #endif Index: src/sys/arch/vax/vsa/smg.c diff -u src/sys/arch/vax/vsa/smg.c:1.61.6.1 src/sys/arch/vax/vsa/smg.c:1.61.6.2 --- src/sys/arch/vax/vsa/smg.c:1.61.6.1 Mon Feb 6 16:48:44 2023 +++ src/sys/arch/vax/vsa/smg.c Sun Feb 12 12:27:26 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: smg.c,v 1.61.6.1 2023/02/06 16:48:44 martin Exp $ */ +/* $NetBSD: smg.c,v 1.61.6.2 2023/02/12 12:27:26 martin Exp $ */ /* * Copyright (c) 1998 Ludd, University of Lule}, Sweden. * All rights reserved. @@ -25,7 +25,11 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61.6.1 2023/02/06 16:48:44 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61.6.2 2023/02/12 12:27:26 martin Exp $"); + +#include "opt_wsfont.h" +#include "dzkbd.h" +#include "wsdisplay.h" #include <sys/param.h> #include <sys/systm.h> @@ -40,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61 #include <machine/vsbus.h> #include <machine/sid.h> #include <machine/ka420.h> +#include <machine/scb.h> #include <dev/cons.h> @@ -52,9 +57,6 @@ __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61 #include <dev/wscons/wscons_callbacks.h> #include <dev/wsfont/wsfont.h> -#include "dzkbd.h" -#include "opt_wsfont.h" - /* Screen hardware defs */ #define SM_COLS 128 /* char width of screen */ #define SM_ROWS 57 /* rows of char on screen */ @@ -187,34 +189,67 @@ static struct smg_screen *curscr; static callout_t smg_cursor_ch; int -smg_match(device_t parent, cfdata_t match, void *aux) +smg_match(device_t parent, cfdata_t cf, void *aux) { struct vsbus_attach_args * const va = aux; volatile uint16_t *ccmd; volatile uint16_t *cfgtst; uint16_t tmp, tmp2; - if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_53) + switch (vax_boardtype) { + default: return 0; - ccmd = (uint16_t *)va->va_addr; - cfgtst = (uint16_t *)vax_map_physmem(VS_CFGTST, 1); - /* - * Try to find the cursor chip by testing the flip-flop. - * If nonexistent, no glass tty. - */ - ccmd[0] = CUR_CMD_HSHI|CUR_CMD_FOPB; - DELAY(300000); - tmp = cfgtst[0]; - ccmd[0] = CUR_CMD_TEST|CUR_CMD_HSHI; - DELAY(300000); - tmp2 = cfgtst[0]; - vax_unmap_physmem((vaddr_t)cfgtst, 1); - - if (tmp2 != tmp) - return 20; /* Using periodic interrupt */ - else - return 0; + case VAX_BTYP_410: + case VAX_BTYP_420: + case VAX_BTYP_43: + if (va->va_paddr != KA420_CUR_BASE) + return 0; + + /* not present on microvaxes */ + if ((vax_confdata & KA420_CFG_MULTU) != 0) + return 0; + /* + * If the color option board is present, do not attach + * unless we are explicitely asked to via device flags. + */ + if ((vax_confdata & KA420_CFG_VIDOPT) != 0 && + (cf->cf_flags & 1) == 0) + return 0; + break; + } + + /* when already running as console, always fake things */ + if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0 +#if NWSDISPLAY > 0 + && cn_tab->cn_putc == wsdisplay_cnputc +#endif + ) { + struct vsbus_softc *sc = device_private(parent); + + sc->sc_mask = 0x08; + scb_fake(0x44, 0x15); + return 20; + } else { + /* + * Try to find the cursor chip by testing the flip-flop. + * If nonexistent, no glass tty. + */ + ccmd = (uint16_t *)va->va_addr; + cfgtst = (uint16_t *)vax_map_physmem(VS_CFGTST, 1); + ccmd[0] = CUR_CMD_HSHI|CUR_CMD_FOPB; + DELAY(300000); + tmp = cfgtst[0]; + ccmd[0] = CUR_CMD_TEST|CUR_CMD_HSHI; + DELAY(300000); + tmp2 = cfgtst[0]; + vax_unmap_physmem((vaddr_t)cfgtst, 1); + + if (tmp2 != tmp) + return 20; /* Using periodic interrupt */ + else + return 0; + } } void @@ -234,7 +269,13 @@ smg_attach(device_t parent, device_t sel if (curscr == NULL) callout_init(&smg_cursor_ch, 0); curscr = &smg_conscreen; - aa.console = (vax_confdata & (KA420_CFG_L3CON|KA420_CFG_MULTU)) == 0; + aa.console = +#if NWSDISPLAY > 0 + (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0 && + cn_tab->cn_putc == wsdisplay_cnputc; +#else + (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0; +#endif aa.scrdata = &smg_screenlist; aa.accessops = &smg_accessops; @@ -581,9 +622,15 @@ smgcninit(struct consdev *cndev) { int fcookie; struct wsdisplay_font *console_font; - extern void lkccninit(struct consdev *); - extern int lkccngetc(dev_t); + extern vaddr_t virtual_avail; extern int dz_vsbus_lk201_cnattach(int); + + sm_addr = (void *)virtual_avail; + ioaccess((vaddr_t)sm_addr, SMADDR, (SMSIZE / VAX_NBPG)); + virtual_avail += SMSIZE; + + virtual_avail = round_page(virtual_avail); + /* Clear screen */ memset(sm_addr, 0, 128*864); @@ -618,7 +665,6 @@ smgcninit(struct consdev *cndev) void smgcnprobe(struct consdev *cndev) { - extern vaddr_t virtual_avail; extern const struct cdevsw wsdisplay_cdevsw; switch (vax_boardtype) { @@ -628,12 +674,9 @@ smgcnprobe(struct consdev *cndev) if ((vax_confdata & KA420_CFG_L3CON) || (vax_confdata & KA420_CFG_MULTU)) break; /* doesn't use graphics console */ - sm_addr = (void *)virtual_avail; - virtual_avail += SMSIZE; - ioaccess((vaddr_t)sm_addr, SMADDR, (SMSIZE/VAX_NBPG)); cndev->cn_pri = CN_INTERNAL; - cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), - 0); + cndev->cn_dev = + makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); break; default: Added files: Index: src/sys/arch/vax/vsa/gpx.c diff -u /dev/null src/sys/arch/vax/vsa/gpx.c:1.1.2.2 --- /dev/null Sun Feb 12 12:27:26 2023 +++ src/sys/arch/vax/vsa/gpx.c Sun Feb 12 12:27:26 2023 @@ -0,0 +1,1361 @@ +/* $NetBSD: gpx.c,v 1.1.2.2 2023/02/12 12:27:26 martin Exp $ */ +/* $OpenBSD: gpx.c,v 1.25 2014/12/23 21:39:12 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 "dzkbd.h" +#include "wsdisplay.h" + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/conf.h> + +#include <machine/sid.h> +#include <machine/cpu.h> +#include <machine/ka420.h> +#include <machine/scb.h> +#include <machine/vsbus.h> +#include <machine/qdreg.h> + +#include <dev/cons.h> + +#include <dev/dec/dzreg.h> +#include <dev/dec/dzvar.h> +#include <dev/dec/dzkbdvar.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> + +#if 0 +#include <dev/ic/bt458reg.h> +#include <dev/ic/dc503reg.h> +#endif + +#define GPXADDR 0x3c000000 /* base address on VAXstation 3100 */ + +#define GPX_ADDER_OFFSET 0x0000 +#define GPX_VDAC_OFFSET 0x0300 +#define GPX_CURSOR_OFFSET 0x0400 /* DC503 */ +#define GPX_READBACK_OFFSET 0x0500 + +#define GPX_WIDTH 1024 +#define GPX_VISHEIGHT 864 +#define GPX_HEIGHT 2048 + +/* XXX these should be in <dev/ic/bt458reg.h> */ +/* + * Brooktree Bt451, Bt457, Bt458 register definitions + */ +#define BT_OV0 0x00 /* overlay 0 */ +#define BT_OV1 0x01 /* overlay 1 */ +#define BT_OV2 0x02 /* overlay 2 */ +#define BT_OV3 0x03 /* overlay 3 */ +#define BT_RMR 0x04 /* read mask */ +#define BT_BMR 0x05 /* blink mask */ +#define BT_CR 0x06 /* control */ +#define BT_CTR 0x07 /* control/test */ + +#define BTCR_MPLX_5 0x80 /* multiplex select, 5:1 */ +#define BTCR_MPLX_4 0x00 /* multiplex select, 4:1 */ +#define BTCR_RAMENA 0x40 /* use color palette RAM */ +#define BTCR_BLINK_M 0x30 /* blink mask */ +#define BTCR_BLINK_1648 0x00 /* 16 on, 48 off */ +#define BTCR_BLINK_1616 0x10 /* 16 on, 16 off */ +#define BTCR_BLINK_3232 0x20 /* 32 on, 32 off */ +#define BTCR_BLINK_6464 0x30 /* 64 on, 64 off */ +#define BTCR_BLINKENA_OV1 0x08 /* OV1 blink enable */ +#define BTCR_BLINKENA_OV0 0x04 /* OV0 blink enable */ +#define BTCR_DISPENA_OV1 0x02 /* OV1 display enable */ +#define BTCR_DISPENA_OV0 0x01 /* OV0 display enable */ + +#define BTCTR_R_ENA 0x01 /* red channel enable */ +#define BTCTR_G_ENA 0x02 /* green channel enable */ +#define BTCTR_B_ENA 0x04 /* blue channel enable */ +#define BTCTR_NIB_M 0x08 /* nibble mask: */ +#define BTCTR_NIB_LOW 0x08 /* low */ +#define BTCTR_NIB_HIGH 0x00 /* high */ + +/* 4 plane option RAMDAC */ +struct ramdac4 { + uint16_t colormap[16]; + uint8_t unknown[0x20]; + uint16_t cursormap[4]; + uint8_t unknown2[0x18]; + uint16_t control; +#define RAMDAC4_INIT 0x0047 +#define RAMDAC4_ENABLE 0x0002 +}; + +/* 8 plane option RAMDAC - Bt458 or compatible */ +struct ramdac8 { + uint16_t address; + uint16_t cmapdata; + uint16_t control; + uint16_t omapdata; +}; + +static int gpx_match(device_t, cfdata_t, void *); +static void gpx_attach(device_t, device_t, 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; + uint8_t ss_cmap[256 * 3]; +#if 0 + struct dc503reg *ss_cursor; + uint16_t ss_curcmd; +#endif +}; + +/* for console */ +struct gpx_screen gpx_consscr; + +struct gpx_softc { + device_t sc_dev; + struct gpx_screen *sc_scr; + int sc_nscreens; +}; + +CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc), + gpx_match, gpx_attach, NULL, NULL); + +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, +}; + +static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *); +static paddr_t gpx_mmap(void *, void *, off_t, int); +static int gpx_alloc_screen(void *, const struct wsscreen_descr *, + void **, int *, int *, long *); +static void gpx_free_screen(void *, void *); +static int gpx_show_screen(void *, void *, int, + void (*) (void *, int, int), void *); + +const struct wsdisplay_accessops gpx_accessops = { + .ioctl = gpx_ioctl, + .mmap = gpx_mmap, + .alloc_screen = gpx_alloc_screen, + .free_screen = gpx_free_screen, + .show_screen = gpx_show_screen, + .load_font = NULL +}; + +static void gpx_clear_screen(struct gpx_screen *); +static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int); +static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int); +static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *); +static void gpx_loadcmap(struct gpx_screen *, int, int); +static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *); +static void gpx_resetcmap(struct gpx_screen *); +static void gpx_reset_viper(struct gpx_screen *); +static int gpx_setup_screen(struct gpx_screen *); +static void gpx_upload_font(struct gpx_screen *); +static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t); +static int gpx_wait(struct gpx_screen *, int); + +static void gpx_copycols(void *, int, int, int, int); +static void gpx_copyrows(void *, int, int, int); +static void gpx_do_cursor(struct rasops_info *); +static void gpx_erasecols(void *, int, int, int, long); +static void gpx_eraserows(void *, int, int, long); +static void gpx_putchar(void *, int, int, u_int, long); + +/* + * Autoconf glue + */ + +int +gpx_match(device_t parent, cfdata_t match, void *aux) +{ + struct vsbus_attach_args *va = aux; + volatile struct adder *adder; + vaddr_t tmp; + u_int depth; + u_short status; + + 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 hardware */ + adder = (volatile struct adder *) + vax_map_physmem(va->va_paddr + GPX_ADDER_OFFSET, 1); + if (adder == NULL) + return 0; + adder->status = 0; + status = adder->status; + vax_unmap_physmem((vaddr_t)adder, 1); + if (status == offsetof(struct adder, status)) + return 0; + + /* Check for a recognized color depth */ + tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1); + if (tmp == 0L) + return 0; + depth = (*(volatile uint16_t *)tmp) & 0x00f0; + vax_unmap_physmem(tmp, 1); + if (depth != 0x00f0 && depth != 0x0080) + return 0; + + /* when already running as console, always fake things */ + if ((vax_confdata & KA420_CFG_L3CON) == 0 +#if NWSDISPLAY > 0 + && cn_tab->cn_putc == wsdisplay_cnputc +#endif + ) { + struct vsbus_softc *sc = device_private(parent); + sc->sc_mask = 0x08; + scb_fake(0x44, 0x15); + } else { + adder = (struct adder *)vax_map_physmem(va->va_paddr + + GPX_ADDER_OFFSET, 1); + if (adder == NULL) + return 0; + adder->interrupt_enable = FRAME_SYNC; + DELAY(100000); /* enough to get a retrace interrupt */ + adder->interrupt_enable = 0; + vax_unmap_physmem((vaddr_t)adder, 1); + } + return 20; +} + +void +gpx_attach(device_t parent, device_t self, void *aux) +{ + struct gpx_softc *sc = device_private(self); + struct vsbus_attach_args *va = aux; + struct gpx_screen *scr; + struct wsemuldisplaydev_attach_args aa; + int console; + vaddr_t tmp; + + sc->sc_dev = self; + console = +#if NWSDISPLAY > 0 + (vax_confdata & KA420_CFG_L3CON) == 0 && + cn_tab->cn_putc == wsdisplay_cnputc; +#else + (vax_confdata & KA420_CFG_L3CON) == 0; +#endif + if (console) { + scr = &gpx_consscr; + sc->sc_nscreens = 1; + } else { + scr = kmem_zalloc(sizeof(*scr), KM_SLEEP); + + tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1); + if (tmp == 0L) { + printf(": can not probe depth\n"); + goto bad1; + } + scr->ss_depth = (*(uint16_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) { + aprint_error(": can not map frame buffer registers\n"); + goto bad1; + } + + scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr + + GPX_VDAC_OFFSET, 1); + if (scr->ss_vdac == NULL) { + aprint_error(": can not map RAMDAC\n"); + goto bad2; + } + +#if 0 + scr->ss_cursor = + (struct dc503reg *)vax_map_physmem(va->va_paddr + + GPX_CURSOR_OFFSET, 1); + if (scr->ss_cursor == NULL) { + aprint_error(": can not map cursor chip\n"); + goto bad3; + } +#endif + + if (gpx_setup_screen(scr) != 0) { + aprint_error(": initialization failed\n"); + goto bad4; + } + } + sc->sc_scr = scr; + + aprint_normal("\n"); + aprint_normal_dev(self, "%dx%d %d plane color framebuffer\n", + 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, CFARGS_NONE); + + return; + + bad4: +#if 0 + vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1); + bad3: +#endif + vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1); + bad2: + vax_unmap_physmem((vaddr_t)scr->ss_adder, 1); + bad1: + kmem_free(scr, sizeof(*scr)); +} + +/* + * wsdisplay accessops + */ + +int +gpx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) +{ + struct gpx_softc *sc = v; + struct gpx_screen *ss = sc->sc_scr; + struct wsdisplay_fbinfo *wdf; + struct wsdisplay_cmap *cm; + int error; + + 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: + cm = (struct wsdisplay_cmap *)data; + error = gpx_getcmap(ss, cm); + if (error != 0) + return error; + break; + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = gpx_putcmap(ss, cm); + if (error != 0) + return error; + gpx_loadcmap(ss, cm->index, cm->count); + break; + + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_SVIDEO: + break; + + case WSDISPLAYIO_LINEBYTES: /* no linear mapping */ + return -1; + + default: + return EPASSTHROUGH; + } + return 0; +} + +paddr_t +gpx_mmap(void *v, void *vs, 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.allocattr(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; +} + +/* + * 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, ul; + + rasops_unpack_attr(attr, &fg, &bg, &ul); + + /* 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->stride * NBBY; + 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; + + if (ul != 0) { + gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth, + 1, attr, LF_R3); /* fg fill */ + } +} + +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, uint16_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->interrupt_enable = 0; + 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 second 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 < 8; 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_ZEROS); + /* underline */ + gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES); + /* cursor */ + gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D); +} + +/* 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; + int cookie; + + memset(ri, 0, 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; + if (ss == &gpx_consscr) + ri->ri_flg |= RI_NO_AUTO; + + /* + * 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(); + cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L, + WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); + if (cookie < 0) + cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, + WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); + if (cookie < 0) + cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, + WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); + if (cookie < 0) + return -1; + if (wsfont_lock(cookie, &ri->ri_font) != 0) + return -1; + ri->ri_wsfcookie = cookie; + + /* + * 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; + + /* + * Initialize RAMDAC. + */ + if (ss->ss_depth == 8) { + struct ramdac8 *rd = ss->ss_vdac; + rd->address = BT_CR; + rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4; + } 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_resetcmap(ss); + + /* + * 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); + +#if 0 + ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI; +#endif + + 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; + uint8_t *fontbits, *fb; + u_int remaining, nchars, row; + u_int i, j; + uint16_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 font is uploaded in 8 or 16 bit wide cells, on + * as many ``lines'' as necessary at the end of the display. + */ + ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars); + if (ss->ss_gpr & 1) + ss->ss_gpr--; + fontbits = font->data; + for (row = 1, remaining = font->numchars; remaining != 0; + row++, remaining -= nchars) { + nchars = MIN(ss->ss_gpr, remaining); + + ss->ss_adder->destination_x = 0; + ss->ss_adder->destination_y = + GPX_HEIGHT - row * font->fontheight; + ss->ss_adder->fast_dest_dx = nchars * 16; + 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; + fontbits += font->stride; + /* PTOB a scan line */ + for (j = nchars; j != 0; j--) { + /* PTOB one scan of a char cell */ + if (font->stride == 1) { + data = *fb; + fb += font->fontheight; + /* + * Do not access past font memory if + * it has an odd number of characters + * and this is the last pair. + */ + if (j != 1 || (nchars & 1) == 0 || + remaining != nchars) { + data |= ((uint16_t)*fb) << 8; + fb += font->fontheight; + } + } else { + data = + fb[0] | (((uint16_t)fb[1]) << 8); + fb += font->fontheight * font->stride; + } + + gpx_wait(ss, TX_READY); + ss->ss_adder->id_data = data; + } + } + fontbits += (nchars - 1) * font->stride * 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)) + continue; + 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; + gpx_wait(ss, RASTEROP_COMPLETE); + 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); + gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg); + gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg); + 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; + gpx_wait(ss, RASTEROP_COMPLETE); + 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; +} + +/* + * Colormap handling routines + */ + +int +gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index, count = cm->count, i; + u_int colcount = 1 << ss->ss_depth; + int error; + uint8_t ramp[256], *c, *r; + + if (index >= colcount || count > colcount - index) + return EINVAL; + + /* extract reds */ + c = ss->ss_cmap + 0 + index * 3; + for (i = count, r = ramp; i != 0; i--) + *r++ = *c << (8 - ss->ss_depth), c += 3; + if ((error = copyout(ramp, cm->red, count)) != 0) + return error; + + /* extract greens */ + c = ss->ss_cmap + 1 + index * 3; + for (i = count, r = ramp; i != 0; i--) + *r++ = *c << (8 - ss->ss_depth), c += 3; + if ((error = copyout(ramp, cm->green, count)) != 0) + return error; + + /* extract blues */ + c = ss->ss_cmap + 2 + index * 3; + for (i = count, r = ramp; i != 0; i--) + *r++ = *c << (8 - ss->ss_depth), c += 3; + if ((error = copyout(ramp, cm->blue, count)) != 0) + return error; + + return 0; +} + +int +gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index, count = cm->count; + u_int colcount = 1 << ss->ss_depth; + int i, error; + uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c; + + if (index >= colcount || count > colcount - index) + return EINVAL; + + if ((error = copyin(cm->red, r, count)) != 0) + return error; + if ((error = copyin(cm->green, g, count)) != 0) + return error; + if ((error = copyin(cm->blue, b, count)) != 0) + return error; + + nr = r, ng = g, nb = b; + c = ss->ss_cmap + index * 3; + for (i = count; i != 0; i--) { + *c++ = *nr++ >> (8 - ss->ss_depth); + *c++ = *ng++ >> (8 - ss->ss_depth); + *c++ = *nb++ >> (8 - ss->ss_depth); + } + + return 0; +} + +void +gpx_loadcmap(struct gpx_screen *ss, int from, int count) +{ + uint8_t *cmap = ss->ss_cmap; + int i, color12; + + gpx_wait(ss, FRAME_SYNC); + if (ss->ss_depth == 8) { + struct ramdac8 *rd = ss->ss_vdac; + + cmap += from * 3; + rd->address = from; + for (i = 0; i < count * 3; i++) + rd->cmapdata = *cmap++; + } else { + struct ramdac4 *rd = ss->ss_vdac; + + cmap = ss->ss_cmap + from; + for (i = from; i < from + count; i++) { + color12 = (*cmap++ >> 4) << 0; + color12 |= (*cmap++ >> 4) << 8; + color12 |= (*cmap++ >> 4) << 4; + rd->colormap[i] = color12; + } + } +} + +void +gpx_resetcmap(struct gpx_screen *ss) +{ + + if (ss->ss_depth == 8) + memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap)); + else { + memcpy(ss->ss_cmap, rasops_cmap, 8 * 3); + memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3); + } + gpx_loadcmap(ss, 0, 1 << ss->ss_depth); + + /* + * On the 4bit RAMDAC, make the hardware cursor black on black + */ + if (ss->ss_depth != 8) { + struct ramdac4 *rd = ss->ss_vdac; + + rd->cursormap[0] = rd->cursormap[1] = + rd->cursormap[2] = rd->cursormap[3] = 0x0000; + } +} + +/* + * Console support code + */ + +cons_decl(gpx); + +/* + * 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(struct consdev *cndev) +{ + extern vaddr_t virtual_avail; + extern const struct cdevsw wsdisplay_cdevsw; + volatile struct adder *adder; + vaddr_t tmp; + int depth; + u_short status; + + switch (vax_boardtype) { + case VAX_BTYP_410: + case VAX_BTYP_420: + case VAX_BTYP_43: + if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0) + break; /* doesn't use graphics console */ + + if ((vax_confdata & KA420_CFG_VIDOPT) == 0) + break; /* no color option */ + + /* Check for hardware */ + tmp = virtual_avail; + ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1); + adder = (struct adder *)tmp; + adder->status = 0; + status = adder->status; + iounaccess(tmp, 1); + if (status == offsetof(struct adder, status)) + return; + + /* Check for a recognized color depth */ + tmp = virtual_avail; + ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); + depth = *(uint16_t *) + (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0; + iounaccess(tmp, 1); + if (depth != 0x00f0 && depth != 0x0080) + return; + + cndev->cn_pri = CN_INTERNAL; + cndev->cn_dev = + makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); + break; + + default: + break; + } +} + +/* + * 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 +gpxcninit(struct consdev *cndev) +{ + struct gpx_screen *ss = &gpx_consscr; + extern vaddr_t virtual_avail; + vaddr_t ova; + long defattr; + struct rasops_info *ri; + + ova = virtual_avail; + + ioaccess(virtual_avail, + vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); + ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail + + (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8; + + ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1); + ss->ss_adder = (struct adder *)virtual_avail; + virtual_avail += VAX_NBPG; + + ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1); + ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET)); + virtual_avail += VAX_NBPG; + +#if 0 + ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1); + ss->ss_cursor = (struct dc503reg *)virtual_avail; + virtual_avail += VAX_NBPG; +#endif + + virtual_avail = round_page(virtual_avail); + + /* this had better not fail */ + if (gpx_setup_screen(ss) != 0) { +#if 0 + iounaccess((vaddr_t)ss->ss_cursor, 1); +#endif + iounaccess((vaddr_t)ss->ss_vdac, 1); + iounaccess((vaddr_t)ss->ss_adder, 1); + virtual_avail = ova; + return; + } + + ri = &ss->ss_ri; + ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr); + wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr); + cn_tab->cn_pri = CN_INTERNAL; + +#if NDZKBD > 0 + dzkbd_cnattach(0); /* Connect keyboard and screen together */ +#endif +}