summaryrefslogtreecommitdiff
path: root/sys/arch/sgi
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2010-03-04 14:50:36 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2010-03-04 14:50:36 +0000
commit362b413ed4f676c5cb0c69ebaac4fca2acafb315 (patch)
tree776b85fc168b29aeae3e55a88a1afec837eafe87 /sys/arch/sgi
parent6c7b46ab88c086928bfcbd0bd0c184cfb4273dca (diff)
Introduce odyssey(4), a driver for the SGI VPro (aka Odyssey) graphics
card, which can be found in Octane, Octane2, Fuel, Tezro and Onyx systems. ok miod@
Diffstat (limited to 'sys/arch/sgi')
-rw-r--r--sys/arch/sgi/conf/GENERIC-IP274
-rw-r--r--sys/arch/sgi/conf/GENERIC-IP304
-rw-r--r--sys/arch/sgi/xbow/files.xbow8
-rw-r--r--sys/arch/sgi/xbow/odyssey.c1048
-rw-r--r--sys/arch/sgi/xbow/odysseyreg.h62
5 files changed, 1123 insertions, 3 deletions
diff --git a/sys/arch/sgi/conf/GENERIC-IP27 b/sys/arch/sgi/conf/GENERIC-IP27
index 4581bfe74b9..ec5bb27e55f 100644
--- a/sys/arch/sgi/conf/GENERIC-IP27
+++ b/sys/arch/sgi/conf/GENERIC-IP27
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC-IP27,v 1.29 2010/02/01 22:06:27 jasper Exp $
+# $OpenBSD: GENERIC-IP27,v 1.30 2010/03/04 14:50:35 jsing Exp $
#
# THIS KERNEL IS FOR Origin, Onyx, Fuel, Tezro (IP27, IP35) SYSTEMS ONLY.
#
@@ -47,6 +47,8 @@ xbow* at mainbus0
xbridge* at xbow?
xbpci* at xbridge?
pci* at xbpci?
+odyssey* at xbow?
+wsdisplay* at odyssey?
# IOC3
ioc* at pci?
diff --git a/sys/arch/sgi/conf/GENERIC-IP30 b/sys/arch/sgi/conf/GENERIC-IP30
index fc0d763c3e3..34c1c7da3b8 100644
--- a/sys/arch/sgi/conf/GENERIC-IP30
+++ b/sys/arch/sgi/conf/GENERIC-IP30
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC-IP30,v 1.24 2010/02/01 22:06:27 jasper Exp $
+# $OpenBSD: GENERIC-IP30,v 1.25 2010/03/04 14:50:35 jsing Exp $
#
# THIS KERNEL IS FOR Octane and Octane 2 (IP30) SYSTEMS ONLY.
#
@@ -50,6 +50,8 @@ onewire* at xheart?
xbridge* at xbow?
xbpci* at xbridge?
pci* at xbpci?
+odyssey* at xbow?
+wsdisplay* at odyssey?
# IOC3
ioc* at pci?
diff --git a/sys/arch/sgi/xbow/files.xbow b/sys/arch/sgi/xbow/files.xbow
index 7287b097dfa..fb6d8d13590 100644
--- a/sys/arch/sgi/xbow/files.xbow
+++ b/sys/arch/sgi/xbow/files.xbow
@@ -1,4 +1,4 @@
-# $OpenBSD: files.xbow,v 1.5 2009/10/22 19:55:45 miod Exp $
+# $OpenBSD: files.xbow,v 1.6 2010/03/04 14:50:35 jsing Exp $
# IP30 and IP27 planar XBow bus
define xbow {[widget = -1], [vendor = -1], [product = -1]}
@@ -17,3 +17,9 @@ attach xbridge at xbow
device xbpci {[bus = -1]} : pcibus
attach xbpci at xbridge
file arch/sgi/xbow/xbridge.c xbridge
+
+# Odyssey graphics
+device odyssey: wsemuldisplaydev, rasops8, rasops16, rasops32
+attach odyssey at xbow
+file arch/sgi/xbow/odyssey.c odyssey needs-flag
+
diff --git a/sys/arch/sgi/xbow/odyssey.c b/sys/arch/sgi/xbow/odyssey.c
new file mode 100644
index 00000000000..b7cc082de55
--- /dev/null
+++ b/sys/arch/sgi/xbow/odyssey.c
@@ -0,0 +1,1048 @@
+/* $OpenBSD: odyssey.c,v 1.1 2010/03/04 14:50:35 jsing Exp $ */
+/*
+ * Copyright (c) 2009, 2010 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.
+ */
+
+/*
+ * Driver for the SGI VPro (aka Odyssey) Graphics Card.
+ */
+
+/*
+ * The details regarding the design and operation of this hardware, along with
+ * the necessary magic numbers, are only available thanks to the reverse
+ * engineering work undertaken by Stanislaw Skowronek <skylark@linux-mips.org>.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+
+#include <machine/autoconf.h>
+
+#include <mips64/arcbios.h>
+
+#include <sgi/xbow/xbow.h>
+#include <sgi/xbow/xbowdevs.h>
+#include <sgi/xbow/odysseyreg.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+
+/*
+ * Colourmap data.
+ */
+struct odyssey_cmap {
+ u_int8_t cm_red[256];
+ u_int8_t cm_green[256];
+ u_int8_t cm_blue[256];
+};
+
+/*
+ * Screen data.
+ */
+struct odyssey_screen {
+ struct device *sc; /* Back pointer. */
+
+ struct rasops_info ri; /* Screen raster display info. */
+ struct odyssey_cmap cmap; /* Display colour map. */
+ long attr; /* Rasops attributes. */
+
+ int width; /* Width in pixels. */
+ int height; /* Height in pixels. */
+ int depth; /* Colour depth in bits. */
+ int linebytes; /* Bytes per line. */
+ int ro_curpos; /* Current position in rasops tile. */
+};
+
+struct odyssey_softc {
+ struct device sc_dev;
+
+ struct mips_bus_space iot_store;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+
+ int console; /* Is this the console? */
+ int screens; /* No of screens allocated. */
+
+ struct odyssey_screen *curscr; /* Current screen. */
+};
+
+int odyssey_match(struct device *, void *, void *);
+void odyssey_attach(struct device *, struct device *, void *);
+
+void odyssey_cmd_wait(struct odyssey_softc *);
+void odyssey_data_wait(struct odyssey_softc *);
+void odyssey_cmd_flush(struct odyssey_softc *, int);
+
+void odyssey_setup(struct odyssey_softc *);
+void odyssey_init_screen(struct odyssey_screen *);
+
+/*
+ * Colour map handling for indexed modes.
+ */
+int odyssey_getcmap(struct odyssey_cmap *, struct wsdisplay_cmap *);
+int odyssey_putcmap(struct odyssey_cmap *, struct wsdisplay_cmap *);
+
+/*
+ * Hardware acceleration for rasops.
+ */
+void odyssey_rop(struct odyssey_softc *, int, int, int, int, int, int);
+void odyssey_copyrect(struct odyssey_softc *, int, int, int, int, int, int);
+void odyssey_fillrect(struct odyssey_softc *, int, int, int, int, u_int);
+int odyssey_do_cursor(struct rasops_info *);
+int odyssey_putchar(void *, int, int, u_int, long);
+int odyssey_copycols(void *, int, int, int, int);
+int odyssey_erasecols(void *, int, int, int, long);
+int odyssey_copyrows(void *, int, int, int);
+int odyssey_eraserows(void *, int, int, long);
+
+u_int32_t ieee754_sp(int32_t);
+
+/*
+ * Interfaces for wscons.
+ */
+int odyssey_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t odyssey_mmap(void *, off_t, int);
+int odyssey_alloc_screen(void *, const struct wsscreen_descr *, void **,
+ int *, int *, long *);
+void odyssey_free_screen(void *, void *);
+int odyssey_show_screen(void *, void *, int, void (*)(void *, int, int),
+ void *);
+void odyssey_burner(void *, u_int, u_int);
+
+struct wsscreen_descr odyssey_stdscreen = {
+ "std", /* Screen name. */
+};
+
+struct wsdisplay_accessops odyssey_accessops = {
+ odyssey_ioctl,
+ odyssey_mmap,
+ odyssey_alloc_screen,
+ odyssey_free_screen,
+ odyssey_show_screen,
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ odyssey_burner,
+ NULL /* pollc */
+};
+
+const struct wsscreen_descr *odyssey_scrlist[] = {
+ &odyssey_stdscreen
+};
+
+struct wsscreen_list odyssey_screenlist = {
+ nitems(odyssey_scrlist), odyssey_scrlist
+};
+
+const struct cfattach odyssey_ca = {
+ sizeof(struct odyssey_softc), odyssey_match, odyssey_attach,
+};
+
+struct cfdriver odyssey_cd = {
+ NULL, "odyssey", DV_DULL,
+};
+
+int
+odyssey_match(struct device *parent, void *match, void *aux)
+{
+ struct xbow_attach_args *xaa = aux;
+
+ if (xaa->xaa_vendor == XBOW_VENDOR_SGI2 &&
+ xaa->xaa_product == XBOW_PRODUCT_SGI2_ODYSSEY)
+ return 1;
+
+ return 0;
+}
+
+void
+odyssey_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct xbow_attach_args *xaa = aux;
+ struct wsemuldisplaydev_attach_args waa;
+ struct odyssey_softc *sc = (void *)self;
+ struct odyssey_screen *screen;
+
+ if (strncmp(bios_graphics, "alive", 5) != 0) {
+ printf(" device has not been setup by firmware!\n");
+ return;
+ }
+
+ printf(" revision %d\n", xaa->xaa_revision);
+
+ /*
+ * Create a copy of the bus space tag.
+ */
+ bcopy(xaa->xaa_iot, &sc->iot_store, sizeof(struct mips_bus_space));
+ sc->iot = &sc->iot_store;
+
+ /*
+ * Setup screen data.
+ */
+ sc->curscr = malloc(sizeof(struct odyssey_screen), M_DEVBUF, M_NOWAIT);
+ if (sc->curscr == NULL) {
+ printf("failed to allocate screen memory!\n");
+ return;
+ }
+ sc->curscr->sc = (void *)sc;
+ screen = sc->curscr;
+
+ /* Setup bus space mappings. */
+ if (bus_space_map(sc->iot, ODYSSEY_REG_OFFSET, ODYSSEY_REG_SIZE,
+ BUS_SPACE_MAP_LINEAR, &sc->ioh)) {
+ printf("failed to map framebuffer bus space!\n");
+ return;
+ }
+
+ /* Setup hardware and clear screen. */
+ odyssey_setup(sc);
+ odyssey_fillrect(sc, 0, 0, 1280, 1024, 0x000000);
+ odyssey_cmd_flush(sc, 0);
+
+ /* Set screen defaults. */
+ screen->width = 1280;
+ screen->height = 1024;
+ screen->depth = 32;
+ screen->linebytes = screen->width * screen->depth / 8;
+
+ odyssey_init_screen(screen);
+
+ waa.console = sc->console;
+ waa.scrdata = &odyssey_screenlist;
+ waa.accessops = &odyssey_accessops;
+ waa.accesscookie = screen;
+ config_found(self, &waa, wsemuldisplaydevprint);
+}
+
+void
+odyssey_init_screen(struct odyssey_screen *screen)
+{
+ u_char *colour;
+ int i;
+
+ /*
+ * Initialise screen.
+ */
+
+ /* Initialise rasops. */
+ memset(&screen->ri, 0, sizeof(struct rasops_info));
+
+ screen->ri.ri_flg = RI_CENTER;
+ screen->ri.ri_depth = screen->depth;
+ screen->ri.ri_width = screen->width;
+ screen->ri.ri_height = screen->height;
+ screen->ri.ri_stride = screen->linebytes;
+
+ if (screen->depth == 32) {
+ screen->ri.ri_bpos = 16;
+ screen->ri.ri_bnum = 8;
+ screen->ri.ri_gpos = 8;
+ screen->ri.ri_gnum = 8;
+ screen->ri.ri_rpos = 0;
+ screen->ri.ri_rnum = 8;
+ } else if (screen->depth == 16) {
+ screen->ri.ri_rpos = 10;
+ screen->ri.ri_rnum = 5;
+ screen->ri.ri_gpos = 5;
+ screen->ri.ri_gnum = 5;
+ screen->ri.ri_bpos = 0;
+ screen->ri.ri_bnum = 5;
+ }
+
+ rasops_init(&screen->ri, screen->height / 8, screen->width / 8);
+
+ /*
+ * Initialise colourmap, if required.
+ */
+ if (screen->depth == 8) {
+ for (i = 0; i < 16; i++) {
+ colour = (u_char *)&rasops_cmap[i * 3];
+ screen->cmap.cm_red[i] = colour[0];
+ screen->cmap.cm_green[i] = colour[1];
+ screen->cmap.cm_blue[i] = colour[2];
+ }
+ for (i = 240; i < 256; i++) {
+ colour = (u_char *)&rasops_cmap[i * 3];
+ screen->cmap.cm_red[i] = colour[0];
+ screen->cmap.cm_green[i] = colour[1];
+ screen->cmap.cm_blue[i] = colour[2];
+ }
+ }
+
+ screen->ri.ri_hw = screen->sc;
+
+ screen->ri.ri_ops.putchar = odyssey_putchar;
+ screen->ri.ri_do_cursor = odyssey_do_cursor;
+ screen->ri.ri_ops.copyrows = odyssey_copyrows;
+ screen->ri.ri_ops.copycols = odyssey_copycols;
+ screen->ri.ri_ops.eraserows = odyssey_eraserows;
+ screen->ri.ri_ops.erasecols = odyssey_erasecols;
+
+ odyssey_stdscreen.ncols = screen->ri.ri_cols;
+ odyssey_stdscreen.nrows = screen->ri.ri_rows;
+ odyssey_stdscreen.textops = &screen->ri.ri_ops;
+ odyssey_stdscreen.fontwidth = screen->ri.ri_font->fontwidth;
+ odyssey_stdscreen.fontheight = screen->ri.ri_font->fontheight;
+ odyssey_stdscreen.capabilities = screen->ri.ri_caps;
+}
+
+/*
+ * Hardware initialisation.
+ */
+void
+odyssey_setup(struct odyssey_softc *sc)
+{
+ u_int64_t val;
+ int i;
+
+ /* Initialise Buzz Graphics Engine. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x20008003);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x21008010);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x22008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x23008002);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2400800c);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2500800e);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x27008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x28008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x290080d6);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2a0080e0);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2c0080ea);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2e008380);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2f008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x30008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x31008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x32008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x33008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x35008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x310081e0);
+ odyssey_cmd_flush(sc, 0);
+
+ /* Initialise Buzz X-Form. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x9080bda2);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0xbf800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4e000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x40400000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4e000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4d000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x9080bdc8);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008010);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x908091df);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
+ odyssey_cmd_flush(sc, 0);
+
+ /* Initialise Buzz Raster. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001203b);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001084a);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000080);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000080);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010845);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000ff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000076ff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001141b);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000001);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011c16);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x03000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011023);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ff0ff0);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ff0ff0);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000ff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011017);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000050);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x20004950);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001204b);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x004ff3ff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ odyssey_cmd_flush(sc, 0);
+
+ /*
+ * Initalise Pixel Blaster & Jammer.
+ */
+ for (i = 0; i < 32; i++) {
+ if ((i & 0xf) == 0)
+ odyssey_data_wait(sc);
+
+ bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
+ ((0x30000001ULL | ((0x2900 + i) << 14)) << 32) |
+ 0x905215a6);
+ }
+
+ odyssey_data_wait(sc);
+ bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
+ ((0x30000001ULL | (0x2581 << 14)) << 32) | 0x0);
+
+ /* Gamma ramp. */
+ for (i = 0; i < 0x600; i++) {
+ if ((i & 0xf) == 0)
+ odyssey_data_wait(sc);
+
+ if (i < 0x200)
+ val = i >> 2;
+ else if (i < 0x300)
+ val = ((i - 0x200) >> 1) + 0x80;
+ else
+ val = ((i - 0x300) >> 1) + 0x100;
+
+ val = (val << 20) | (val << 10) | val;
+
+ bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
+ ((0x30000001ULL | ((0x1a00 + i) << 14)) << 32) | val);
+ }
+}
+
+void
+odyssey_cmd_wait(struct odyssey_softc *sc)
+{
+ u_int32_t val, timeout = 1000000;
+
+ val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_STATUS);
+ while ((val & ODYSSEY_STATUS_CMD_FIFO_LOW) == 0) {
+ delay(1);
+ if (--timeout == 0) {
+ printf("odyssey: timeout waiting for command fifo!\n");
+ return;
+ }
+ val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_STATUS);
+ }
+}
+
+void
+odyssey_data_wait(struct odyssey_softc *sc)
+{
+ u_int32_t val, timeout = 1000000;
+
+ val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_DBE_STATUS);
+ while ((val & 0x7f) > 0) {
+ delay(1);
+ if (--timeout == 0) {
+ printf("odyssey: timeout waiting for data fifo!\n");
+ return;
+ }
+ val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_DBE_STATUS);
+ }
+}
+
+void
+odyssey_cmd_flush(struct odyssey_softc *sc, int quick)
+{
+
+ odyssey_cmd_wait(sc);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000fa);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+
+ if (quick)
+ return;
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010019);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000096);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000fa);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
+}
+
+/*
+ * Interfaces for wscons.
+ */
+
+int
+odyssey_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct odyssey_screen *screen = (struct odyssey_screen *)v;
+ int rc;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_ODYSSEY;
+ break;
+
+ case WSDISPLAYIO_GINFO:
+ {
+ struct wsdisplay_fbinfo *fb = (struct wsdisplay_fbinfo *)data;
+
+ fb->height = screen->height;
+ fb->width = screen->width;
+ fb->depth = screen->depth;
+ fb->cmsize = screen->depth == 8 ? 256 : 0;
+ }
+ break;
+
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = screen->linebytes;
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ if (screen->depth == 8) {
+ struct wsdisplay_cmap *cm =
+ (struct wsdisplay_cmap *)data;
+
+ rc = odyssey_getcmap(&screen->cmap, cm);
+ if (rc != 0)
+ return (rc);
+ }
+ break;
+
+ case WSDISPLAYIO_PUTCMAP:
+ if (screen->depth == 8) {
+ struct wsdisplay_cmap *cm =
+ (struct wsdisplay_cmap *)data;
+
+ rc = odyssey_putcmap(&screen->cmap, cm);
+ if (rc != 0)
+ return (rc);
+ }
+ break;
+
+ case WSDISPLAYIO_GVIDEO:
+ case WSDISPLAYIO_SVIDEO:
+ /* Handled by the upper layer. */
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+odyssey_getcmap(struct odyssey_cmap *cm, struct wsdisplay_cmap *rcm)
+{
+ u_int index = rcm->index, count = rcm->count;
+ int rc;
+
+ if (index >= 256 || count > 256 - index)
+ return (EINVAL);
+
+ if ((rc = copyout(&cm->cm_red[index], rcm->red, count)) != 0)
+ return (rc);
+ if ((rc = copyout(&cm->cm_green[index], rcm->green, count)) != 0)
+ return (rc);
+ if ((rc = copyout(&cm->cm_blue[index], rcm->blue, count)) != 0)
+ return (rc);
+
+ return (0);
+}
+
+int
+odyssey_putcmap(struct odyssey_cmap *cm, struct wsdisplay_cmap *rcm)
+{
+ u_int index = rcm->index, count = rcm->count;
+ int rc;
+
+ if (index >= 256 || count > 256 - index)
+ return (EINVAL);
+
+ if ((rc = copyin(rcm->red, &cm->cm_red[index], count)) != 0)
+ return (rc);
+ if ((rc = copyin(rcm->green, &cm->cm_green[index], count)) != 0)
+ return (rc);
+ if ((rc = copyin(rcm->blue, &cm->cm_blue[index], count)) != 0)
+ return (rc);
+
+ return (0);
+}
+
+paddr_t
+odyssey_mmap(void *v, off_t offset, int protection)
+{
+ return (-1);
+}
+
+int
+odyssey_alloc_screen(void *v, const struct wsscreen_descr *type,
+ void **cookiep, int *curxp, int *curyp, long *attrp)
+{
+ struct odyssey_screen *screen = (struct odyssey_screen *)v;
+ struct odyssey_softc *sc = (struct odyssey_softc *)screen->sc;
+
+ /* We do not allow multiple consoles at the moment. */
+ if (sc->screens > 0)
+ return (ENOMEM);
+
+ sc->screens++;
+
+ /* Return rasops_info via cookie. */
+ *cookiep = &screen->ri;
+
+ /* Move cursor to top left of screen. */
+ *curxp = 0;
+ *curyp = 0;
+
+ /* Correct screen attributes. */
+ screen->ri.ri_ops.alloc_attr(&screen->ri, 0, 0, 0, attrp);
+ screen->attr = *attrp;
+
+ return (0);
+}
+
+void
+odyssey_free_screen(void *v, void *cookie)
+{
+ /* We do not allow multiple consoles at the moment. */
+}
+
+int
+odyssey_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
+odyssey_burner(void *v, u_int on, u_int flags)
+{
+}
+
+/*
+ * Hardware accelerated functions.
+ */
+
+void
+odyssey_rop(struct odyssey_softc *sc, int x, int y, int w, int h, int op, int c)
+{
+ /* Setup raster operation. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00100000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_LOGIC_OP);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, op);
+ odyssey_cmd_flush(sc, 1);
+
+ odyssey_fillrect(sc, x, y, w, h, c);
+
+ /* Return to copy mode. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00100000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_LOGIC_OP);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ OPENGL_LOGIC_OP_COPY);
+ odyssey_cmd_flush(sc, 1);
+}
+
+void
+odyssey_copyrect(struct odyssey_softc *sc, int sx, int sy, int dx, int dy,
+ int w, int h)
+{
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010658);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00120000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002031);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, sx | (sy << 16));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x80502050);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, w | (h << 16));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x82223042);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, dx | (dy << 16));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3222204b);
+
+ odyssey_cmd_flush(sc, 1);
+}
+
+void
+odyssey_fillrect(struct odyssey_softc *sc, int x, int y, int w, int h, u_int c)
+{
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_BEGIN);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_QUADS);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_COLOR_3UB);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, c & 0xff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, (c >> 8) & 0xff);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, (c >> 16) & 0xff);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x + w);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x + w);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y + h);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y + h);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_END);
+
+ odyssey_cmd_flush(sc, 1);
+}
+
+int
+odyssey_do_cursor(struct rasops_info *ri)
+{
+ struct odyssey_softc *sc = ri->ri_hw;
+ struct odyssey_screen *screen = sc->curscr;
+ int y, x, w, h, fg, bg;
+
+ w = ri->ri_font->fontwidth;
+ h = ri->ri_font->fontheight;
+ x = ri->ri_xorigin + ri->ri_ccol * w;
+ y = ri->ri_yorigin + ri->ri_crow * h;
+
+ ri->ri_ops.unpack_attr(ri, screen->attr, &fg, &bg, NULL);
+
+ odyssey_rop(sc, x, y, w, h, OPENGL_LOGIC_OP_XOR, ri->ri_devcmap[fg]);
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+int
+odyssey_putchar(void *cookie, int row, int col, u_int uc, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct odyssey_softc *sc = ri->ri_hw;
+ struct wsdisplay_font *font = ri->ri_font;
+ int x, y, w, h, bg, fg, ul, i, j, ci, l;
+ u_int8_t *fontbitmap;
+ u_int chunk;
+
+ w = ri->ri_font->fontwidth;
+ h = ri->ri_font->fontheight;
+ x = ri->ri_xorigin + col * w;
+ y = ri->ri_yorigin + row * h;
+
+ fontbitmap = (u_int8_t *)(font->data + (uc - font->firstchar) *
+ ri->ri_fontscale);
+ ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);
+
+ /* Handle spaces with a single fillrect. */
+ if (uc == ' ') {
+ odyssey_fillrect(sc, x, y, w, h, ri->ri_devcmap[bg]);
+ odyssey_cmd_flush(sc, 0);
+ return 0;
+ }
+
+ odyssey_fillrect(sc, x, y, w, h, 0xff0000);
+
+ /* Setup pixel painting. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010405);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002400);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0xc580cc08);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011453);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000002);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ odyssey_cmd_flush(sc, 0);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2900812f);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00014400);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0000000a);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0xcf80a92f);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, ieee754_sp(x));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, ieee754_sp(y));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ ieee754_sp(x + font->fontwidth));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ ieee754_sp(y + font->fontheight));
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x8080c800);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00004570);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0f00104c);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000071);
+
+ for (i = font->fontheight; i != 0; i--) {
+
+ /* Get bitmap for current line. */
+ if (font->fontwidth <= 8)
+ chunk = *fontbitmap;
+ else
+ chunk = *(u_int16_t *)fontbitmap;
+ fontbitmap += font->stride;
+
+ /* Handle underline. */
+ if (ul && i == 1)
+ chunk = 0xffff;
+
+ /* Draw character. */
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ 0x00004570);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ 0x0fd1104c);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
+ 0x00000071);
+
+ w = font->fontwidth;
+ l = 0;
+
+ for (j = 0; j < font->fontwidth; j++) {
+
+ if (l == 0) {
+
+ l = (w > 14 ? 14 : w);
+ w -= 14;
+
+ /* Number of pixels. */
+ bus_space_write_4(sc->iot, sc->ioh,
+ ODYSSEY_CMD_FIFO, (0x00014011 |
+ (l << 10)));
+
+ }
+
+ if (font->fontwidth > 8)
+ ci = (chunk & (1 << (16 - j)) ? fg : bg);
+ else
+ ci = (chunk & (1 << (8 - j)) ? fg : bg);
+
+ bus_space_write_4(sc->iot, sc->ioh,
+ ODYSSEY_CMD_FIFO, ri->ri_devcmap[ci]);
+
+ l--;
+ }
+ }
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00014001);
+ odyssey_cmd_flush(sc, 1);
+
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x290080d6);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011453);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010405);
+ bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+int
+odyssey_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct odyssey_softc *sc = ri->ri_hw;
+ int i;
+
+ if (src < dst) {
+
+ /* We cannot control copy direction, so copy col by col. */
+ for (i = num - 1; i >= 0; i--)
+ odyssey_copyrect(sc,
+ ri->ri_xorigin + (src + i) * ri->ri_font->fontwidth,
+ ri->ri_yorigin + row * ri->ri_font->fontheight,
+ ri->ri_xorigin + (dst + i) * ri->ri_font->fontwidth,
+ ri->ri_yorigin + row * ri->ri_font->fontheight,
+ ri->ri_font->fontwidth, ri->ri_font->fontheight);
+
+ } else {
+
+ odyssey_copyrect(sc,
+ ri->ri_xorigin + src * ri->ri_font->fontwidth,
+ ri->ri_yorigin + row * ri->ri_font->fontheight,
+ ri->ri_xorigin + dst * ri->ri_font->fontwidth,
+ ri->ri_yorigin + row * ri->ri_font->fontheight,
+ num * ri->ri_font->fontwidth, ri->ri_font->fontheight);
+
+ }
+
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+int
+odyssey_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct odyssey_softc *sc = ri->ri_hw;
+ int bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ row *= ri->ri_font->fontheight;
+ col *= ri->ri_font->fontwidth;
+ num *= ri->ri_font->fontwidth;
+
+ odyssey_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+int
+odyssey_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct odyssey_softc *sc = ri->ri_hw;
+ int i;
+
+ if (src < dst) {
+
+ /* We cannot control copy direction, so copy row by row. */
+ for (i = num - 1; i >= 0; i--)
+ odyssey_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin +
+ (src + i) * ri->ri_font->fontheight,
+ ri->ri_xorigin, ri->ri_yorigin +
+ (dst + i) * ri->ri_font->fontheight,
+ ri->ri_emuwidth, ri->ri_font->fontheight);
+
+ } else {
+
+ odyssey_copyrect(sc, ri->ri_xorigin,
+ ri->ri_yorigin + src * ri->ri_font->fontheight,
+ ri->ri_xorigin,
+ ri->ri_yorigin + dst * ri->ri_font->fontheight,
+ ri->ri_emuwidth, num * ri->ri_font->fontheight);
+
+ }
+
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+int
+odyssey_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct odyssey_softc *sc = ri->ri_hw;
+ int x, y, w, bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
+ num = ri->ri_height;
+ x = y = 0;
+ w = ri->ri_width;
+ } else {
+ num *= ri->ri_font->fontheight;
+ x = ri->ri_xorigin;
+ y = ri->ri_yorigin + row * ri->ri_font->fontheight;
+ w = ri->ri_emuwidth;
+ }
+
+ odyssey_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
+ odyssey_cmd_flush(sc, 0);
+
+ return 0;
+}
+
+u_int32_t
+ieee754_sp(int32_t v)
+{
+ u_int8_t exp = 0, sign = 0;
+ int i = 32;
+
+ /*
+ * Convert an integer to IEEE754 single precision floating point:
+ *
+ * Sign - 1 bit
+ * Exponent - 8 bits (with 2^(8-1)-1 = 127 bias)
+ * Fraction - 23 bits
+ */
+
+ if (v < 0) {
+ sign = 1;
+ v = -v;
+ }
+
+ /* Determine shift for fraction. */
+ while (i && (v & (1 << --i)) == 0);
+
+ if (v != 0)
+ exp = 127 + i;
+
+ return (sign << 31) | (exp << 23) | ((v << (23 - i)) & 0x7fffff);
+}
diff --git a/sys/arch/sgi/xbow/odysseyreg.h b/sys/arch/sgi/xbow/odysseyreg.h
new file mode 100644
index 00000000000..5464cb2efaf
--- /dev/null
+++ b/sys/arch/sgi/xbow/odysseyreg.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: odysseyreg.h,v 1.1 2010/03/04 14:50:35 jsing Exp $ */
+/*
+ * Copyright (c) 2009, 2010 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.
+ */
+
+/*
+ * Register details for the SGI VPro (aka Odyssey) Graphics Card.
+ */
+
+#define ODYSSEY_REG_OFFSET 0x00000000
+#define ODYSSEY_REG_SIZE 0x00410000
+
+#define ODYSSEY_STATUS 0x00001064
+#define ODYSSEY_STATUS_CMD_FIFO_HIGH 0x00008000
+#define ODYSSEY_STATUS_CMD_FIFO_LOW 0x00020000
+#define ODYSSEY_DBE_STATUS 0x0000106c
+
+#define ODYSSEY_CMD_FIFO 0x00110000
+#define ODYSSEY_DATA_FIFO 0x00400000
+
+/*
+ * OpenGL Commands.
+ */
+
+#define OPENGL_BEGIN 0x00014400
+#define OPENGL_END 0x00014001
+#define OPENGL_LOGIC_OP 0x00010422
+#define OPENGL_VERTEX_2I 0x8080c800
+#define OPENGL_COLOR_3UB 0xc580cc08
+
+#define OPENGL_QUADS 0x00000007
+
+/* Logic Operations. */
+#define OPENGL_LOGIC_OP_CLEAR 0
+#define OPENGL_LOGIC_OP_AND 1
+#define OPENGL_LOGIC_OP_AND_REVERSE 2
+#define OPENGL_LOGIC_OP_COPY 3
+#define OPENGL_LOGIC_OP_AND_INVERTED 4
+#define OPENGL_LOGIC_OP_NOOP 5
+#define OPENGL_LOGIC_OP_XOR 6
+#define OPENGL_LOGIC_OP_OR 7
+#define OPENGL_LOGIC_OP_NOR 8
+#define OPENGL_LOGIC_OP_EQUIV 9
+#define OPENGL_LOGIC_OP_INVERT 10
+#define OPENGL_LOGIC_OP_OR_REVERSE 11
+#define OPENGL_LOGIC_OP_COPY_INVERTED 12
+#define OPENGL_LOGIC_OP_OR_INVERTED 13
+#define OPENGL_LOGIC_OP_NAND 14
+#define OPENGL_LOGIC_OP_SET 15
+