summaryrefslogtreecommitdiff
path: root/sys/arch/sgi
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2007-11-27 15:31:01 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2007-11-27 15:31:01 +0000
commit91e4040d93a4e30e2f59e581c586043a49d31e39 (patch)
treeacbed2ce71d3a9411e26e01fdccd1112e57fc2c4 /sys/arch/sgi
parentd1f8f49d4141edeb39ba6fbf589c776b8485f27d (diff)
Initial support for the SGI Graphics Back End (GBE) frame buffer found in
SGI O2 machines. We currently rely on the video hardware being initialised by the ARCS firmware and can only use the initial resolution with a colour depth of 32 bits. This driver is disabled by default. ok miod@
Diffstat (limited to 'sys/arch/sgi')
-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
4 files changed, 652 insertions, 2 deletions
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