diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2008-08-20 19:00:02 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2008-08-20 19:00:02 +0000 |
commit | 0a888f23826234f38645bd474a4fee8001fd9ae9 (patch) | |
tree | b1d80ba2e920694d43aba95ee5579b79983e44a7 /sys/arch/vax/mbus | |
parent | 62934187ea5d446e8e7d2c0a26e417b36eafa442 (diff) |
Minimal driver for the VAXstation 35x0/38x0 LEGSS option, currently limited
to 8 bit mode operation, and no color or accelerated features until I can
find documentation about it.
Speed is decent by VAX standards, except for scrolling, which is so
abysmally slow one could see ZZ Top's beards growing while waiting for the
screen to scroll...
Diffstat (limited to 'sys/arch/vax/mbus')
-rw-r--r-- | sys/arch/vax/mbus/files.mbus | 12 | ||||
-rw-r--r-- | sys/arch/vax/mbus/legss.c | 428 |
2 files changed, 436 insertions, 4 deletions
diff --git a/sys/arch/vax/mbus/files.mbus b/sys/arch/vax/mbus/files.mbus index 8b692910545..88d0de15eea 100644 --- a/sys/arch/vax/mbus/files.mbus +++ b/sys/arch/vax/mbus/files.mbus @@ -1,4 +1,4 @@ -# $OpenBSD: files.mbus,v 1.1 2008/08/18 23:19:25 miod Exp $ +# $OpenBSD: files.mbus,v 1.2 2008/08/20 19:00:01 miod Exp $ # VAXstation 3[58][24]0 internal bus device mbus { [mid = -1] } @@ -19,11 +19,15 @@ file arch/vax/mbus/if_le_fwio.c le_fwio attach sii at fwio with sii_fwio file arch/vax/mbus/sii_fwio.c sii_fwio -# L2008 CQBIC +# L2004 LEGSS video +# (with L2005 8-plane output module and optional L2006 16-plane module) +device legss: wsemuldisplaydev, rasops32 +attach legss at mbus +file arch/vax/mbus/legss.c legss needs-flag + +# L2008 FQAM (CQBIC) attach uba at mbus with uba_mbus file arch/vax/mbus/uba_mbus.c uba_mbus # L2001 or L2010 CPU -# L2004 LEGSS video -# (with L2005 8-plane output module and optional L2006 16-plane module) # L2007 memory diff --git a/sys/arch/vax/mbus/legss.c b/sys/arch/vax/mbus/legss.c new file mode 100644 index 00000000000..3b73ce80f33 --- /dev/null +++ b/sys/arch/vax/mbus/legss.c @@ -0,0 +1,428 @@ +/* $OpenBSD: legss.c,v 1.1 2008/08/20 19:00:01 miod Exp $ */ + +/* + * Copyright (c) 2008 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 and this permission notice 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. + */ + +/* + * LEGSS frame buffer + * + * This beast is different enough from a QDSS or a GPX to need a specific + * driver. Unfortunately, it is not yet known how this hardware works. + * + * The frame buffer memory is accessible linearly in 32 bit words (one + * per pixel, although apparently only 20 bits are writable). + * + * We currently drive the frame buffer as a monochrome, unaccelerated + * display. + * + * Note that the hardware probe is made easier since graphics can only + * exist in the last M-Bus slot, and the terminal information in the SSC + * will tell us whether it is properly populated or not. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/conf.h> +#include <sys/kernel.h> + +#include <machine/cpu.h> +#include <machine/cvax.h> +#include <machine/sid.h> + +#include <vax/mbus/mbusreg.h> +#include <vax/mbus/mbusvar.h> + +#include <uvm/uvm_extern.h> + +#include <dev/cons.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/rasops/rasops.h> +#include <dev/wsfont/wsfont.h> + +/* Graphics can only exist at mid 7 */ +#define MID_GRAPHICS 7 +#define LEGSS_BASE MBUS_SLOT_BASE(MID_GRAPHICS) + +#define LEGSS_VRAM_OFFSET 0x00800000 + +#define LEGSS_VISWIDTH 1280 +#define LEGSS_WIDTH 2048 +#define LEGSS_VISHEIGHT 1024 +#define LEGSS_HEIGHT 2048 + +int legss_match(struct device *, void *, void *); +void legss_attach(struct device *, struct device *, void *); + +struct legss_screen { + struct rasops_info ss_ri; + int ss_console; + u_int ss_depth; + vaddr_t ss_vram; +}; + +/* for console */ +struct legss_screen legss_consscr; + +struct legss_softc { + struct device sc_dev; + struct legss_screen *sc_scr; + int sc_nscreens; +}; + +struct cfattach legss_ca = { + sizeof(struct legss_softc), legss_match, legss_attach, +}; + +struct cfdriver legss_cd = { + NULL, "legss", DV_DULL +}; + +struct wsscreen_descr legss_stdscreen = { + "std", +}; + +const struct wsscreen_descr *_legss_scrlist[] = { + &legss_stdscreen, +}; + +const struct wsscreen_list legss_screenlist = { + sizeof(_legss_scrlist) / sizeof(struct wsscreen_descr *), + _legss_scrlist, +}; + +int legss_ioctl(void *, u_long, caddr_t, int, struct proc *); +paddr_t legss_mmap(void *, off_t, int); +int legss_alloc_screen(void *, const struct wsscreen_descr *, + void **, int *, int *, long *); +void legss_free_screen(void *, void *); +int legss_show_screen(void *, void *, int, + void (*) (void *, int, int), void *); + +const struct wsdisplay_accessops legss_accessops = { + legss_ioctl, + legss_mmap, + legss_alloc_screen, + legss_free_screen, + legss_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + NULL /* burner */ +}; + +int legss_setup_screen(struct legss_screen *); +u_int legss_probe_depth(vaddr_t); + +/* + * Autoconf glue + */ + +int +legss_match(struct device *parent, void *vcf, void *aux) +{ + struct mbus_attach_args *maa = (struct mbus_attach_args *)aux; + + if (maa->maa_class == CLASS_GRAPHICS && + maa->maa_interface == INTERFACE_FBIC && + maa->maa_mid == MID_GRAPHICS) + return 1; + + return 0; +} + +void +legss_attach(struct device *parent, struct device *self, void *aux) +{ + struct legss_softc *sc = (struct legss_softc *)self; + struct legss_screen *scr; + struct wsemuldisplaydev_attach_args aa; + int console; + vaddr_t tmp; + extern struct consdev wsdisplay_cons; + + console = (vax_confdata & 0x60) != 0 && cn_tab == &wsdisplay_cons; + if (console) { + scr = &legss_consscr; + sc->sc_nscreens = 1; + } else { + scr = malloc(sizeof(struct legss_screen), M_DEVBUF, M_NOWAIT); + if (scr == NULL) { + printf(": can not allocate memory\n"); + return; + } + + tmp = vax_map_physmem(LEGSS_BASE + LEGSS_VRAM_OFFSET, 1); + if (tmp == 0L) { + printf(": can not probe depth\n"); + goto bad1; + } + scr->ss_depth = legss_probe_depth(tmp); + vax_unmap_physmem(tmp, 1); + + if (scr->ss_depth == 0) { + printf(": unrecognized depth\n"); + goto bad1; + } + + scr->ss_vram = vax_map_physmem(LEGSS_BASE + LEGSS_VRAM_OFFSET, + (LEGSS_VISHEIGHT * LEGSS_WIDTH * 32 / NBBY) / VAX_NBPG); + if (scr->ss_vram == 0L) { + printf(": can not map frame buffer\n"); + goto bad1; + } + + if (legss_setup_screen(scr) != 0) { + printf(": initialization failed\n"); + goto bad2; + } + } + sc->sc_scr = scr; + + printf(": %dx%d %d plane color framebuffer\n", + LEGSS_VISWIDTH, LEGSS_VISHEIGHT, scr->ss_depth); + + aa.console = console; + aa.scrdata = &legss_screenlist; + aa.accessops = &legss_accessops; + aa.accesscookie = sc; + aa.defaultscreens = 0; + + config_found(self, &aa, wsemuldisplaydevprint); + + return; + +bad2: + vax_unmap_physmem(scr->ss_vram, + (LEGSS_VISHEIGHT * LEGSS_WIDTH * 32 / NBBY) / VAX_NBPG); +bad1: + free(scr, M_DEVBUF); +} + +/* + * wsdisplay accessops + */ + +int +legss_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct legss_softc *sc = v; + struct legss_screen *ss = sc->sc_scr; + struct wsdisplay_fbinfo *wdf; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = 0; /* XXX WSDISPLAY_TYPE_LEGSS; */ + 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 = 0; + break; + + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = LEGSS_WIDTH * 32 / NBBY; + + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: + break; + + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_SVIDEO: + break; + + default: + return -1; + } + + return 0; +} + +paddr_t +legss_mmap(void *v, off_t offset, int prot) +{ + /* Do not allow mmap yet because of the read-only upper 12 bits */ + return -1; +} + +int +legss_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, + int *curxp, int *curyp, long *defattrp) +{ + struct legss_softc *sc = v; + struct legss_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 +legss_free_screen(void *v, void *cookie) +{ + struct legss_softc *sc = v; + + sc->sc_nscreens--; +} + +int +legss_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + return 0; +} + +int +legss_setup_screen(struct legss_screen *ss) +{ + struct rasops_info *ri = &ss->ss_ri; + + bzero(ri, sizeof(*ri)); + ri->ri_depth = 32; /* masquerade as a 32 bit device for rasops */ + ri->ri_width = LEGSS_VISWIDTH; + ri->ri_height = LEGSS_VISHEIGHT; + ri->ri_stride = LEGSS_WIDTH * 32 / NBBY; + ri->ri_flg = RI_FORCEMONO | RI_CENTER | RI_CLEAR; + ri->ri_hw = ss; + ri->ri_bits = (u_char *)ss->ss_vram; + + /* + * Ask for an unholy big display, rasops will trim this to more + * reasonable values. + */ + if (rasops_init(ri, 160, 160) != 0) + return -1; + + legss_stdscreen.ncols = ri->ri_cols; + legss_stdscreen.nrows = ri->ri_rows; + legss_stdscreen.textops = &ri->ri_ops; + legss_stdscreen.fontwidth = ri->ri_font->fontwidth; + legss_stdscreen.fontheight = ri->ri_font->fontheight; + legss_stdscreen.capabilities = ri->ri_caps; + + return 0; +} + +u_int +legss_probe_depth(vaddr_t vram) +{ + uint32_t probe; + + *(volatile uint32_t *)vram = 0; + *(volatile uint32_t *)vram = 0xffffffff; + probe = *(volatile uint32_t *)vram; + + /* + * Need to mask the upper 12 bits, they don't seem to be connected + * to anything and latch random bus data. + */ + switch (probe & 0x000fffff) { + case 0x00ff: + return 8; + default: + return 0; + } +} + +/* + * Console support code + */ + +int legsscnprobe(void); +int legsscninit(void); + +int +legsscnprobe() +{ + extern vaddr_t virtual_avail; + int depth; + + if (vax_boardtype != VAX_BTYP_60) + return 0; /* move along, nothing there */ + + /* no working graphics hardware, or forced serial console? */ + if ((vax_confdata & 0x60) == 0) + return 0; + + /* + * Check for a recognized color depth. + */ + + ioaccess(virtual_avail, LEGSS_BASE + LEGSS_VRAM_OFFSET, 1); + depth = legss_probe_depth(virtual_avail); + iounaccess(virtual_avail, 1); + + if (depth == 0) + return 0; /* unsupported, default to serial */ + + return 1; +} + +/* + * 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. + */ +int +legsscninit() +{ + struct legss_screen *ss = &legss_consscr; + extern vaddr_t virtual_avail; + vaddr_t ova; + long defattr; + struct rasops_info *ri; + + ova = virtual_avail; + + ioaccess(virtual_avail, LEGSS_BASE + LEGSS_VRAM_OFFSET, 1); + ss->ss_depth = legss_probe_depth(virtual_avail); + iounaccess(virtual_avail, 1); + if (ss->ss_depth == 0) + return 1; + + ioaccess(virtual_avail, LEGSS_BASE + LEGSS_VRAM_OFFSET, + (LEGSS_VISHEIGHT * LEGSS_WIDTH * 32 / NBBY) / VAX_NBPG); + ss->ss_vram = virtual_avail; + virtual_avail += (LEGSS_VISHEIGHT * LEGSS_WIDTH * 32 / NBBY); + virtual_avail = round_page(virtual_avail); + + /* this had better not fail */ + if (legss_setup_screen(ss) != 0) { + iounaccess(ss->ss_vram, + (LEGSS_VISHEIGHT * LEGSS_WIDTH * 32 / NBBY) / VAX_NBPG); + virtual_avail = ova; + return 1; + } + + ri = &ss->ss_ri; + ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr); + wsdisplay_cnattach(&legss_stdscreen, ri, 0, 0, defattr); + + return 0; +} |