summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/man4.sgi/gbe.450
-rw-r--r--sys/arch/sgi/conf/GENERIC6
-rw-r--r--sys/arch/sgi/conf/files.sgi7
-rw-r--r--sys/arch/sgi/dev/gbe.c553
-rw-r--r--sys/arch/sgi/dev/gbereg.h88
5 files changed, 702 insertions, 2 deletions
diff --git a/share/man/man4/man4.sgi/gbe.4 b/share/man/man4/man4.sgi/gbe.4
new file mode 100644
index 00000000000..9efb1194777
--- /dev/null
+++ b/share/man/man4/man4.sgi/gbe.4
@@ -0,0 +1,50 @@
+.\"
+.\" Copyright (c) 2007, Joel Sing <jsing@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: November 27 2007 $
+.Dt GBE 4 sgi
+.Os
+.Sh NAME
+.Nm gbe
+.Nd SGI Graphics Back End (GBE) Frame Buffer
+.Sh SYNOPSIS
+.Cd "gbe0 at mainbus0"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the on-board Graphics Back End (GBE) frame
+buffer found in SGI
+.Tn O2
+machines. Console support is provided by the
+.Xr wscons 4
+console framework.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr wscons 4 ,
+.Xr wsdisplay 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 4.3 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Joel Sing .
+.Sh BUGS
+Hardware initialization must currently be performed by the ARCS firmware.
+The resolution configured by the firmware will be used, with a fixed
+color depth of 32 bits.
diff --git a/sys/arch/sgi/conf/GENERIC b/sys/arch/sgi/conf/GENERIC
index 27ec1c40fee..163cae86788 100644
--- a/sys/arch/sgi/conf/GENERIC
+++ b/sys/arch/sgi/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.22 2007/10/18 18:59:29 jsing Exp $
+# $OpenBSD: GENERIC,v 1.23 2007/11/27 15:31:00 jsing Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -47,6 +47,9 @@ cpu* at mainbus0
#crimebus0 at mainbus0
macebus0 at mainbus0 # MACE controller localbus.
+# GBE Framebuffer
+gbe0 at mainbus0 disable
+
# Localbus devices
clock0 at macebus0
mec0 at macebus0 sys 0x18 base 0x00280000 irq 4
@@ -110,6 +113,7 @@ audio* at emu?
#### WS console
#wsdisplay* at vga?
#wskbd* at ukbd? mux 1
+wsdisplay* at gbe?
#### Keyboard and Mouse
pckbd* at mkbc?
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi
index 100cc12e849..70dd2fd625d 100644
--- a/sys/arch/sgi/conf/files.sgi
+++ b/sys/arch/sgi/conf/files.sgi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sgi,v 1.14 2007/10/18 18:59:29 jsing Exp $
+# $OpenBSD: files.sgi,v 1.15 2007/11/27 15:31:00 jsing Exp $
#
# maxpartitions must be first item in files.${ARCH}
#
@@ -84,6 +84,11 @@ attach clock at macebus with clock_macebus
attach clock at xbowmux with clock_xbowmux
file arch/sgi/sgi/clock_md.c clock
+# GBE framebuffer
+device gbe: wsemuldisplaydev, rasops8, rasops16, rasops32
+attach gbe at mainbus
+file arch/sgi/dev/gbe.c gbe
+
# 16[45]50-based "com" ports on localbus
attach com at xbowmux with com_xbow
attach com at macebus with com_localbus
diff --git a/sys/arch/sgi/dev/gbe.c b/sys/arch/sgi/dev/gbe.c
new file mode 100644
index 00000000000..7668190fe93
--- /dev/null
+++ b/sys/arch/sgi/dev/gbe.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2007, Joel Sing <jsing@openbsd.org>
+ *
+ * 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.
+ */
+
+/*
+ * Graphics Back End (GBE) Framebuffer for SGI O2
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <mips64/arcbios.h>
+#include <mips64/archtype.h>
+
+#include <sgi/localbus/crimebus.h>
+#include <sgi/localbus/macebus.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+
+#include "gbereg.h"
+
+struct gbe_softc {
+ struct device sc_dev;
+ struct rasops_info ri; /* Raster display info */
+
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+
+ bus_dma_tag_t dmat;
+
+ bus_dmamap_t tm_dmamap;
+ bus_dmamap_t fb_dmamap;
+
+ bus_dma_segment_t tm_segs[1];
+ bus_dma_segment_t fb_segs[1];
+
+ int tm_nsegs;
+ int fb_nsegs;
+
+ int fb_size; /* Size of framebuffer memory */
+ int tm_size; /* Size of tilemap memory */
+
+ caddr_t tilemap; /* Address of tilemap memory */
+ caddr_t fb; /* Address of framebuffer memory */
+
+ int rev; /* Revision */
+ int console; /* Is this the console? */
+ int screens; /* No of screens allocated */
+
+ int width; /* Width in pixels */
+ int height; /* Height in pixels */
+ int depth; /* Colour depth in bits */
+ int linebytes; /* Bytes per line */
+};
+
+void gbe_disable(struct gbe_softc *);
+
+/*
+ * Interfaces for wscons.
+ */
+
+int gbe_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t gbe_mmap(void *, off_t, int);
+int gbe_alloc_screen(void *, const struct wsscreen_descr *, void **,
+ int *, int *, long *);
+void gbe_free_screen(void *, void *);
+int gbe_show_screen(void *, void *, int, void (*)(void *, int, int),
+ void *);
+void gbe_burner(void *, u_int, u_int);
+
+struct wsscreen_descr gbe_stdscreen = {
+ "std", /* Screen name */
+};
+
+struct wsdisplay_accessops gbe_accessops = {
+ gbe_ioctl,
+ gbe_mmap,
+ gbe_alloc_screen,
+ gbe_free_screen,
+ gbe_show_screen,
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ gbe_burner,
+ NULL /* pollc */
+};
+
+const struct wsscreen_descr *gbe_scrlist[] = {
+ &gbe_stdscreen
+};
+
+struct wsscreen_list gbe_screenlist = {
+ sizeof(gbe_scrlist) / sizeof(struct wsscreen_descr *), gbe_scrlist
+};
+
+int gbe_match(struct device *, void *, void *);
+void gbe_attach(struct device *, struct device *, void *);
+
+struct cfattach gbe_ca = {
+ sizeof (struct gbe_softc), gbe_match, gbe_attach
+};
+
+struct cfdriver gbe_cd = {
+ NULL, "gbe", DV_DULL
+};
+
+int
+gbe_match(struct device *parent, void *cf, void *aux)
+{
+ /* GBE framebuffer only on SGI O2 (for now anyway). */
+ if (sys_config.system_type == SGI_O2)
+ return 1;
+
+ return 0;
+}
+
+void
+gbe_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gbe_softc *gsc = (void*)self;
+ struct wsemuldisplaydev_attach_args waa;
+ uint16_t *tm;
+ uint32_t val;
+ int i;
+#ifdef notyet
+ char *cp;
+#endif
+
+ printf(": ");
+
+ /* GBE isn't strictly on the crimebus, but use this for now... */
+ gsc->iot = &crimebus_tag;
+ gsc->dmat = &mace_bus_dma_tag;
+ gsc->console = 0; /* XXX for now! */
+ gsc->screens = 0;
+
+ /*
+ * Setup bus space mapping.
+ */
+ if (bus_space_map(gsc->iot, GBE_BASE - CRIMEBUS_BASE, 0x100000,
+ BUS_SPACE_MAP_LINEAR, &gsc->ioh)) {
+ printf("failed to map bus space!\n");
+ return;
+ }
+
+ /* Determine GBE revision. */
+ gsc->rev = bus_space_read_4(gsc->iot, gsc->ioh, GBE_CTRL_STAT) & 0xf;
+
+ /* Determine resolution configured by firmware. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_HCMAP);
+ gsc->width = (val >> GBE_VT_HCMAP_ON_SHIFT) & 0xfff;
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_VCMAP);
+ gsc->height = (val >> GBE_VT_VCMAP_ON_SHIFT) & 0xfff;
+
+ if (gsc->width == 0 || gsc->height == 0) {
+ printf("device has not been setup by firmware!\n");
+ goto fail0;
+ }
+
+ /* Determine colour depth configured by firmware. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE);
+ gsc->depth = 0x8 << ((val >> GBE_FB_SIZE_TILE_DEPTH_SHIFT) & 0x3);
+
+ /* XXX 8MB and 32bpp for now. */
+ gsc->fb_size = 8 * 1024 * 1024;
+ gsc->tm_size = GBE_TLB_SIZE * sizeof(uint16_t);
+ gsc->depth = 32;
+ gsc->linebytes = gsc->width * gsc->depth / 8;
+
+ /*
+ * Setup DMA for tile map.
+ */
+
+ if (bus_dmamap_create(gsc->dmat, gsc->tm_size, 1, gsc->tm_size, 0,
+ BUS_DMA_NOWAIT, &gsc->tm_dmamap)) {
+ printf("failed to create DMA map for tile map!\n");
+ goto fail0;
+ }
+
+ if (bus_dmamem_alloc(gsc->dmat, gsc->tm_size, 65536, 0, gsc->tm_segs, 1,
+ &gsc->tm_nsegs, BUS_DMA_NOWAIT)) {
+ printf("failed to allocate DMA memory for tile map!\n");
+ goto fail1;
+ }
+
+ if (bus_dmamem_map(gsc->dmat, gsc->tm_segs, gsc->tm_nsegs, gsc->tm_size,
+ &gsc->tilemap, BUS_DMA_COHERENT)) {
+ printf("failed to map DMA memory for tile map!\n");
+ goto fail2;
+ }
+
+ if (bus_dmamap_load(gsc->dmat, gsc->tm_dmamap, gsc->tilemap,
+ gsc->tm_size, NULL, BUS_DMA_NOWAIT)){
+ printf("failed to load DMA map for tilemap\n");
+ goto fail3;
+ }
+
+ /*
+ * Setup DMA for framebuffer.
+ */
+
+ if (bus_dmamap_create(gsc->dmat, gsc->fb_size, 1, gsc->fb_size, 0,
+ BUS_DMA_NOWAIT, &gsc->fb_dmamap)) {
+ printf("failed to create DMA map for framebuffer!\n");
+ goto fail4;
+ }
+
+ if (bus_dmamem_alloc(gsc->dmat, gsc->fb_size, 65536, 0, gsc->fb_segs,
+ 1, &gsc->fb_nsegs, BUS_DMA_NOWAIT)) {
+ printf("failed to allocate DMA memory for framebuffer!\n");
+ goto fail5;
+ }
+
+ if (bus_dmamem_map(gsc->dmat, gsc->fb_segs, gsc->fb_nsegs, gsc->fb_size,
+ &gsc->fb, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
+ printf("failed to map DMA memory for framebuffer!\n");
+ goto fail6;
+ }
+
+ if (bus_dmamap_load(gsc->dmat, gsc->fb_dmamap, gsc->fb, gsc->fb_size,
+ NULL, BUS_DMA_NOWAIT)) {
+ printf("failed to load DMA map for framebuffer\n");
+ goto fail7;
+ }
+
+ shutdownhook_establish((void(*)(void *))gbe_disable, self);
+
+ /*
+ * Initialise rasops.
+ */
+ memset(&gsc->ri, 0, sizeof(struct rasops_info));
+
+ gsc->ri.ri_flg = RI_CENTER | RI_CLEAR;
+ gsc->ri.ri_depth = gsc->depth;
+ gsc->ri.ri_width = gsc->width;
+ gsc->ri.ri_height = gsc->height;
+ gsc->ri.ri_bits = (void *)gsc->fb;
+ gsc->ri.ri_stride = gsc->linebytes;
+
+ if (gsc->depth == 32) {
+ gsc->ri.ri_rpos = 24;
+ gsc->ri.ri_rnum = 8;
+ gsc->ri.ri_gpos = 16;
+ gsc->ri.ri_gnum = 8;
+ gsc->ri.ri_bpos = 8;
+ gsc->ri.ri_bnum = 8;
+ }
+
+ rasops_init(&gsc->ri, gsc->height / 8, gsc->width / 8);
+
+ /*
+ * Map framebuffer into tile map. Each entry in the tilemap is 16 bits
+ * wide. Each tile is 64KB or 2^16 bits, hence the last 16 bits of the
+ * address will range from 0x0000 to 0xffff. As a result we simply
+ * discard the lower 16 bits and store bits 17 through 32 as an entry
+ * in the tilemap.
+ */
+ tm = (void *)gsc->tilemap;
+ for (i = 0; i < (gsc->fb_size >> GBE_TILE_SHIFT); i++)
+ tm[i] = (gsc->fb_dmamap->dm_segs[0].ds_addr >> GBE_TILE_SHIFT) + i;
+
+ /* Disable DMA. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_OVERLAY_CTRL);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_OVERLAY_CTRL,
+ val & ~GBE_OVERLAY_CTRL_DMA_ENABLE);
+ delay(1000);
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_FB_CTRL);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_CTRL,
+ val & ~GBE_FB_CTRL_DMA_ENABLE);
+ delay(1000);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_DID_CTRL, 0);
+ delay(1000);
+
+ /* Freeze pixel counter. */
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_VT_XY, GBE_VT_XY_FREEZE);
+ delay(10000);
+ for (i = 0; i < 10000; i++) {
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_XY);
+ if ((val & GBE_VT_XY_FREEZE) == GBE_VT_XY_FREEZE)
+ break;
+ delay(10);
+ }
+ if (i == 10000)
+ printf("timeout freezing pixel counter!\n");
+
+ /* Disable dot clock. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK,
+ val & ~GBE_DOTCLOCK_RUN);
+ delay(10000);
+ for (i = 0; i < 10000; i++) {
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK);
+ if ((val & GBE_DOTCLOCK_RUN) == 0)
+ break;
+ delay(10);
+ }
+ if (i == 10000)
+ printf("timeout disabling dot clock!\n");
+
+ /* Reset DMA fifo. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE);
+ val &= ~(1 << GBE_FB_SIZE_TILE_FIFO_RESET_SHIFT);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE,
+ val | (1 << GBE_FB_SIZE_TILE_FIFO_RESET_SHIFT));
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE, val);
+
+ /* Disable overlay and turn off hardware cursor. */
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_OVERLAY_TILE, 0);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_CURSOR_CTRL, 0);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_DID_CTRL, 0);
+
+ /* Trick framebuffer into linear mode. */
+ i = gsc->width * gsc->height / (512 / (gsc->depth >> 3));
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_PIXEL,
+ i << GBE_FB_SIZE_PIXEL_HEIGHT_SHIFT);
+
+ /* Setup framebuffer - fixed at 32bpp for now. */
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE,
+ (1 << GBE_FB_SIZE_TILE_WIDTH_SHIFT) |
+ (GBE_FB_DEPTH_32 << GBE_FB_SIZE_TILE_DEPTH_SHIFT));
+ val = (GBE_CMODE_RGB8 << GBE_WID_MODE_SHIFT) | GBE_BMODE_BOTH;
+ for (i = 0; i < (32 * 4); i += 4)
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_MODE + i, val);
+
+ /* Enable dot clock. */
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK,
+ val | GBE_DOTCLOCK_RUN);
+ delay(10000);
+ for (i = 0; i < 10000; i++) {
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_DOTCLOCK);
+ if ((val & GBE_DOTCLOCK_RUN) == GBE_DOTCLOCK_RUN)
+ break;
+ delay(10);
+ }
+ if (i == 10000)
+ printf("timeout enabling dot clock!\n");
+
+ /* Unfreeze pixel counter. */
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_VT_XY, 0);
+ delay(10000);
+ for (i = 0; i < 10000; i++) {
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_XY);
+ if ((val & GBE_VT_XY_FREEZE) == 0)
+ break;
+ delay(10);
+ }
+ if (i == 10000)
+ printf("timeout unfreezing pixel counter!\n");
+
+ /* Provide GBE with address of tile map and enable DMA. */
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_CTRL,
+ ((gsc->tm_dmamap->dm_segs[0].ds_addr >> 9) <<
+ GBE_FB_CTRL_TILE_PTR_SHIFT) | GBE_FB_CTRL_DMA_ENABLE);
+
+ printf("rev %u, %iMB, %dx%d at %d bits\n", gsc->rev, gsc->fb_size >> 20,
+ gsc->width, gsc->height, gsc->depth);
+
+#ifdef notyet
+ cp = Bios_GetEnvironmentVariable("ConsoleOut");
+ if (cp != NULL && strncmp(cp, "video", 5) == 0) {
+ wsdisplay_cnattach(&gbe_stdscreen, &gsc->ri, 0, 0, /*defattr*/ 0);
+ gsc->console = 1;
+ }
+#endif
+
+ /*
+ * Setup default screen and attach wsdisplay.
+ */
+
+ gbe_stdscreen.ncols = gsc->ri.ri_cols;
+ gbe_stdscreen.nrows = gsc->ri.ri_rows;
+ gbe_stdscreen.textops = &gsc->ri.ri_ops;
+ gbe_stdscreen.fontwidth = gsc->ri.ri_font->fontwidth;
+ gbe_stdscreen.fontheight = gsc->ri.ri_font->fontheight;
+ gbe_stdscreen.capabilities = gsc->ri.ri_caps;
+
+ waa.console = gsc->console;
+ waa.scrdata = &gbe_screenlist;
+ waa.accessops = &gbe_accessops;
+ waa.accesscookie = self;
+ config_found(self, &waa, wsemuldisplaydevprint);
+
+ return;
+
+fail7:
+ bus_dmamem_unmap(gsc->dmat, gsc->fb, gsc->fb_size);
+fail6:
+ bus_dmamem_free(gsc->dmat, gsc->fb_segs, gsc->fb_nsegs);
+fail5:
+ bus_dmamap_destroy(gsc->dmat, gsc->fb_dmamap);
+fail4:
+ bus_dmamap_unload(gsc->dmat, gsc->tm_dmamap);
+fail3:
+ bus_dmamem_unmap(gsc->dmat, gsc->tilemap, gsc->tm_size);
+fail2:
+ bus_dmamem_free(gsc->dmat, gsc->tm_segs, gsc->tm_nsegs);
+fail1:
+ bus_dmamap_destroy(gsc->dmat, gsc->tm_dmamap);
+fail0:
+ bus_space_unmap(gsc->iot, gsc->ioh, 0x100000);
+}
+
+/*
+ * GBE hardware specific functions.
+ */
+
+void
+gbe_disable(struct gbe_softc *gsc)
+{
+ uint32_t val;
+
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_FB_CTRL);
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_CTRL,
+ val & ~GBE_FB_CTRL_DMA_ENABLE);
+}
+
+/*
+ * Interfaces for wscons.
+ */
+
+int
+gbe_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct gbe_softc *gsc = (struct gbe_softc *)v;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_GBE;
+ break;
+
+ case WSDISPLAYIO_GINFO:
+ {
+ struct wsdisplay_fbinfo *fb = (struct wsdisplay_fbinfo *)data;
+
+ fb->height = gsc->height;
+ fb->width = gsc->width;
+ fb->depth = gsc->depth;
+ fb->cmsize = gsc->depth == 8 ? 256 : 0;
+ }
+ break;
+
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = gsc->linebytes;
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ if (gsc->depth == 8) {
+#ifdef notyet
+ struct wsdisplay_cmap *cm =
+ (struct wsdisplay_cmap *)data;
+
+ rc = gbe_getcmap(&scr->scr_cmap, cm);
+ if (rc != 0)
+ return (rc);
+#endif
+ }
+ break;
+
+ case WSDISPLAYIO_PUTCMAP:
+ if (gsc->depth == 8) {
+#ifdef notyet
+ struct wsdisplay_cmap *cm =
+ (struct wsdisplay_cmap *)data;
+
+ rc = gbe_putcmap(&scr->scr_cmap, cm);
+ if (rc != 0)
+ return (rc);
+ gbe_loadcmap(sc, cm->index, cm->index + cm->count);
+#endif
+ }
+ break;
+
+ case WSDISPLAYIO_GVIDEO:
+ case WSDISPLAYIO_SVIDEO:
+ /* Handled by the upper layer. */
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+paddr_t
+gbe_mmap(void *v, off_t offset, int protection)
+{
+ /* Not at the moment. */
+ return (-1);
+}
+
+int
+gbe_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+ int *curxp, int *curyp, long *attrp)
+{
+ struct gbe_softc *gsc = (struct gbe_softc *)v;
+
+ /* We do not allow multiple consoles at the moment. */
+ if (gsc->screens > 0)
+ return (ENOMEM);
+
+ gsc->screens++;
+
+ /* Return rasops_info via cookie. */
+ *cookiep = &gsc->ri;
+
+ /* Move cursor to top left of screen. */
+ *curxp = 0;
+ *curyp = 0;
+
+ /* Correct screen attributes. */
+ gsc->ri.ri_ops.alloc_attr(&gsc->ri, 0, 0, 0, attrp);
+
+ return 0;
+}
+
+void
+gbe_free_screen(void *v, void *cookie)
+{
+ /* We do not allow multiple consoles at the moment. */
+}
+
+int
+gbe_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
+ void *cbarg)
+{
+ /* We do not allow multiple consoles at the moment. */
+ return (0);
+}
+
+void
+gbe_burner(void *v, u_int on, u_int flags)
+{
+}
diff --git a/sys/arch/sgi/dev/gbereg.h b/sys/arch/sgi/dev/gbereg.h
new file mode 100644
index 00000000000..615b43bd6d2
--- /dev/null
+++ b/sys/arch/sgi/dev/gbereg.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2007, Joel Sing <jsing@openbsd.org>
+ *
+ * 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.
+ */
+
+/*
+ * GBE Framebuffer for SGI O2.
+ */
+
+#define GBE_BASE 0x16000000
+#define GBE_TLB_SIZE 128
+
+#define GBE_TILE_SHIFT 16
+#define GBE_TILE_SIZE (1 << GBE_TILE_SHIFT)
+
+/*
+ * Register locations.
+ */
+
+#define GBE_CTRL_STAT 0x00000000 /* General control/status */
+#define GBE_DOTCLOCK 0x00000004 /* Dotclock */
+#define GBE_DOTCLOCK_RUN 0x00100000 /* Enable dotclock */
+#define GBE_VT_XY 0x00010000 /* Current dot coordinates */
+#define GBE_VT_XY_FREEZE 0x80000000 /* Freeze pixel counter */
+#define GBE_VT_MAXXY 0x00010004 /* */
+#define GBE_VT_VSYNC 0x00010008 /* Vertical sync on/off */
+#define GBE_VT_HSYNC 0x0001000c /* Horizontal sync on/off */
+#define GBE_VT_VBLANK 0x00010010 /* Vertical blanking */
+#define GBE_VT_HBLANK 0x00010014 /* Horizontal blanking */
+#define GBE_VT_FLAGS 0x00010018 /* Video timing flags */
+#define GBE_VT_SYNC_LOW 0x00000010 /* Sync on green */
+#define GBE_VT_HPIXEN 0x00010034 /* Horizontal pixel on/off */
+#define GBE_VT_VPIXEN 0x00010038 /* Vertical pixel on/off */
+#define GBE_VT_HCMAP 0x0001003c /* Horizontal cmap write */
+#define GBE_VT_HCMAP_ON_SHIFT 12
+#define GBE_VT_VCMAP 0x00010040 /* Vertical cmap write */
+#define GBE_VT_VCMAP_ON_SHIFT 12
+#define GBE_VT_DIDSTARTXY 0x00010044 /* DID reset at x/y */
+#define GBE_VT_CRSSTARTXY 0x00010048 /* CRS reset at x/y */
+#define GBE_VT_VCSTARTXY 0x0001004c /* VC reset at x/y */
+#define GBE_OVERLAY_TILE 0x00020000 /* Overlay plane - tile width */
+#define GBE_OVERLAY_HW_CTRL 0x00020004 /* Overlay plane - h/w control */
+#define GBE_OVERLAY_CTRL 0x00020008 /* Overlay plane - control */
+#define GBE_OVERLAY_CTRL_DMA_ENABLE 0x00000001
+#define GBE_FB_SIZE_TILE 0x00030000 /* Framebuffer - tile size */
+#define GBE_FB_SIZE_TILE_WIDTH_SHIFT 5
+#define GBE_FB_SIZE_TILE_DEPTH_SHIFT 13
+#define GBE_FB_SIZE_TILE_FIFO_RESET_SHIFT 15
+#define GBE_FB_SIZE_PIXEL 0x00030004 /* Framebuffer - pixel size */
+#define GBE_FB_SIZE_PIXEL_HEIGHT_SHIFT 16
+#define GBE_FB_CTRL 0x0003000c /* Framebuffer - control */
+#define GBE_FB_CTRL_TILE_PTR_SHIFT 9
+#define GBE_FB_CTRL_DMA_ENABLE 0x00000001
+#define GBE_DID_CTRL 0x00040004 /* DID control */
+#define GBE_MODE 0x00048000 /* Colour mode */
+#define GBE_WID_MODE_SHIFT 2
+#define GBE_CURSOR_POS 0x00070000 /* Cursor position */
+#define GBE_CURSOR_CTRL 0x00070004 /* Cursor control */
+
+/*
+ * Constants.
+ */
+
+#define GBE_FB_DEPTH_8 0
+#define GBE_FB_DEPTH_16 1
+#define GBE_FB_DEPTH_32 2
+
+#define GBE_CMODE_I8 0
+#define GBE_CMODE_I12 1
+#define GBE_CMODE_RG3B2 2
+#define GBE_CMODE_RGB4 3
+#define GBE_CMODE_ARGB5 4
+#define GBE_CMODE_RGB8 5
+#define GBE_CMODE_RGBA5 6
+#define GBE_CMODE_RGB10 7
+
+#define GBE_BMODE_BOTH 3