code:
/*	$OpenBSD: light.c,v 1.7 2014/12/07 17:15:56 miod Exp $	*/
/*	$NetBSD: light.c,v 1.5 2007/03/04 06:00:39 christos Exp $	*/

/*
 * Copyright (c) 2012, 2014 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.
 */
/*
 * Copyright (c) 2006 Stephen M. Rumble
 * Copyright (c) 2003 Ilpo Ruotsalainen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
 */

/*
 * SGI "Light" graphics, a.k.a. "Entry", "Starter", "LG1", and "LG2".
 *
 * 1024x768 8bpp at 60Hz.
 *
 * This driver supports the boards found in Indigo R3k and R4k machines.
 * There is a Crimson variant, but the register offsets differ significantly.
 *
 * Light's REX chip is the precursor of the REX3 found in "newport", hence
 * much similarity exists.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <machine/autoconf.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>

#include <sgi/dev/gl.h>
#include <sgi/gio/giovar.h>
#include <sgi/gio/lightvar.h>
#include <sgi/gio/lightreg.h>

#include <dev/cons.h>

struct light_softc {
	struct device		sc_dev;

	struct light_devconfig *sc_dc;

	int			sc_nscreens;
	struct wsscreen_list	sc_wsl;
	const struct wsscreen_descr *sc_scrlist[1];
};

struct light_devconfig {
	struct rasops_info	dc_ri;
	long			dc_defattr;

	uint32_t		dc_addr;
	bus_space_tag_t		dc_st;
	bus_space_handle_t	dc_sh;

	int			dc_boardrev;

	struct light_softc	*dc_sc;
	struct wsscreen_descr	dc_wsd;

	uint8_t			dc_cmap[256 * 3];
};

/* always 1024x768x8 */
#define LIGHT_XRES	1024
#define LIGHT_YRES	768
#define LIGHT_DEPTH	8

int	light_match(struct device *, void *, void *);
void	light_attach(struct device *, struct device *, void *);

struct cfdriver light_cd = {
	NULL, "light", DV_DULL
};

const struct cfattach light_ca = {
	sizeof(struct light_softc), light_match, light_attach
};

/* wsdisplay_accessops */
int	light_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t	light_mmap(void *, off_t, int);
int	light_alloc_screen(void *, const struct wsscreen_descr *, void **,
	    int *, int *, long *);
void	light_free_screen(void *, void *);
int	light_show_screen(void *, void *, int, void (*)(void *, int, int),
	    void *);
int	light_load_font(void *, void *, struct wsdisplay_font *);
int	light_list_font(void *, struct wsdisplay_font *);
void	light_burner(void *, u_int, u_int);

struct wsdisplay_accessops light_accessops = {
	.ioctl = light_ioctl,
	.mmap = light_mmap,
	.alloc_screen = light_alloc_screen,
	.free_screen = light_free_screen,
	.show_screen = light_show_screen,
	.load_font = light_load_font,
	.list_font = light_list_font,
	.burn_screen = light_burner
};

int	light_do_cursor(struct rasops_info *);
int	light_putchar(void *, int, int, u_int, long);
int	light_copycols(void *, int, int, int, int);
int	light_erasecols(void *, int, int, int, long);
int	light_copyrows(void *, int, int, int);
int	light_eraserows(void *, int, int, long);

static __inline__
uint32_t rex_read(struct light_devconfig *, uint32_t, uint32_t);
static __inline__
void	 rex_write(struct light_devconfig *, uint32_t, uint32_t, uint32_t);
uint8_t	 rex_vc1_sysctl_read(struct light_devconfig *);
void	 rex_vc1_sysctl_write(struct light_devconfig *, uint8_t);
static __inline__
void	 rex_wait(struct light_devconfig *);
static __inline__
int	 rex_revision(struct light_devconfig *);
void	 rex_copy_rect(struct light_devconfig *, int, int, int, int, int, int,
	    int);
void	 rex_fill_rect(struct light_devconfig *, int, int, int, int, int);

int	light_getcmap(struct light_devconfig *, struct wsdisplay_cmap *);
void	light_loadcmap(struct light_devconfig *, int, int);
int	light_putcmap(struct light_devconfig *, struct wsdisplay_cmap *);

void	light_attach_common(struct light_devconfig *, struct gio_attach_args *);
void	light_init_screen(struct light_devconfig *);

static struct light_devconfig light_console_dc;

#define LIGHT_IS_LG1(_rev)		((_rev) < 2)	/* else LG2 */

/*
 * REX routines and helper functions.
 */

static __inline__
uint32_t
rex_read(struct light_devconfig *dc, uint32_t rset, uint32_t r)
{
	return bus_space_read_4(dc->dc_st, dc->dc_sh, rset + r);
}

static __inline__
void
rex_write(struct light_devconfig *dc, uint32_t rset, uint32_t r, uint32_t v)
{
	bus_space_write_4(dc->dc_st, dc->dc_sh, rset + r, v);
}

uint8_t
rex_vc1_sysctl_read(struct light_devconfig *dc)
{
	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL);

	rex_read(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA);
	return rex_read(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA);
}

void
rex_vc1_sysctl_write(struct light_devconfig *dc, uint8_t val)
{
	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL);

	rex_write(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA, val);
	rex_write(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA, val);
}

static __inline__
void
rex_wait(struct light_devconfig *dc)
{
	while (rex_read(dc, REX_PAGE1_SET,REX_P1REG_CFGMODE) & REX_CFGMODE_BUSY)
		continue;
}

static __inline__
int
rex_revision(struct light_devconfig *dc)
{
	rex_write(dc, REX_PAGE1_SET, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_LADDR);
	rex_read(dc, REX_PAGE1_GO, REX_P1REG_WCLOCKREV);
	return rex_read(dc, REX_PAGE1_SET, REX_P1REG_WCLOCKREV) & 0x7;
}

void
rex_copy_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x,
    int to_y, int width, int height, int rop)
{
	int dx, dy, ystarti, yendi;

	dx = from_x - to_x;
	dy = from_y - to_y;

	if (to_y > from_y) {
		ystarti = to_y + height - 1;
		yendi = to_y;
	} else {
		ystarti = to_y;
		yendi = to_y + height - 1;
	}

	rex_wait(dc);

	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, to_x);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, to_x + width - 1);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, ystarti);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, yendi);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
	    REX_OP_FLG_LOGICSRC | REX_OP_FLG_QUADMODE |
	    REX_OP_FLG_BLOCK | REX_OP_FLG_STOPONX | REX_OP_FLG_STOPONY |
	    (rop << REX_LOGICOP_SHIFT));
	rex_write(dc, REX_PAGE0_GO, REX_P0REG_XYMOVE,
	    ((dx << 16) & 0xffff0000) | (dy & 0x0000ffff));
}

void
rex_fill_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x,
    int to_y, int bg)
{
	struct rasops_info *ri = &dc->dc_ri;

	rex_wait(dc);

	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, from_y);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, to_y - 1);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, from_x);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, to_x - 1);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORREDI,
	    ri->ri_devcmap[bg] & 0xff);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
	    REX_OP_FLG_QUADMODE | REX_OP_FLG_BLOCK |
	    REX_OP_FLG_STOPONX | REX_OP_FLG_STOPONY |
	    (OPENGL_LOGIC_OP_COPY << REX_LOGICOP_SHIFT));
	rex_read(dc, REX_PAGE0_GO, REX_P0REG_COMMAND);
}

/*
 * Colormap routines
 */

int
light_getcmap(struct light_devconfig *dc, struct wsdisplay_cmap *cm)
{
	u_int index = cm->index, count = cm->count, i;
	u_int colcount = 1 << dc->dc_ri.ri_depth;
	int rc;
	u_int8_t color[256], *c, *r;

	if (index >= colcount || count > colcount - index)
		return EINVAL;

	c = dc->dc_cmap + 0 + index * 3;
	for (i = count, r = color; i != 0; i--) {
		*r++ = *c;
		c += 3;
	}
	if ((rc = copyout(color, cm->red, count)) != 0)
		return rc;

	c = dc->dc_cmap + 1 + index * 3;
	for (i = count, r = color; i != 0; i--) {
		*r++ = *c;
		c += 3;
	}
	if ((rc = copyout(color, cm->green, count)) != 0)
		return rc;

	c = dc->dc_cmap + 2 + index * 3;
	for (i = count, r = color; i != 0; i--) {
		*r++ = *c;
		c += 3;
	}
	if ((rc = copyout(color, cm->blue, count)) != 0)
		return rc;

	return 0;
}

int
light_putcmap(struct light_devconfig *dc, struct wsdisplay_cmap *cm)
{
	u_int index = cm->index, count = cm->count;
	u_int colcount = 1 << dc->dc_ri.ri_depth;
	int i, rc;
	u_int8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;

	if (index >= colcount || count > colcount - index)
		return EINVAL;

	if ((rc = copyin(cm->red, r, count)) != 0)
		return rc;
	if ((rc = copyin(cm->green, g, count)) != 0)
		return rc;
	if ((rc = copyin(cm->blue, b, count)) != 0)
		return rc;

	nr = r, ng = g, nb = b;
	c = dc->dc_cmap + index * 3;
	for (i = count; i != 0; i--) {
		*c++ = *nr++;
		*c++ = *ng++;
		*c++ = *nb++;
	}

	return 0;
}

void
light_loadcmap(struct light_devconfig *dc, int from, int count)
{
	u_int8_t *cmap = dc->dc_cmap;

	/* XXX should wait for retrace first */

	cmap += 3 * from;
	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_DAC_WADDR);
	rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, from);
	rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, from);

	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_DAC_CMAP);
	while (count-- > 0) {
		rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap);
		rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++);
		rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap);
		rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++);
		rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap);
		rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++);
	}
}

/*
 * Autoconf and console glue
 */

int
light_match(struct device *parent, void *vcf, void *aux)
{
	struct gio_attach_args *ga = aux;

	if (ga->ga_product != GIO_PRODUCT_FAKEID_LIGHT)
		return 0;

	return 1;
}

void
light_attach(struct device *parent, struct device *self, void *aux)
{
	struct light_softc *sc = (struct light_softc *)self;
	struct gio_attach_args *ga = aux;
	struct light_devconfig *dc;
	struct wsemuldisplaydev_attach_args waa;
	extern struct consdev wsdisplay_cons;

	if (cn_tab == &wsdisplay_cons &&
	    ga->ga_addr == light_console_dc.dc_addr) {
		waa.console = 1;
		dc = &light_console_dc;
		sc->sc_nscreens = 1;
	} else {
		waa.console = 0;
		dc = malloc(sizeof(struct light_devconfig), M_DEVBUF,
		    M_WAITOK | M_ZERO);
		light_attach_common(dc, ga);
		light_init_screen(dc);
	}
	sc->sc_dc = dc;
	dc->dc_sc = sc;

	if (ga->ga_descr != NULL && *ga->ga_descr != '\0')
		printf(": %s", ga->ga_descr);
	else
		printf(": LG%dMC\n",
		    LIGHT_IS_LG1(sc->sc_dc->dc_boardrev) ? 1 : 2);
	printf(", revision %d\n", dc->dc_boardrev);
	printf("%s: %dx%d %d-bit frame buffer\n", self->dv_xname,
	    dc->dc_ri.ri_width, dc->dc_ri.ri_height, dc->dc_ri.ri_depth);

	sc->sc_scrlist[0] = &dc->dc_wsd;
	sc->sc_wsl.nscreens = 1;
	sc->sc_wsl.screens = sc->sc_scrlist;

	waa.scrdata = &sc->sc_wsl;
	waa.accessops = &light_accessops;
	waa.accesscookie = dc;
	waa.defaultscreens = 0;

	config_found(self, &waa, wsemuldisplaydevprint);
}

int
light_cnprobe(struct gio_attach_args *ga)
{
	return light_match(NULL, NULL, ga);
}

int
light_cnattach(struct gio_attach_args *ga)
{
	struct rasops_info *ri = &light_console_dc.dc_ri;
	long defattr;

	light_attach_common(&light_console_dc, ga);
	light_init_screen(&light_console_dc);

	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
	wsdisplay_cnattach(&light_console_dc.dc_wsd, ri, 0, 0, defattr);

	return 0;
}

void
light_attach_common(struct light_devconfig *dc, struct gio_attach_args *ga)
{
	dc->dc_addr = ga->ga_addr;
	dc->dc_st = ga->ga_iot;
	dc->dc_sh = ga->ga_ioh;

	dc->dc_boardrev = rex_revision(dc);

	rex_vc1_sysctl_write(dc, rex_vc1_sysctl_read(dc) &
	    ~(VC1_SYSCTL_CURSOR | VC1_SYSCTL_CURSOR_ON));
}

void
light_init_screen(struct light_devconfig *dc)
{
	struct rasops_info *ri = &dc->dc_ri;

	memset(ri, 0, sizeof(struct rasops_info));
	ri->ri_hw = dc;
	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
	/* for the proper operation of rasops computations, pretend 8bpp */
	ri->ri_depth = 8;
	ri->ri_stride = LIGHT_XRES;
	ri->ri_width = LIGHT_XRES;
	ri->ri_height = LIGHT_YRES;

	rasops_init(ri, 160, 160);

	ri->ri_do_cursor = light_do_cursor;
	ri->ri_ops.copyrows = light_copyrows;
	ri->ri_ops.eraserows = light_eraserows;
	ri->ri_ops.copycols = light_copycols;
	ri->ri_ops.erasecols = light_erasecols;
	ri->ri_ops.putchar = light_putchar;

	strlcpy(dc->dc_wsd.name, "std", sizeof(dc->dc_wsd.name));
	dc->dc_wsd.ncols = ri->ri_cols;
	dc->dc_wsd.nrows = ri->ri_rows;
	dc->dc_wsd.textops = &ri->ri_ops;
	dc->dc_wsd.fontwidth = ri->ri_font->fontwidth;
	dc->dc_wsd.fontheight = ri->ri_font->fontheight;
	dc->dc_wsd.capabilities = ri->ri_caps;

	memcpy(dc->dc_cmap, rasops_cmap, sizeof(dc->dc_cmap));
	light_loadcmap(dc, 0, 1 << ri->ri_depth);

	rex_fill_rect(dc, 0, 0, ri->ri_width, ri->ri_height, WSCOL_BLACK);
}

/*
 * wsdisplay_emulops
 */

int
light_do_cursor(struct rasops_info *ri)
{
	struct light_devconfig *dc = ri->ri_hw;
	int x, y, w, h;

	w = ri->ri_font->fontwidth;
	h = ri->ri_font->fontheight;
	x = ri->ri_ccol * w + ri->ri_xorigin;
	y = ri->ri_crow * h + ri->ri_yorigin;

	rex_copy_rect(dc, x, y, x, y, w, h, OPENGL_LOGIC_OP_COPY_INVERTED);

	return 0;
}

int
light_putchar(void *c, int row, int col, u_int ch, long attr)
{
	struct rasops_info *ri = c;
	struct light_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	uint8_t *bitmap;
	uint32_t pattern;
	int x = col * font->fontwidth + ri->ri_xorigin;
	int y = row * font->fontheight + ri->ri_yorigin;
	int i;
	int bg, fg, ul;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);

	if ((ch == ' ' || ch == 0) && ul == 0) {
		rex_fill_rect(dc, x, y, x + font->fontwidth,
		    y + font->fontheight, bg);
		return 0;
	}

	rex_wait(dc);

	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, y);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, y + font->fontheight - 1);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, x);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, x + font->fontwidth - 1);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORREDI,
	    ri->ri_devcmap[fg] & 0xff);
	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORBACK,
	    ri->ri_devcmap[bg] & 0xff);
	rex_write(dc, REX_PAGE0_GO, REX_P0REG_COMMAND, REX_OP_NOP);

	rex_wait(dc);

	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
	    REX_OP_FLG_ENZPATTERN | REX_OP_FLG_QUADMODE |
	    REX_OP_FLG_XYCONTINUE | REX_OP_FLG_STOPONX | REX_OP_FLG_BLOCK |
	    REX_OP_FLG_LENGTH32 | REX_OP_FLG_ZOPAQUE |
	    (OPENGL_LOGIC_OP_COPY << REX_LOGICOP_SHIFT));

	bitmap = (uint8_t *)font->data +
	    (ch - font->firstchar) * ri->ri_fontscale;
	if (font->fontwidth <= 8) {
		for (i = font->fontheight; i != 0; i--) {
			if (ul && i == 1)
				pattern = 0xff;
			else
				pattern = *bitmap;
			rex_write(dc, REX_PAGE0_GO, REX_P0REG_ZPATTERN,
			    pattern << 24);
			bitmap += font->stride;
		}
	} else {
		for (i = font->fontheight; i != 0; i--) {
			if (ul && i == 1)
				pattern = 0xffff;
			else
				pattern = *(uint16_t *)bitmap;
			rex_write(dc, REX_PAGE0_GO, REX_P0REG_ZPATTERN,
			    pattern << 16);
			bitmap += font->stride;
		}
	}

	return 0;
}

/* copy set of columns within the same line */
int
light_copycols(void *c, int row, int srccol, int dstcol, int ncols)
{
	struct rasops_info *ri = c;
	struct light_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int from_x, to_x, y, width, height;

	from_x = ri->ri_xorigin + srccol * font->fontwidth;
	to_x = ri->ri_xorigin + dstcol * font->fontwidth;
	y = ri->ri_yorigin + row * font->fontheight;
	width = ncols * font->fontwidth;
	height = font->fontheight;

	rex_copy_rect(dc, from_x, y, to_x, y, width, height,
	    OPENGL_LOGIC_OP_COPY);

	return 0;
}

/* erase a set of columns in the same line */
int
light_erasecols(void *c, int row, int startcol, int ncols, long attr)
{
	struct rasops_info *ri = c;
	struct light_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int from_x, from_y, to_x, to_y;
	int bg, fg;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL);

	from_x = ri->ri_xorigin + startcol * font->fontwidth;
	from_y = ri->ri_yorigin + row * font->fontheight;
	to_x = from_x + ncols * font->fontwidth;
	to_y = from_y + font->fontheight;

	rex_fill_rect(dc, from_x, from_y, to_x, to_y, bg);

	return 0;
}

/* copy a set of complete rows */
int
light_copyrows(void *c, int srcrow, int dstrow, int nrows)
{
	struct rasops_info *ri = c;
	struct light_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int x, from_y, to_y, width, height;

	x = ri->ri_xorigin;
	from_y = ri->ri_yorigin + srcrow * font->fontheight;
	to_y = ri->ri_yorigin + dstrow * font->fontheight;
	width = ri->ri_emuwidth;
	height = nrows * font->fontheight;

	rex_copy_rect(dc, x, from_y, x, to_y, width, height,
	    OPENGL_LOGIC_OP_COPY);

	return 0;
}

/* erase a set of complete rows */
int
light_eraserows(void *c, int row, int nrows, long attr)
{
	struct rasops_info *ri = c;
	struct light_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int bg, fg;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL);

	if (nrows == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) {
		rex_fill_rect(dc, 0, 0, ri->ri_width, ri->ri_height, bg);
		return 0;
	}

	rex_fill_rect(dc, ri->ri_xorigin,
	    ri->ri_yorigin + row * font->fontheight,
	    ri->ri_xorigin + ri->ri_emuwidth,
	    ri->ri_yorigin + (row + nrows) * font->fontheight, bg);

	return 0;
}

/*
 * wsdisplay_accessops
 */

int
light_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct light_devconfig *dc = v;
	struct wsdisplay_fbinfo *fb;
	struct wsdisplay_cmap *cm;
	int rc;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_LIGHT;
		break;
	case WSDISPLAYIO_GINFO:
		fb = (struct wsdisplay_fbinfo *)data;
		fb->width = dc->dc_ri.ri_width;
		fb->height = dc->dc_ri.ri_height;
		fb->depth = dc->dc_ri.ri_depth;
		fb->cmsize = 1 << fb->depth;
		break;
	case WSDISPLAYIO_GETCMAP:
		cm = (struct wsdisplay_cmap *)data;
		rc = light_getcmap(dc, cm);
		if (rc != 0)
			return rc;
		break;
	case WSDISPLAYIO_PUTCMAP:
		cm = (struct wsdisplay_cmap *)data;
		rc = light_putcmap(dc, cm);
		if (rc != 0)
			return rc;
		light_loadcmap(dc, cm->index, cm->count);
		break;
	default:
		return -1;
	}

	return 0;
}

paddr_t
light_mmap(void *v, off_t off, int prot)
{
	return -1;
}

int
light_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    int *curxp, int *curyp, long *attrp)
{
	struct light_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;
	struct light_softc *sc = dc->dc_sc;

	if (sc->sc_nscreens > 0)
		return ENOMEM;

	sc->sc_nscreens++;

	*cookiep = ri;
	*curxp = *curyp = 0;
	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &dc->dc_defattr);
	*attrp = dc->dc_defattr;

	return 0;
}

void
light_free_screen(void *v, void *cookie)
{
}

int
light_show_screen(void *v, void *cookie, int waitok,
    void (*cb)(void *, int, int), void *cbarg)
{
	return 0;
}

int
light_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
	struct light_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;

	return rasops_load_font(ri, emulcookie, font);
}

int
light_list_font(void *v, struct wsdisplay_font *font)
{
	struct light_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;

	return rasops_list_font(ri, font);
}

void
light_burner(void *v, u_int on, u_int flags)
{
	struct light_devconfig *dc = v;

	if (on)
		rex_vc1_sysctl_write(dc, rex_vc1_sysctl_read(dc) |
		    VC1_SYSCTL_VIDEO_ON);
	else
		rex_vc1_sysctl_write(dc, rex_vc1_sysctl_read(dc) &
		    ~VC1_SYSCTL_VIDEO_ON);
}


code:
/*	$OpenBSD: lightreg.h,v 1.2 2014/03/18 23:23:09 miod Exp $	*/
/*	$NetBSD: lightreg.h,v 1.3 2006/12/29 00:31:48 rumble Exp $	*/

/*
 * Copyright (c) 2006 Stephen M. Rumble
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define LIGHT_ADDR_0		0x1f3f0000
#define LIGHT_ADDR_1		0x1f3f8000	/* dual head */
#define	LIGHT_SIZE		0x00008000

#define REX_PAGE0_SET		0x00000000	/* REX registers */
#define REX_PAGE0_GO		0x00000800
#define REX_PAGE1_SET		0x00004790	/* configuration registers */
#define REX_PAGE1_GO		0x00004F90

/* REX register offsets (from REX_PAGE0_{SET,GO}) */
#define REX_P0REG_COMMAND	0x00000000
#define REX_P0REG_XSTARTI	0x0000000C
#define REX_P0REG_YSTARTI	0x0000001C
#define REX_P0REG_XYMOVE	0x00000034
#define REX_P0REG_COLORREDI	0x00000038
#define REX_P0REG_COLORGREENI	0x00000040
#define REX_P0REG_COLORBLUEI	0x00000048
#define REX_P0REG_COLORBACK	0x0000005C
#define REX_P0REG_ZPATTERN	0x00000060
#define REX_P0REG_XENDI		0x00000084
#define REX_P0REG_YENDI		0x00000088

/* configuration register offsets (from REX_PAGE1_{SET,GO}) */
#define REX_P1REG_WCLOCKREV	0x00000054	/* nsclock / revision */
#define REX_P1REG_DAC_ADDRDATA	0x00000058	/* DAC r/w addr and data 8bit */
#define REX_P1REG_CFGSEL	0x0000005c	/* function selector */
#define REX_P1REG_VC1_ADDRDATA	0x00000060	/* vc1 r/w addr and data 8bit */
#define REX_P1REG_CFGMODE	0x00000068	/* REX system config */
#define REX_P1REG_XYOFFSET	0x0000006c	/* x, y start of screen */

/* REX opcodes */
#define REX_OP_NOP		0x00000000
#define REX_OP_DRAW		0x00000001

/* REX command flags */
#define REX_OP_FLG_BLOCK	0x00000008
#define REX_OP_FLG_LENGTH32	0x00000010
#define REX_OP_FLG_QUADMODE	0x00000020
#define REX_OP_FLG_XYCONTINUE	0x00000080
#define REX_OP_FLG_STOPONX	0x00000100
#define REX_OP_FLG_STOPONY	0x00000200
#define REX_OP_FLG_ENZPATTERN	0x00000400
#define REX_OP_FLG_LOGICSRC	0x00080000
#define REX_OP_FLG_ZOPAQUE	0x00800000
#define REX_OP_FLG_ZCONTINUE	0x01000000

/* REX logicops */
#define REX_LOGICOP_SHIFT	28

/* configmode bits */
#define REX_CFGMODE_BUSY	0x00000001

/* configsel bits */
#define REX_CFGSEL_VC1_LADDR	0x00000004	/* low address bits */
#define REX_CFGSEL_VC1_HADDR	0x00000005	/* high address bits */
#define REX_CFGSEL_VC1_SYSCTL	0x00000006
#define REX_CFGSEL_DAC_WADDR	0x00000000	/* write address */
#define REX_CFGSEL_DAC_CMAP	0x00000001	/* colormap data */
#define REX_CFGSEL_DAC_PMASK	0x00000002	/* pixel read mask */
#define REX_CFGSEL_DAC_RADDR	0x00000003	/* read address */
#define REX_CFGSEL_DAC_OVWADDR	0x00000004	/* overlay write address */
#define REX_CFGSEL_DAC_OV	0x00000005	/* overlay registers */
#define REX_CFGSEL_DAC_CTL	0x00000006	/* control registers */
#define REX_CFGSEL_DAC_OVRADDR	0x00000007	/* overlay read address */

/* vc1 sysctl bits (byte) */
#define VC1_SYSCTL_VIDEO_ON	0x04
#define VC1_SYSCTL_CURSOR	0x10
#define VC1_SYSCTL_CURSOR_ON	0x20

license: unknown


code:
/*	$OpenBSD: lightvar.h,v 1.1 2012/04/17 15:36:55 miod Exp $	*/
/*	$NetBSD: lightvar.h,v 1.2 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2006 Stephen M. Rumble
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

int light_cnattach(struct gio_attach_args *);
int light_cnprobe(struct gio_attach_args *);


code:
/*	$OpenBSD: newport.c,v 1.9 2014/07/12 18:44:42 tedu Exp $	*/
/*	$NetBSD: newport.c,v 1.15 2009/05/12 23:51:25 macallan Exp $	*/

/*
 * Copyright (c) 2012 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.
 */
/*
 * Copyright (c) 2003 Ilpo Ruotsalainen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>

#include <machine/autoconf.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>

#include <sgi/dev/gl.h>
#include <sgi/gio/gioreg.h>
#include <sgi/gio/giovar.h>
#include <sgi/gio/newportreg.h>
#include <sgi/gio/newportvar.h>

#include <dev/cons.h>

struct newport_softc {
	struct device		sc_dev;

	struct newport_devconfig *sc_dc;

	int			sc_nscreens;
	struct wsscreen_list	sc_wsl;
	const struct wsscreen_descr *sc_scrlist[1];
};

struct newport_devconfig {
	struct rasops_info	dc_ri;
	long			dc_defattr;

	uint32_t		dc_addr;
	bus_space_tag_t		dc_st;
	bus_space_handle_t	dc_sh;

	int			dc_xres;
	int			dc_yres;
	int			dc_depth;

#ifdef notyet
	int			dc_mode;
#endif

	int			dc_boardrev;
	int			dc_vc2rev;
	int			dc_xmaprev;

	struct newport_softc	*dc_sc;
	struct wsscreen_descr	dc_wsd;
};

int	newport_match(struct device *, void *, void *);
void	newport_attach(struct device *, struct device *, void *);

struct cfdriver newport_cd = {
	NULL, "newport", DV_DULL
};

const struct cfattach newport_ca = {
	sizeof(struct newport_softc), newport_match, newport_attach
};

/* accessops */
int	newport_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t	newport_mmap(void *, off_t, int);
int	newport_alloc_screen(void *, const struct wsscreen_descr *, void **,
	    int *, int *, long *);
void	newport_free_screen(void *, void *);
int	newport_show_screen(void *, void *, int, void (*)(void *, int, int),
	    void *);
int	newport_load_font(void *, void *, struct wsdisplay_font *);
int	newport_list_font(void *, struct wsdisplay_font *);

struct wsdisplay_accessops newport_accessops = {
	.ioctl = newport_ioctl,
	.mmap = newport_mmap,
	.alloc_screen = newport_alloc_screen,
	.free_screen = newport_free_screen,
	.show_screen = newport_show_screen,
	.load_font = newport_load_font,
	.list_font = newport_list_font
};

int	newport_do_cursor(struct rasops_info *);
int	newport_putchar(void *, int, int, u_int, long);
int	newport_copycols(void *, int, int, int, int);
int	newport_erasecols(void *, int, int, int, long);
int	newport_copyrows(void *, int, int, int);
int	newport_eraserows(void *, int, int, long);

static __inline__
void	 rex3_write(struct newport_devconfig *, bus_size_t, uint32_t);
static __inline__
void	 rex3_write_go(struct newport_devconfig *, bus_size_t, uint32_t);
static __inline__
uint32_t rex3_read(struct newport_devconfig *, bus_size_t);
int	 rex3_wait_gfifo(struct newport_devconfig *, const char *);

void	 vc2_write_ireg(struct newport_devconfig *, uint8_t, uint16_t);
uint16_t vc2_read_ireg(struct newport_devconfig *, uint8_t);
uint16_t vc2_read_ram(struct newport_devconfig *, uint16_t);
void	 vc2_write_ram(struct newport_devconfig *, uint16_t, uint16_t);
uint32_t xmap9_read(struct newport_devconfig *, int);
void	 xmap9_write(struct newport_devconfig *, int, uint8_t);
void	 xmap9_write_mode(struct newport_devconfig *, uint8_t, uint32_t);

void	newport_attach_common(struct newport_devconfig *,
	    struct gio_attach_args *);
int	newport_bitblt(struct newport_devconfig *, int, int, int, int, int, int,
	    int);
void	newport_cmap_setrgb(struct newport_devconfig *, int, uint8_t, uint8_t,
	    uint8_t);
int	newport_fill_rectangle(struct newport_devconfig *, int, int, int, int,
	    int);
void	newport_get_resolution(struct newport_devconfig *);
int	newport_init_screen(struct newport_devconfig *);
void	newport_setup_hw(struct newport_devconfig *);

static struct newport_devconfig newport_console_dc;

/**** Low-level hardware register groveling functions ****/
static __inline__ void
rex3_write(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
{
	bus_space_write_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET + rexreg,
	    val);
}

static __inline__ void
rex3_write_go(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
{
	rex3_write(dc, rexreg + REX3_REG_GO, val);
}

static __inline__ uint32_t
rex3_read(struct newport_devconfig *dc, bus_size_t rexreg)
{
	return bus_space_read_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET +
	    rexreg);
}

int
rex3_wait_gfifo(struct newport_devconfig *dc, const char *from)
{
	unsigned int iter;
	uint32_t rxstatus;

	for (iter = 100000; iter != 0; iter--) {
		rxstatus = rex3_read(dc, REX3_REG_STATUS);
		if ((rxstatus &
		    (REX3_STATUS_GFXBUSY | REX3_STATUS_FIFOLEVEL_MASK)) == 0)
			return 0;
	}

#ifdef DEBUG
	printf("%s: failed to idle, %05x\n", from, rxstatus);
#endif
	return EAGAIN;
}

void
vc2_write_ireg(struct newport_devconfig *dc, uint8_t ireg, uint16_t val)
{
	rex3_write(dc, REX3_REG_DCBMODE,
	    REX3_DCBMODE_DW_3 | REX3_DCBMODE_ENCRSINC |
	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
	    REX3_DCBMODE_ENASYNCACK | (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, (ireg << 24) | (val << 8));
}

uint16_t
vc2_read_ireg(struct newport_devconfig *dc, uint8_t ireg)
{
	rex3_write(dc, REX3_REG_DCBMODE,
	    REX3_DCBMODE_DW_1 | REX3_DCBMODE_ENCRSINC |
	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
	    REX3_DCBMODE_ENASYNCACK | (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, ireg << 24);

	rex3_write(dc, REX3_REG_DCBMODE,
	    REX3_DCBMODE_DW_2 | REX3_DCBMODE_ENCRSINC |
	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (VC2_DCBCRS_IREG << REX3_DCBMODE_DCBCRS_SHIFT) |
	    REX3_DCBMODE_ENASYNCACK | (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
}

uint16_t
vc2_read_ram(struct newport_devconfig *dc, uint16_t addr)
{
	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);

	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_2 |
	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
	    REX3_DCBMODE_ENASYNCACK | (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
}

#if 0
void
vc2_write_ram(struct newport_devconfig *dc, uint16_t addr, uint16_t val)
{
	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);

	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_2 |
	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
	    REX3_DCBMODE_ENASYNCACK | (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, val << 16);
}
#endif

uint32_t
xmap9_read(struct newport_devconfig *dc, int crs)
{
	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_1 |
		(NEWPORT_DCBADDR_XMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
		(crs << REX3_DCBMODE_DCBCRS_SHIFT) |
		(3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
		(2 << REX3_DCBMODE_CSHOLD_SHIFT) |
		(1 << REX3_DCBMODE_CSSETUP_SHIFT));
	return rex3_read(dc, REX3_REG_DCBDATA0);
}

void
xmap9_write(struct newport_devconfig *dc, int crs, uint8_t val)
{
	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_1 |
	    (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (crs << REX3_DCBMODE_DCBCRS_SHIFT) |
	    (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
	    (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, val << 24);
}

void
xmap9_write_mode(struct newport_devconfig *dc, uint8_t index, uint32_t mode)
{
	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_4 |
	    (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (XMAP9_DCBCRS_MODE_SETUP << REX3_DCBMODE_DCBCRS_SHIFT) |
	    (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
	    (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, (index << 24) | mode);
}

/**** Helper functions ****/
int
newport_fill_rectangle(struct newport_devconfig *dc, int x1, int y1, int x2,
    int y2, int bg)
{
	struct rasops_info *ri = &dc->dc_ri;

	if (rex3_wait_gfifo(dc, __func__) != 0)
		return EAGAIN;

	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
	rex3_write(dc, REX3_REG_DRAWMODE1, REX3_DRAWMODE1_PLANES_CI |
	    REX3_DRAWMODE1_DD_DD8 | REX3_DRAWMODE1_RWPACKED |
	    REX3_DRAWMODE1_HD_HD8 | REX3_DRAWMODE1_COMPARE_LT |
	    REX3_DRAWMODE1_COMPARE_EQ | REX3_DRAWMODE1_COMPARE_GT |
	    (OPENGL_LOGIC_OP_COPY << REX3_DRAWMODE1_LOGICOP_SHIFT));
	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
	rex3_write(dc, REX3_REG_COLORI, ri->ri_devcmap[bg] & 0xff);
	rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);

	rex3_write_go(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);

	return 0;
}

int
newport_bitblt(struct newport_devconfig *dc, int xs, int ys, int xd,
    int yd, int wi, int he, int rop)
{
	int xe, ye;
	uint32_t tmp;

	if (rex3_wait_gfifo(dc, __func__) != 0)
		return EAGAIN;

	if (yd > ys) {
		/* need to copy bottom up */
		ye = ys;
		yd += he - 1;
		ys += he - 1;
	} else
		ye = ys + he - 1;

	if (xd > xs) {
		/* need to copy right to left */
		xe = xs;
		xd += wi - 1;
		xs += wi - 1;
	} else
		xe = xs + wi - 1;

	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_SCR2SCR |
	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
	rex3_write(dc, REX3_REG_DRAWMODE1, REX3_DRAWMODE1_PLANES_CI |
	    REX3_DRAWMODE1_DD_DD8 | REX3_DRAWMODE1_RWPACKED |
	    REX3_DRAWMODE1_HD_HD8 | REX3_DRAWMODE1_COMPARE_LT |
	    REX3_DRAWMODE1_COMPARE_EQ | REX3_DRAWMODE1_COMPARE_GT |
	    (rop << REX3_DRAWMODE1_LOGICOP_SHIFT));
	rex3_write(dc, REX3_REG_XYSTARTI, (xs << REX3_XYSTARTI_XSHIFT) | ys);
	rex3_write(dc, REX3_REG_XYENDI, (xe << REX3_XYENDI_XSHIFT) | ye);

	tmp = (yd - ys) & 0xffff;
	tmp |= (xd - xs) << REX3_XYMOVE_XSHIFT;

	rex3_write_go(dc, REX3_REG_XYMOVE, tmp);

	return 0;
}

void
newport_cmap_setrgb(struct newport_devconfig *dc, int index, uint8_t r,
    uint8_t g, uint8_t b)
{
	rex3_write(dc, REX3_REG_DCBMODE,
	    REX3_DCBMODE_DW_2 | REX3_DCBMODE_ENCRSINC |
	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (CMAP_DCBCRS_ADDRESS_LOW << REX3_DCBMODE_DCBCRS_SHIFT) |
	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
	    (1 << REX3_DCBMODE_CSSETUP_SHIFT) | REX3_DCBMODE_SWAPENDIAN);

	rex3_write(dc, REX3_REG_DCBDATA0, index << 16);

	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_3 |
	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (CMAP_DCBCRS_PALETTE << REX3_DCBMODE_DCBCRS_SHIFT) |
	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));

	rex3_write(dc, REX3_REG_DCBDATA0, (r << 24) | (g << 16) | (b << 8));
}

void
newport_get_resolution(struct newport_devconfig *dc)
{
	uint16_t vep, lines;
	uint16_t linep, cols;
	uint16_t data;

	vep = vc2_read_ireg(dc, VC2_IREG_VIDEO_ENTRY);

	dc->dc_xres = 0;
	dc->dc_yres = 0;

	for (;;) {
		/* Iterate over runs in video timing table */

		cols = 0;

		linep = vc2_read_ram(dc, vep++);
		lines = vc2_read_ram(dc, vep++);

		if (lines == 0)
			break;

#define	VC2_SRUN_EOL	0x8000	/* end of line */
#define	VC2_SRUN_SBSC	0x0080	/* zero if SB/SC follows */
#define	VC2_SRUN_MASK	0x7f00
#define	VC2_SRUN_SHIFT	8
#define	VC2_SA_MASK	0x007f
#define	VC2_SA_SHIFT	0
#define	VC2_SA_VISIBLE	(1 << (14 % 7))
		do {
			/* Iterate over state runs in line sequence table */
			data = vc2_read_ram(dc, linep++);

			if ((((data & VC2_SA_MASK) >> VC2_SA_SHIFT) &
			    VC2_SA_VISIBLE) == 0)
				cols += (data & VC2_SRUN_MASK) >> VC2_SRUN_SHIFT;
			if ((data & VC2_SRUN_SBSC) == 0)
				data = vc2_read_ram(dc, linep++);
		} while ((data & VC2_SRUN_EOL) == 0);

		if (cols != 0) {
			cols <<= 1;	/* was in 2 pixels unit */
			if (cols > dc->dc_xres)
				dc->dc_xres = cols;
			dc->dc_yres += lines;
		}
	}
}

void
newport_setup_hw(struct newport_devconfig *dc)
{
	uint16_t tmp;
	int i;
	uint32_t scratch;

	/* Get various revisions */
	rex3_write(dc, REX3_REG_DCBMODE, REX3_DCBMODE_DW_1 |
	    (NEWPORT_DCBADDR_CMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
	    (CMAP_DCBCRS_REVISION << REX3_DCBMODE_DCBCRS_SHIFT) |
	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
	scratch = rex3_read(dc, REX3_REG_DCBDATA0) >> 24;

	dc->dc_boardrev = (scratch >> 4) & 0x07;
	/* cmaprev = scratch & 0x07; */
	dc->dc_xmaprev = xmap9_read(dc, XMAP9_DCBCRS_REVISION) & 0x07;
	dc->dc_depth = ((dc->dc_boardrev > 1) && (scratch & 0x80)) ? 8 : 24;

	scratch = vc2_read_ireg(dc, VC2_IREG_CONFIG);
	dc->dc_vc2rev = (scratch & VC2_IREG_CONFIG_REVISION) >> 5;

	/* Setup VC2 to a known state */
	tmp = vc2_read_ireg(dc, VC2_IREG_CONTROL) & VC2_CONTROL_INTERLACE;
	vc2_write_ireg(dc, VC2_IREG_CONTROL, tmp |
	    VC2_CONTROL_DISPLAY_ENABLE | VC2_CONTROL_VTIMING_ENABLE |
	    VC2_CONTROL_DID_ENABLE | VC2_CONTROL_CURSORFUNC_ENABLE);

	/* Setup XMAP9s */
	xmap9_write(dc, XMAP9_DCBCRS_CONFIG,
	    XMAP9_CONFIG_8BIT_SYSTEM | XMAP9_CONFIG_RGBMAP_CI);

	xmap9_write(dc, XMAP9_DCBCRS_CURSOR_CMAP, 0);

	xmap9_write_mode(dc, 0,
	    XMAP9_MODE_GAMMA_BYPASS | XMAP9_MODE_PIXSIZE_8BPP);
	xmap9_write(dc, XMAP9_DCBCRS_MODE_SELECT, 0);

	/* Setup REX3 */
	rex3_write(dc, REX3_REG_XYWIN, (4096 << 16) | 4096);
	rex3_write(dc, REX3_REG_TOPSCAN, 0x3ff); /* XXX Why? XXX */

	/* Setup CMAP */
	for (i = 0; i < 256; i++)
		newport_cmap_setrgb(dc, i, rasops_cmap[i * 3],
		    rasops_cmap[i * 3 + 1], rasops_cmap[i * 3 + 2]);
}

/**** Attach routines ****/
int
newport_match(struct device *parent, void *vcf, void *aux)
{
	struct gio_attach_args *ga = aux;

	if (ga->ga_product != GIO_PRODUCT_FAKEID_NEWPORT)
		return 0;

	return 1;
}

void
newport_attach(struct device *parent, struct device *self, void *aux)
{
	struct newport_softc *sc = (struct newport_softc *)self;
	struct gio_attach_args *ga = aux;
	struct newport_devconfig *dc;
	struct wsemuldisplaydev_attach_args waa;
	const char *descr;
	extern struct consdev wsdisplay_cons;
	int fail = 0;

	if (cn_tab == &wsdisplay_cons &&
	    ga->ga_addr == newport_console_dc.dc_addr) {
		waa.console = 1;
		dc = &newport_console_dc;
		sc->sc_nscreens = 1;
	} else {
		waa.console = 0;
		dc = malloc(sizeof(struct newport_devconfig),
		    M_DEVBUF, M_WAITOK | M_ZERO);
		newport_attach_common(dc, ga);
		if (newport_init_screen(dc) != 0)
			fail = 1;
	}
	sc->sc_dc = dc;
	dc->dc_sc = sc;

	descr = ga->ga_descr;
	if (descr == NULL || *descr == '\0')
		descr = "NG1";
	printf(": %s (board rev %d, xmap rev %d, vc2 rev %d)\n",
	    descr, dc->dc_boardrev, dc->dc_xmaprev, dc->dc_vc2rev);
	printf("%s: %dx%d %d-bit frame buffer\n",
	    self->dv_xname, dc->dc_xres, dc->dc_yres, dc->dc_depth);
#ifdef DEBUG
	printf("%s: REX3 config = %06x\n",
	    self->dv_xname, rex3_read(dc, REX3_REG_CONFIG));
#endif

	if (fail) {
		printf("%s: failed to initialize screen\n", self->dv_xname);
		free(dc, M_DEVBUF, 0);
		return;
	}

	sc->sc_scrlist[0] = &dc->dc_wsd;
	sc->sc_wsl.nscreens = 1;
	sc->sc_wsl.screens = sc->sc_scrlist;

	waa.scrdata = &sc->sc_wsl;
	waa.accessops = &newport_accessops;
	waa.accesscookie = dc;
	waa.defaultscreens = 0;

	config_found(self, &waa, wsemuldisplaydevprint);
}

int
newport_cnprobe(struct gio_attach_args *ga)
{
	return newport_match(NULL, NULL, ga);
}

int
newport_cnattach(struct gio_attach_args *ga)
{
	struct rasops_info *ri = &newport_console_dc.dc_ri;
	long defattr;
	int rc;

	newport_attach_common(&newport_console_dc, ga);
	rc = newport_init_screen(&newport_console_dc);
	if (rc != 0)
		return rc;

	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
	wsdisplay_cnattach(&newport_console_dc.dc_wsd, ri, 0, 0, defattr);

	return 0;
}

void
newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
{
	dc->dc_addr = ga->ga_addr;
	dc->dc_st = ga->ga_iot;
	dc->dc_sh = ga->ga_ioh;

	newport_setup_hw(dc);
	newport_get_resolution(dc);
}

int
newport_init_screen(struct newport_devconfig *dc)
{
	struct rasops_info *ri = &dc->dc_ri;
	int rc;

	memset(ri, 0, sizeof(struct rasops_info));
	ri->ri_hw = dc;
	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
	/* for the proper operation of rasops computations, pretend 8bpp */
	ri->ri_depth = 8;
	ri->ri_stride = dc->dc_xres;
	ri->ri_width = dc->dc_xres;
	ri->ri_height = dc->dc_yres;

	rasops_init(ri, 160, 160);

	ri->ri_do_cursor = newport_do_cursor;
	ri->ri_ops.copyrows = newport_copyrows;
	ri->ri_ops.eraserows = newport_eraserows;
	ri->ri_ops.copycols = newport_copycols;
	ri->ri_ops.erasecols = newport_erasecols;
	ri->ri_ops.putchar = newport_putchar;

	strlcpy(dc->dc_wsd.name, "std", sizeof(dc->dc_wsd.name));
	dc->dc_wsd.ncols = ri->ri_cols;
	dc->dc_wsd.nrows = ri->ri_rows;
	dc->dc_wsd.textops = &ri->ri_ops;
	dc->dc_wsd.fontwidth = ri->ri_font->fontwidth;
	dc->dc_wsd.fontheight = ri->ri_font->fontheight;
	dc->dc_wsd.capabilities = ri->ri_caps;

	rc = newport_fill_rectangle(dc, 0, 0, ri->ri_width - 1,
	    ri->ri_height - 1, WSCOL_BLACK);

#ifdef notyet
	dc->dc_mode = WSDISPLAYIO_MODE_EMUL;
#endif

	return rc;
}

/**** wsdisplay textops ****/

int
newport_do_cursor(struct rasops_info *ri)
{
	struct newport_devconfig *dc = ri->ri_hw;
	int x, y, w, h;

	w = ri->ri_font->fontwidth;
	h = ri->ri_font->fontheight;
	x = ri->ri_ccol * w + ri->ri_xorigin;
	y = ri->ri_crow * h + ri->ri_yorigin;

	return newport_bitblt(dc, x, y, x, y, w, h,
	    OPENGL_LOGIC_OP_COPY_INVERTED);
}

int
newport_putchar(void *c, int row, int col, u_int ch, long attr)
{
	struct rasops_info *ri = c;
	struct newport_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	uint8_t *bitmap;
	uint32_t pattern;
	int x = col * font->fontwidth + ri->ri_xorigin;
	int y = row * font->fontheight + ri->ri_yorigin;
	int i;
	int bg, fg, ul;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);

	if ((ch == ' ' || ch == 0) && ul == 0) {
		return newport_fill_rectangle(dc, x, y, x + font->fontwidth - 1,
		    y + font->fontheight - 1, bg);
	}

	if (rex3_wait_gfifo(dc, __func__) != 0)
		return EAGAIN;

	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
	    REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);

	rex3_write(dc, REX3_REG_DRAWMODE1, REX3_DRAWMODE1_PLANES_CI |
	    REX3_DRAWMODE1_DD_DD8 | REX3_DRAWMODE1_RWPACKED |
	    REX3_DRAWMODE1_HD_HD8 | REX3_DRAWMODE1_COMPARE_LT |
	    REX3_DRAWMODE1_COMPARE_EQ | REX3_DRAWMODE1_COMPARE_GT |
	    (OPENGL_LOGIC_OP_COPY << REX3_DRAWMODE1_LOGICOP_SHIFT));

	rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
	rex3_write(dc, REX3_REG_XYENDI,
	    (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);

	rex3_write(dc, REX3_REG_COLORI, ri->ri_devcmap[fg] & 0xff);
	rex3_write(dc, REX3_REG_COLORBACK, ri->ri_devcmap[bg] & 0xff);

	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);

	bitmap = (uint8_t *)font->data +
	    (ch - font->firstchar) * ri->ri_fontscale;
	if (font->fontwidth <= 8) {
		for (i = font->fontheight; i != 0; i--) {
			if (ul && i == 1)
				pattern = 0xff000000;
			else
				pattern = *bitmap << 24;
			rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
			bitmap += font->stride;
		}
	} else {
		for (i = font->fontheight; i != 0; i--) {
			if (ul && i == 1)
				pattern = 0xffff0000;
			else
				pattern = *(uint16_t *)bitmap << 16;
			rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
			bitmap += font->stride;
		}
	}

	return 0;
}

int
newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
{
	struct rasops_info *ri = c;
	struct newport_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int32_t xs, xd, y, width, height;

	xs = ri->ri_xorigin + font->fontwidth * srccol;
	xd = ri->ri_xorigin + font->fontwidth * dstcol;
	y = ri->ri_yorigin + font->fontheight * row;
	width = font->fontwidth * ncols;
	height = font->fontheight;
	return newport_bitblt(dc, xs, y, xd, y, width, height,
	    OPENGL_LOGIC_OP_COPY);
}

int
newport_erasecols(void *c, int row, int startcol, int ncols, long attr)
{
	struct rasops_info *ri = c;
	struct newport_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int sx, sy, dx, dy;
	int bg, fg;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL);

	sx = ri->ri_xorigin + startcol * font->fontwidth;
	sy = ri->ri_yorigin + row * font->fontheight;
	dx = sx + ncols * font->fontwidth - 1;
	dy = sy + font->fontheight - 1;

	return newport_fill_rectangle(dc, sx, sy, dx, dy, bg);
}

int
newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
{
	struct rasops_info *ri = c;
	struct newport_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int32_t x, ys, yd, width, height;

	x = ri->ri_xorigin;
	ys = ri->ri_yorigin + font->fontheight * srcrow;
	yd = ri->ri_yorigin + font->fontheight * dstrow;
	width = ri->ri_emuwidth;
	height = font->fontheight * nrows;

	return newport_bitblt(dc, x, ys, x, yd, width, height,
	    OPENGL_LOGIC_OP_COPY);
}

int
newport_eraserows(void *c, int startrow, int nrows, long attr)
{
	struct rasops_info *ri = c;
	struct newport_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int bg, fg;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL);

	if (nrows == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) {
		return newport_fill_rectangle(dc, 0, 0, ri->ri_width - 1,
		    ri->ri_height - 1, bg);
	}

	return newport_fill_rectangle(dc, ri->ri_xorigin,
	    ri->ri_yorigin + startrow * font->fontheight,
	    ri->ri_xorigin + ri->ri_emuwidth - 1,
	    ri->ri_yorigin + (startrow + nrows) * font->fontheight - 1, bg);
}

/**** wsdisplay accessops ****/

int
newport_alloc_screen(void *v, const struct wsscreen_descr *type,
    void **cookiep, int *curxp, int *curyp, long *attrp)
{
	struct newport_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;
	struct newport_softc *sc = dc->dc_sc;

	if (sc->sc_nscreens > 0)
		return ENOMEM;

	sc->sc_nscreens++;

	*cookiep = ri;
	*curxp = *curyp = 0;
	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &dc->dc_defattr);
	*attrp = dc->dc_defattr;

	return 0;
}

void
newport_free_screen(void *v, void *cookie)
{
}

int
newport_show_screen(void *v, void *cookie, int waitok,
    void (*cb)(void *, int, int), void *cbarg)
{
	return 0;
}

int
newport_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct newport_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;
	struct wsdisplay_fbinfo *fb;
#ifdef notyet
	int nmode;
#endif

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
		break;
	case WSDISPLAYIO_GINFO:
		fb = (struct wsdisplay_fbinfo *)data;
		fb->width = ri->ri_width;
		fb->height = ri->ri_height;
		fb->depth = dc->dc_depth;	/* real depth */
		if (dc->dc_depth > 8)
			fb->cmsize = 0;
		else
			fb->cmsize = 1 << ri->ri_depth;
		break;
#ifdef notyet
	case WSDISPLAYIO_SMODE:
		nmode = *(int *)data;
		if (nmode != dc->dc_mode) {
			if (nmode == WSDISPLAYIO_MODE_EMUL) {
				if (rex3_wait_gfifo(dc, __func__) != 0)
					return EAGAIN;
				dc->dc_mode = nmode;
				newport_setup_hw(dc);
			} else
				dc->dc_mode = nmode;
		}
		break;
#endif
	default:
		return -1;
	}

	return 0;
}

paddr_t
newport_mmap(void *v, off_t offset, int prot)
{
	return -1;
}

int
newport_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
	struct newport_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;

	return rasops_load_font(ri, emulcookie, font);
}

int
newport_list_font(void *v, struct wsdisplay_font *font)
{
	struct newport_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;

	return rasops_list_font(ri, font);
}


code:
/*	$OpenBSD: newportreg.h,v 1.2 2013/04/20 20:26:26 miod Exp $	*/
/*	$NetBSD: newportreg.h,v 1.5 2011/02/20 07:59:50 matt Exp $	*/

/*
 * Copyright (c) 2003 Ilpo Ruotsalainen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
 */

/* REX3 */

#define NEWPORT_REX3_OFFSET		0xf0000

#define REX3_REG_DRAWMODE1		0x0000
#define  REX3_DRAWMODE1_PLANES_MASK	0x00000007
#define   REX3_DRAWMODE1_PLANES_NONE	0x00000000
#define   REX3_DRAWMODE1_PLANES_RGB	0x00000001
#define   REX3_DRAWMODE1_PLANES_CI	0x00000001
#define   REX3_DRAWMODE1_PLANES_RGBA	0x00000002
#define   REX3_DRAWMODE1_PLANES_OLAY	0x00000004
#define   REX3_DRAWMODE1_PLANES_PUP	0x00000005
#define   REX3_DRAWMODE1_PLANES_CID	0x00000006
#define  REX3_DRAWMODE1_DD_MASK		0x00000018
#define   REX3_DRAWMODE1_DD_DD4		0x00000000
#define   REX3_DRAWMODE1_DD_DD8		0x00000008
#define   REX3_DRAWMODE1_DD_DD12	0x00000010
#define   REX3_DRAWMODE1_DD_DD24	0x00000018
#define  REX3_DRAWMODE1_DBLSRC		0x00000020
#define  REX3_DRAWMODE1_YFLIP		0x00000040
#define  REX3_DRAWMODE1_RWPACKED	0x00000080
#define  REX3_DRAWMODE1_HD_MASK		0x00000300
#define   REX3_DRAWMODE1_HD_HD4		0x00000000
#define   REX3_DRAWMODE1_HD_HD8		0x00000100
#define   REX3_DRAWMODE1_HD_HD12	0x00000200
#define   REX3_DRAWMODE1_HD_HD24	0x00000300
#define  REX3_DRAWMODE1_RWDOUBLE	0x00000400
#define  REX3_DRAWMODE1_SWAPENDIAN	0x00000800
#define  REX3_DRAWMODE1_COMPARE_MASK	0x00007000
#define   REX3_DRAWMODE1_COMPARE_LT	0x00001000
#define   REX3_DRAWMODE1_COMPARE_EQ	0x00002000
#define   REX3_DRAWMODE1_COMPARE_GT	0x00004000
#define  REX3_DRAWMODE1_RGBMODE		0x00008000
#define  REX3_DRAWMODE1_DITHER		0x00010000
#define  REX3_DRAWMODE1_FASTCLEAR	0x00020000
#define  REX3_DRAWMODE1_BLEND		0x00040000
#define  REX3_DRAWMODE1_SFACTOR_MASK	0x00380000
#define   REX3_DRAWMODE1_SFACTOR_ZERO	0x00000000
#define   REX3_DRAWMODE1_SFACTOR_ONE	0x00080000
#define   REX3_DRAWMODE1_SFACTOR_DC	0x00100000
#define   REX3_DRAWMODE1_SFACTOR_MDC	0x00180000
#define   REX3_DRAWMODE1_SFACTOR_SA	0x00200000
#define   REX3_DRAWMODE1_SFACTOR_MSA	0x00280000
#define  REX3_DRAWMODE1_DFACTOR_MASK	0x01c00000
#define   REX3_DRAWMODE1_DFACTOR_ZERO	0x00000000
#define   REX3_DRAWMODE1_DFACTOR_ONE	0x00400000
#define   REX3_DRAWMODE1_DFACTOR_SC	0x00800000
#define   REX3_DRAWMODE1_DFACTOR_MSC	0x00c00000
#define   REX3_DRAWMODE1_DFACTOR_SA	0x01000000
#define   REX3_DRAWMODE1_DFACTOR_MSA	0x01400000
#define  REX3_DRAWMODE1_BACKBLEND	0x02000000
#define  REX3_DRAWMODE1_PREFETCH	0x04000000
#define  REX3_DRAWMODE1_BLENDALPHA	0x08000000
#define  REX3_DRAWMODE1_LOGICOP_SHIFT	28

#define REX3_REG_DRAWMODE0		0x0004
#define  REX3_DRAWMODE0_OPCODE_MASK	0x00000003
#define   REX3_DRAWMODE0_OPCODE_NOOP	0x00000000
#define   REX3_DRAWMODE0_OPCODE_READ	0x00000001
#define   REX3_DRAWMODE0_OPCODE_DRAW	0x00000002
#define   REX3_DRAWMODE0_OPCODE_SCR2SCR	0x00000003
#define  REX3_DRAWMODE0_ADRMODE_MASK	0x0000001c
#define   REX3_DRAWMODE0_ADRMODE_SPAN	0x00000000
#define   REX3_DRAWMODE0_ADRMODE_BLOCK	0x00000004
#define   REX3_DRAWMODE0_ADRMODE_I_LINE	0x00000008
#define   REX3_DRAWMODE0_ADRMODE_F_LINE	0x0000000c
#define   REX3_DRAWMODE0_ADRMODE_A_LINE	0x00000010
#define  REX3_DRAWMODE0_DOSETUP		0x00000020
#define  REX3_DRAWMODE0_COLORHOST	0x00000040
#define  REX3_DRAWMODE0_ALPHAHOST	0x00000080
#define  REX3_DRAWMODE0_STOPONX		0x00000100
#define  REX3_DRAWMODE0_STOPONY		0x00000200
#define  REX3_DRAWMODE0_SKIPFIRST	0x00000400
#define  REX3_DRAWMODE0_SKIPLAST	0x00000800
#define  REX3_DRAWMODE0_ENZPATTERN	0x00001000
#define  REX3_DRAWMODE0_ENLSPATTERN	0x00002000
#define  REX3_DRAWMODE0_LSADVLAST	0x00004000
#define  REX3_DRAWMODE0_LENGTH32	0x00008000
#define  REX3_DRAWMODE0_ZPOPAQUE	0x00010000
#define  REX3_DRAWMODE0_LSOPAQUE	0x00020000
#define  REX3_DRAWMODE0_SHADE		0x00040000
#define  REX3_DRAWMODE0_LRONLY		0x00080000
#define  REX3_DRAWMODE0_XYOFFSET	0x00100000
#define  REX3_DRAWMODE0_CICLAMP		0x00200000
#define  REX3_DRAWMODE0_ENDPTFILTER	0x00400000
#define  REX3_DRAWMODE0_YSTRIDE		0x00800000
#define REX3_REG_LSMODE			0x0008

#define REX3_REG_LSPATTERN		0x000c

#define REX3_REG_LSPATSAVE		0x0010

#define REX3_REG_ZPATTERN		0x0014

#define REX3_REG_COLORBACK		0x0018

#define REX3_REG_XSTART			0x0100

#define REX3_REG_XYMOVE			0x0114
#define  REX3_XYMOVE_XSHIFT		16

#define REX3_REG_XSTARTI		0x0148

#define REX3_REG_XYSTARTI		0x0150
#define  REX3_XYSTARTI_XSHIFT		16

#define REX3_REG_XYENDI			0x0154
#define  REX3_XYENDI_XSHIFT		16

#define REX3_REG_WRMASK			0x0220

#define REX3_REG_COLORI			0x0224

#define REX3_REG_DCBMODE		0x0238
#define  REX3_DCBMODE_DW_MASK		0x00000003
#define   REX3_DCBMODE_DW_4		0x00000000
#define   REX3_DCBMODE_DW_1		0x00000001
#define   REX3_DCBMODE_DW_2		0x00000002
#define   REX3_DCBMODE_DW_3		0x00000003
#define  REX3_DCBMODE_ENDATAPACK	0x00000004
#define  REX3_DCBMODE_ENCRSINC		0x00000008
#define  REX3_DCBMODE_DCBCRS_MASK	0x00000070
#define   REX3_DCBMODE_DCBCRS_SHIFT	4
#define  REX3_DCBMODE_DCBADDR_MASK	0x00000780
#define   REX3_DCBMODE_DCBADDR_SHIFT	7
#define  REX3_DCBMODE_ENSYNCACK		0x00000800
#define  REX3_DCBMODE_ENASYNCACK	0x00001000
#define  REX3_DCBMODE_CSWIDTH_MASK	0x0003e000
#define  REX3_DCBMODE_CSWIDTH_SHIFT	13
#define  REX3_DCBMODE_CSHOLD_MASK	0x007c0000
#define  REX3_DCBMODE_CSHOLD_SHIFT	18
#define  REX3_DCBMODE_CSSETUP_MASK	0x0f800000
#define  REX3_DCBMODE_CSSETUP_SHIFT	23
#define  REX3_DCBMODE_SWAPENDIAN	0x10000000

#define REX3_REG_DCBDATA0		0x0240
#define REX3_REG_DCBDATA1		0x0244

/* Not really a register, but in the same space */
#define REX3_REG_GO			0x0800

#define REX3_REG_TOPSCAN		0x1320
#define REX3_REG_XYWIN			0x1324

#define REX3_REG_CONFIG			0x1330

#define REX3_REG_STATUS			0x1338
#define  REX3_STATUS_GFXBUSY		0x00000008
#define  REX3_STATUS_FIFOLEVEL_MASK	0x00001F80
#define  REX3_STATUS_FIFOLEVEL_SHIFT	7

/* VC2 */

#define VC2_DCBCRS_INDEX		0
#define VC2_DCBCRS_IREG			1
#define VC2_DCBCRS_RAM			3

#define VC2_IREG_VIDEO_ENTRY		0x00

#define VC2_IREG_CURSOR_ENTRY		0x01

#define VC2_IREG_CURSOR_X		0x02

#define VC2_IREG_CURSOR_Y		0x03

#define VC2_IREG_SCANLINE_LENGTH	0x06

#define VC2_IREG_RAM_ADDRESS		0x07

#define VC2_IREG_CONTROL		0x10
#define  VC2_CONTROL_VINTR_ENABLE	0x0001
#define  VC2_CONTROL_DISPLAY_ENABLE	0x0002
#define  VC2_CONTROL_VTIMING_ENABLE	0x0004
#define  VC2_CONTROL_DID_ENABLE		0x0008
#define  VC2_CONTROL_CURSORFUNC_ENABLE	0x0010
#define  VC2_CONTROL_GENSYNC_ENABLE	0x0020
#define  VC2_CONTROL_INTERLACE		0x0040
#define  VC2_CONTROL_CURSOR_ENABLE	0x0080
#define  VC2_CONTROL_CROSSHAIR_CURSOR	0x0100
#define  VC2_CONTROL_LARGE_CURSOR	0x0200
#define  VC2_CONTROL_GENLOCK_1		0x0400

#define VC2_IREG_CONFIG			0x1f
#define VC2_IREG_CONFIG_SOFTRESET	0x01	/* active low */
#define VC2_IREG_CONFIG_SLOWCLOCK	0x02
#define VC2_IREG_CONFIG_CURSORERROR	0x04
#define VC2_IREG_CONFIG_DIDERROR	0x08
#define VC2_IREG_CONFIG_VTGERROR	0x10
#define VC2_IREG_CONFIG_REVISION	0x70

/* CMAP */

#define CMAP_DCBCRS_ADDRESS_LOW		0
#define CMAP_DCBCRS_ADDRESS_HIGH	1
#define CMAP_DCBCRS_PALETTE		2
#define CMAP_DCBCRS_REVISION		6

/* XMAP9 */

#define XMAP9_DCBCRS_CONFIG		0
#define  XMAP9_CONFIG_PUP_ENABLE	0x01
#define  XMAP9_CONFIG_ODD_PIXEL		0x02
#define  XMAP9_CONFIG_8BIT_SYSTEM	0x04
#define  XMAP9_CONFIG_SLOW_PCLK		0x08
#define  XMAP9_CONFIG_RGBMAP_CI		0x00
#define  XMAP9_CONFIG_RGBMAP_0		0x10
#define  XMAP9_CONFIG_RGBMAP_1		0x20
#define  XMAP9_CONFIG_RGBMAP_2		0x30
#define  XMAP9_CONFIG_EXPRESS_MODE	0x40
#define  XMAP9_CONFIG_VIDEO_ENABLE	0x80
#define XMAP9_DCBCRS_REVISION		1
#define XMAP9_DCBCRS_FIFOAVAIL		2
#define XMAP9_DCBCRS_CURSOR_CMAP	3
#define XMAP9_DCBCRS_PUP_CMAP		4
#define XMAP9_DCBCRS_MODE_SETUP		5
#define  XMAP9_MODE_GAMMA_BYPASS	0x000004
#define  XMAP9_MODE_PIXSIZE_8BPP	0x000400
#define XMAP9_DCBCRS_MODE_SELECT	7

/* DCB addresses */

#define NEWPORT_DCBADDR_VC2		0
#define NEWPORT_DCBADDR_CMAP_BOTH	1
#define NEWPORT_DCBADDR_CMAP_0		2
#define NEWPORT_DCBADDR_CMAP_1		3
#define NEWPORT_DCBADDR_XMAP_BOTH	4
#define NEWPORT_DCBADDR_XMAP_0		5
#define NEWPORT_DCBADDR_XMAP_1		6
#define NEWPORT_DCBADDR_RAMDAC		7
#define NEWPORT_DCBADDR_VIDEO_CC1	8
#define NEWPORT_DCBADDR_VIDEO_AB1	9


code:
/*	$OpenBSD: newportvar.h,v 1.1 2012/04/16 22:31:36 miod Exp $	*/
/*	$NetBSD: newportvar.h,v 1.3 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2003 Ilpo Ruotsalainen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
 */

int newport_cnattach(struct gio_attach_args *);
int newport_cnprobe(struct gio_attach_args *);


code:
/*	$OpenBSD: pci_gio.c,v 1.3 2014/10/02 18:55:49 miod Exp $	*/
/*	$NetBSD: pci_gio.c,v 1.9 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2006 Stephen M. Rumble
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Glue for PCI devices that are connected to the GIO bus by various little
 * GIO<->PCI ASICs.
 *
 * We presently recognize the following boards:
 *	o Phobos G100/G130/G160	(dc, lxtphy)
 *	o Set Engineering GFE	(tl, nsphy)
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/extent.h>

#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/cpu.h>

#include <mips64/archtype.h>
#include <sgi/sgi/ip22.h>

#include <sgi/gio/giovar.h>
#include <sgi/gio/gioreg.h>
#include <sgi/gio/giodevs.h>

#include <sgi/localbus/imcvar.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>

#include "cardbus.h"

#if NCARDBUS > 0
#include <dev/cardbus/rbus.h>
#endif

int giopci_debug = 0;
#define DPRINTF(_x)	if (giopci_debug) printf _x

struct giopci_softc {
	struct device			sc_dev;
	int				sc_slot;

	bus_space_tag_t			sc_cfgt;
	bus_space_handle_t		sc_cfgh;
	uint32_t			sc_cfg_len;

	struct mips_pci_chipset		sc_pc;

	bus_dma_tag_t			sc_dmat;
	bus_size_t			sc_dma_boundary;
	struct machine_bus_dma_tag	sc_dmat_store;
};

int	 giopci_match(struct device *, void *, void *);
void	 giopci_attach(struct device *, struct device *, void *);

const struct cfattach giopci_ca = {
	sizeof(struct giopci_softc), giopci_match, giopci_attach
};

struct cfdriver giopci_cd = {
	NULL, "giopci", DV_DULL
};

void	 giopci_attach_hook(struct device *, struct device *,
	    struct pcibus_attach_args *);
int	 giopci_bus_maxdevs(void *, int);
pcitag_t giopci_make_tag(void *, int, int, int);
void	 giopci_decompose_tag(void *, pcitag_t, int *, int *, int *);
int	 giopci_conf_size(void *, pcitag_t);
pcireg_t giopci_conf_read(void *, pcitag_t, int);
void	 giopci_conf_write(void *, pcitag_t, int, pcireg_t);
int	 giopci_probe_device_hook(void *, struct pci_attach_args *);
int	 giopci_get_widget(void *);
int	 giopci_get_dl(void *, pcitag_t, struct sgi_device_location *);
int	 giopci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
const char *giopci_intr_string(void *, pci_intr_handle_t);
void	*giopci_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *),
	    void *, const char *);
void	 giopci_intr_disestablish(void *, void *);
int	 giopci_intr_line(void *, pci_intr_handle_t);
int	 giopci_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *,
	    bus_addr_t *, bus_addr_t *);
void	*giopci_rbus_parent_io(struct pci_attach_args *);
void	*giopci_rbus_parent_mem(struct pci_attach_args *);

static const struct mips_pci_chipset giopci_pci_chipset = {
	.pc_attach_hook = giopci_attach_hook,
	.pc_bus_maxdevs = giopci_bus_maxdevs,
	.pc_make_tag = giopci_make_tag,
	.pc_decompose_tag = giopci_decompose_tag,
	.pc_conf_size = giopci_conf_size,
	.pc_conf_read = giopci_conf_read,
	.pc_conf_write = giopci_conf_write,
	.pc_probe_device_hook = giopci_probe_device_hook,
	.pc_get_widget = giopci_get_widget,
	.pc_get_dl = giopci_get_dl,
	.pc_intr_map = giopci_intr_map,
	.pc_intr_string = giopci_intr_string,
	.pc_intr_establish = giopci_intr_establish,
	.pc_intr_disestablish = giopci_intr_disestablish,
	.pc_intr_line = giopci_intr_line,
	.pc_ppb_setup = giopci_ppb_setup,
#if NCARDBUS > 0
	.pc_rbus_parent_io = giopci_rbus_parent_io,
	.pc_rbus_parent_mem = giopci_rbus_parent_mem
#endif
};

int	 giopci_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
	    bus_size_t, int, bus_dmamap_t *);
int      giopci_print(void *, const char *);

#define PHOBOS_PCI_OFFSET	0x00100000
#define PHOBOS_PCI_LENGTH	0x00000080	/* verified on G130 */
#define PHOBOS_TULIP_START	0x00101000
#define PHOBOS_TULIP_END	0x001fffff

#define SETENG_MAGIC_OFFSET	0x00020000
#define SETENG_MAGIC_VALUE	0x00001000
#define SETENG_PCI_OFFSET	0x00080000
#define SETENG_PCI_LENGTH	0x00000080	/* ~arbitrary */
#define SETENG_TLAN_START	0x00100000
#define SETENG_TLAN_END		0x001fffff

int
giopci_match(struct device *parent, void *vcf, void *aux)
{
	struct gio_attach_args *ga = aux;

	switch (GIO_PRODUCT_PRODUCTID(ga->ga_product)) {
	case GIO_PRODUCT_PHOBOS_G160:
	case GIO_PRODUCT_PHOBOS_G130:
	case GIO_PRODUCT_PHOBOS_G100:
	case GIO_PRODUCT_SETENG_GFE:
		return 1;
	}

	return 0;
}

void
giopci_attach(struct device *parent, struct device *self, void *aux)
{
	struct giopci_softc *sc = (struct giopci_softc *)self;
	pci_chipset_tag_t pc = &sc->sc_pc;
	struct gio_attach_args *ga = aux;
	uint32_t cfg_off, cfg_len, arb, reg;
	struct pcibus_attach_args pba;
	uint32_t m_start, m_end;
	struct extent *ex;
	pcireg_t csr;

	printf(": %s\n",
	    gio_product_string(GIO_PRODUCT_PRODUCTID(ga->ga_product)));

	sc->sc_cfgt = ga->ga_iot;
	sc->sc_dmat = ga->ga_dmat;
	sc->sc_slot = ga->ga_slot;

	if (sys_config.system_type != SGI_IP20 &&
	    sys_config.system_subtype == IP22_INDIGO2)
		arb = GIO_ARB_RT | GIO_ARB_MST | GIO_ARB_PIPE;
	else
		arb = GIO_ARB_RT | GIO_ARB_MST;

	if (gio_arb_config(ga->ga_slot, arb)) {
		printf("%s: failed to configure GIO bus arbiter\n",
		    self->dv_xname);
		return;
	}

	imc_disable_sysad_parity();

	switch (GIO_PRODUCT_PRODUCTID(ga->ga_product)) {
	case GIO_PRODUCT_PHOBOS_G160:
	case GIO_PRODUCT_PHOBOS_G130:
	case GIO_PRODUCT_PHOBOS_G100:
		cfg_off = PHOBOS_PCI_OFFSET;
		cfg_len = PHOBOS_PCI_LENGTH;
		m_start = PHOBOS_TULIP_START;
		m_end = PHOBOS_TULIP_END;
		sc->sc_dma_boundary = 0;
		break;

	case GIO_PRODUCT_SETENG_GFE:
		cfg_off = SETENG_PCI_OFFSET;
		cfg_len = SETENG_PCI_LENGTH;
		m_start = SETENG_TLAN_START;
		m_end = SETENG_TLAN_END;
		sc->sc_dma_boundary = 0x1000;

		bus_space_write_4(ga->ga_iot, ga->ga_ioh,
		    SETENG_MAGIC_OFFSET, SETENG_MAGIC_VALUE);

		break;
	}

	if (bus_space_subregion(ga->ga_iot, ga->ga_ioh, cfg_off, cfg_len,
	    &sc->sc_cfgh)) {
		printf("%s: unable to map PCI configuration space\n",
		    self->dv_xname);
		return;
	}

	sc->sc_cfg_len = cfg_len;

	bcopy(&giopci_pci_chipset, pc, sizeof(giopci_pci_chipset));
	pc->pc_conf_v = pc->pc_intr_v = sc;

	/*
	 * Setup a bus_dma tag if necessary.
	 */

	if (sc->sc_dma_boundary != 0) {
		bcopy(ga->ga_dmat, &sc->sc_dmat_store,
		    sizeof(struct machine_bus_dma_tag));
		sc->sc_dmat_store._dmamap_create = giopci_dmamap_create;
		sc->sc_dmat_store._cookie = sc;
	}

	/*
	 * Setup resource extent for memory BARs.
	 */

	ex = extent_create(self->dv_xname, 0, (u_long)-1L, M_DEVBUF,
	    NULL, 0, EX_NOWAIT | EX_FILLED);
	if (ex == NULL || extent_free(ex, ga->ga_addr + m_start,
	    m_end + 1 - m_start, EX_NOWAIT) != 0) {
		printf("%s: unable to setup PCI resource management\n",
		    self->dv_xname);
		return;
	}

	/*
	 * Reset all BARs. Note that we are assuming there is only
	 * one device, which is neither a bridge nor a multifunction
	 * device.
	 * This is necessary because they contain garbage upon poweron,
	 * and although the bridge chip does not support I/O mappings,
	 * the chips behind it (at least on Phobos boards) have I/O BARs.
	 */

	for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4)
		bus_space_write_4(sc->sc_cfgt, sc->sc_cfgh, reg, 0);

	csr =
	    bus_space_read_4(sc->sc_cfgt, sc->sc_cfgh, PCI_COMMAND_STATUS_REG);
	bus_space_write_4(sc->sc_cfgt, sc->sc_cfgh, PCI_COMMAND_STATUS_REG,
	    (csr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)) |
	    PCI_COMMAND_MASTER_ENABLE);

	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = pba.pba_memt = ga->ga_iot;
	if (sc->sc_dma_boundary == 0)
		pba.pba_dmat = ga->ga_dmat;
	else
		pba.pba_dmat = &sc->sc_dmat_store;
	pba.pba_pc = pc;
	pba.pba_ioex = NULL;
	pba.pba_memex = ex;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0;

	config_found(self, &pba, giopci_print);
}

int
giopci_print(void *aux, const char *pnp)
{
	struct pcibus_attach_args *pba = aux;

	if (pnp != NULL)
		printf("%s at %s", pba->pba_busname, pnp);
	printf(" bus %d", pba->pba_bus);

	return UNCONF;
}

/*
 * pci_chipset_t routines
 */

void
giopci_attach_hook(struct device *parent, struct device *self,
    struct pcibus_attach_args *pba)
{
}

pcitag_t
giopci_make_tag(void *v, int bus, int dev, int fnc)
{
	return (bus << 16) | (dev << 11) | (fnc << 8);
}

void
giopci_decompose_tag(void *v, pcitag_t tag, int *busp, int *devp, int *fncp)
{
	if (busp != NULL)
		*busp = (tag >> 16) & 0xff;
	if (devp != NULL)
		*devp = (tag >> 11) & 0x1f;
	if (fncp != NULL)
		*fncp = (tag >> 8) & 0x7;
}

int
giopci_bus_maxdevs(void *v, int busno)
{
	return busno == 0 ? 1 : 0;
}

int
giopci_conf_size(void *v, pcitag_t tag)
{
	struct giopci_softc *sc = (struct giopci_softc *)v;

	return sc->sc_cfg_len;
}

pcireg_t
giopci_conf_read(void *v, pcitag_t tag, int reg)
{
	struct giopci_softc *sc = v;
	int bus, dev, func;
	pcireg_t data;

	giopci_decompose_tag(v, tag, &bus, &dev, &func);
	if (bus != 0 || dev != 0 || func != 0)
		return reg == PCI_ID_REG ? 0xffffffff : 0;

	if (reg >= sc->sc_cfg_len)
		return 0;

	DPRINTF(("giopci_conf_read: reg 0x%x = 0x", reg));
	data = bus_space_read_4(sc->sc_cfgt, sc->sc_cfgh, reg);
	DPRINTF(("%08x\n", data));

	return data;
}

void
giopci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
{
	struct giopci_softc *sc = v;
	int bus, dev, func;

	giopci_decompose_tag(v, tag, &bus, &dev, &func);
	if (bus != 0 || dev != 0 || func != 0)
		return;

	if (reg >= sc->sc_cfg_len)
		return;

	DPRINTF(("giopci_conf_write: reg 0x%x = 0x%08x\n", reg, data));
	bus_space_write_4(sc->sc_cfgt, sc->sc_cfgh, reg, data);
}

int
giopci_probe_device_hook(void *unused, struct pci_attach_args *notused)
{
	return 0;
}

/* will not actually be used */
int
giopci_get_widget(void *unused)
{
	return 0;
}

/* will not actually be used */
int
giopci_get_dl(void *v, pcitag_t tag, struct sgi_device_location *sdl)
{
	int bus, device, fn;

	memset(sdl, 0, sizeof *sdl);
	giopci_decompose_tag(v, tag, &bus, &device, &fn);
	if (bus != 0)
		return 0;
	sdl->device = device;
	sdl->fn = fn;
	return 1;
}

int
giopci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
	struct giopci_softc *sc = (struct giopci_softc *)pa->pa_pc->pc_intr_v;
	int intr;

	if (pa->pa_rawintrpin == 0)
		intr = -1;
	else
		intr = gio_intr_map(sc->sc_slot);

	*ihp = intr;
	return intr < 0 ? 1 : 0;
}

const char *
giopci_intr_string(void *v, pci_intr_handle_t ih)
{
	static char str[10];

	snprintf(str, sizeof(str), "irq %d", (int)ih);
	return str;
}

void *
giopci_intr_establish(void *v, pci_intr_handle_t ih, int level,
    int (*func)(void *), void *arg, const char *name)
{
	return gio_intr_establish((int)ih, level, func, arg, name);
}

void
giopci_intr_disestablish(void *v, void *ih)
{
	panic("%s", __func__);
}

int
giopci_intr_line(void *v, pci_intr_handle_t ih)
{
	return (int)ih;
}

int
giopci_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart,
    bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend)
{
	panic("%s", __func__);
}

#if NCARDBUS > 0
void *
giopci_rbus_parent_io(struct pci_attach_args *pa)
{
	panic("%s");
}

void *
giopci_rbus_parent_mem(struct pci_attach_args *pa)
{
	panic("%s");
}
#endif	/* NCARDBUS > 0 */

/*
 *  DMA routines
 */

int
giopci_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
    bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
{
	struct giopci_softc *sc = (struct giopci_softc *)t->_cookie;

	if (boundary == 0 || boundary > sc->sc_dma_boundary)
		boundary = sc->sc_dma_boundary;

	return bus_dmamap_create(sc->sc_dmat, size, nsegments, maxsegsz,
	    boundary, flags, dmamp);
}


code: src/sys/arch/sgi/hpc

path: sys/arch/sgi/hpc/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.1 2014/05/22 19:39:37 miod Exp $

AWK=	awk

PROG=	makemap.awk
MAP=	../../../dev/pckbc/wskbdmap_mfii.c

all:	wskbdmap_sgi.c

wskbdmap_sgi.c: ${MAP} ${PROG}
	/bin/rm -f $@
	${AWK} -f ${PROG} ${MAP} > $@

path: sys/arch/sgi/hpc/Makefile


code:
/*	$OpenBSD: dpclock.c,v 1.3 2014/10/11 18:41:18 miod Exp $	*/
/*	$NetBSD: dpclock.c,v 1.3 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2012 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.
 */
/*
 * Copyright (c) 2001 Erik Reid
 * Copyright (c) 2001 Rafal K. Boni
 * Copyright (c) 2001 Christopher Sekiya
 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Portions of this code are derived from software contributed to The
 * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
 * Simulation Facility, NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1982, 1990, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah $Hdr: clock.c 1.18 91/01/21$
 *
 *	@(#)clock.c	8.2 (Berkeley) 1/12/94
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <machine/bus.h>

#include <mips64/dev/clockvar.h>

#include <dev/ic/dp8573areg.h>
#include <sgi/hpc/hpcvar.h>

#define	IRIX_BASE_YEAR	1940

struct dpclock_softc {
	struct device		sc_dev;

	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

int	dpclock_match(struct device *, void *, void *);
void	dpclock_attach(struct device *, struct device *, void *);

struct cfdriver dpclock_cd = {
	NULL, "dpclock", DV_DULL
};

const struct cfattach dpclock_ca = {
	sizeof(struct dpclock_softc), dpclock_match, dpclock_attach
};

#define	dpclock_read(sc,r) \
	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
#define	dpclock_write(sc,r,v) \
	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))

static inline int frombcd(int);
static inline int tobcd(int);
static inline int leapyear(int year);

static inline int
frombcd(int x)
{
	return (x >> 4) * 10 + (x & 0xf);
}
static inline int
tobcd(int x)
{
	return (x / 10 * 16) + (x % 10);
}
/*
 * This inline avoids some unnecessary modulo operations
 * as compared with the usual macro:
 *   ( ((year % 4) == 0 &&
 *      (year % 100) != 0) ||
 *     ((year % 400) == 0) )
 * It is otherwise equivalent.
 * (borrowed from kern/clock_subr.c)
 */
static inline int
leapyear(int year)
{
	int rv = 0;

	if ((year & 3) == 0) {
		rv = 1;
		if ((year % 100) == 0) {
			rv = 0;
			if ((year % 400) == 0)
				rv = 1;
		}
	}
	return (rv);
}

void	dpclock_gettime(void *, time_t, struct tod_time *);
void	dpclock_settime(void *, struct tod_time *);

int
dpclock_match(struct device *parent, void *vcf, void *aux)
{
	struct hpc_attach_args *haa = aux;

	if (strcmp(haa->ha_name, dpclock_cd.cd_name) != 0)
		return 0;

	return 1;
}

void
dpclock_attach(struct device *parent, struct device *self, void *aux)
{
	struct dpclock_softc *sc = (void *)self;
	struct hpc_attach_args *haa = aux;
	uint8_t st, mode, pflag;

	sc->sc_iot = haa->ha_st;
	if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
	    4 * DP8573A_NREG, &sc->sc_ioh) != 0) {
		printf(": can't map registers\n");
		return;
	}

	st = dpclock_read(sc, DP8573A_STATUS);
	dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
	mode = dpclock_read(sc, DP8573A_RT_MODE);
	if ((mode & DP8573A_RT_MODE_CLKSS) == 0) {
		printf(": clock stopped");
		dpclock_write(sc, DP8573A_RT_MODE,
		    mode | DP8573A_RT_MODE_CLKSS);
		dpclock_write(sc, DP8573A_INT0_CTL, 0);
		dpclock_write(sc, DP8573A_INT1_CTL, DP8573A_INT1_CTL_PWRINT);
	}
	dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
	pflag = dpclock_read(sc, DP8573A_PFLAG);
	if (pflag & DP8573A_PFLAG_OFSS) {
		dpclock_write(sc, DP8573A_PFLAG, pflag);
		pflag = dpclock_read(sc, DP8573A_PFLAG);
		if (pflag & DP8573A_PFLAG_OFSS) {
			/*
			 * If the `oscillator failure' condition sticks,
			 * the battery needs replacement and the clock
			 * is not ticking. Do not claim sys_tod.
			 */
			printf("%s oscillator failure\n",
			    (mode & DP8573A_RT_MODE_CLKSS) == 0 ?  "," : ":");
			return;
		}
	}
	if (pflag & DP8573A_PFLAG_TESTMODE) {
		dpclock_write(sc, DP8573A_RAM_1F, 0);
		dpclock_write(sc, DP8573A_PFLAG,
		    pflag & ~DP8573A_PFLAG_TESTMODE);
	}

	printf("\n");

	sys_tod.tod_get = dpclock_gettime;
	sys_tod.tod_set = dpclock_settime;
	sys_tod.tod_cookie = self;
}

/*
 * Get the time of day, based on the clock's value and/or the base value.
 */
void
dpclock_gettime(void *cookie, time_t base, struct tod_time *ct)
{
	struct dpclock_softc *sc = (void *)cookie;
	uint i;
	uint8_t regs[DP8573A_NREG];

	i = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
	dpclock_write(sc, DP8573A_TIMESAVE_CTL, i | DP8573A_TIMESAVE_CTL_EN);
	dpclock_write(sc, DP8573A_TIMESAVE_CTL, i);

	for (i = 0; i < nitems(regs); i++)
		regs[i] = dpclock_read(sc, i);

	ct->sec = frombcd(regs[DP8573A_SAVE_SEC]);
	ct->min = frombcd(regs[DP8573A_SAVE_MIN]);

	if (regs[DP8573A_RT_MODE] & DP8573A_RT_MODE_1224) {
		ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
		    DP8573A_HOUR_12HR_MASK) +
		    ((regs[DP8573A_SAVE_HOUR] & DP8573A_RT_MODE_1224) ? 0 : 12);

		/*
		 * In AM/PM mode, hour range is 01-12, so adding in 12 hours
		 * for PM gives us 01-24, whereas we want 00-23, so map hour
		 * 24 to hour 0.
		 */
		if (ct->hour == 24)
			ct->hour = 0;
	} else {
		ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
		    DP8573A_HOUR_24HR_MASK);
	}

	ct->day = frombcd(regs[DP8573A_SAVE_DOM]);
	ct->mon = frombcd(regs[DP8573A_SAVE_MONTH]);
	ct->year = frombcd(regs[DP8573A_YEAR]) + (IRIX_BASE_YEAR - 1900);
}

/*
 * Reset the TODR based on the time value.
 */
void
dpclock_settime(void *cookie, struct tod_time *ct)
{
	struct dpclock_softc *sc = (void *)cookie;
	uint i;
	uint st, r, delta;
	uint8_t regs[DP8573A_NREG];

	r = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
	dpclock_write(sc, DP8573A_TIMESAVE_CTL, r | DP8573A_TIMESAVE_CTL_EN);
	dpclock_write(sc, DP8573A_TIMESAVE_CTL, r);

	for (i = 0; i < nitems(regs); i++)
		regs[i] = dpclock_read(sc, i);

	regs[DP8573A_SUBSECOND] = 0;
	regs[DP8573A_SECOND] = tobcd(ct->sec);
	regs[DP8573A_MINUTE] = tobcd(ct->min);
	regs[DP8573A_HOUR] = tobcd(ct->hour) & DP8573A_HOUR_24HR_MASK;
	regs[DP8573A_DOW] = tobcd(ct->dow);
	regs[DP8573A_DOM] = tobcd(ct->day);
	regs[DP8573A_MONTH] = tobcd(ct->mon);
	regs[DP8573A_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900));

	st = dpclock_read(sc, DP8573A_STATUS);
	dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
	r = dpclock_read(sc, DP8573A_RT_MODE);
	dpclock_write(sc, DP8573A_RT_MODE, r & ~DP8573A_RT_MODE_CLKSS);

	for (i = 0; i < 10; i++)
		dpclock_write(sc, DP8573A_COUNTERS + i,
		    regs[DP8573A_COUNTERS + i]);

	/*
	 * We now need to set the leap year counter to the correct value.
	 * Unfortunately it is only two bits wide, while eight years can
	 * happen between two leap years.  Skirting this is left as an
	 * exercise to the reader with an Indigo in working condition
	 * by year 2100.
	 */
	delta = 0;
	while (delta < 3 && !leapyear(ct->year - delta))
		delta++;

	r &= ~(DP8573A_RT_MODE_LYLSB | DP8573A_RT_MODE_LYMSB);
	dpclock_write(sc, DP8573A_RT_MODE, r | delta | DP8573A_RT_MODE_CLKSS);

	dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
}


code:
/*	$OpenBSD: dsclock.c,v 1.4 2012/10/03 22:46:09 miod Exp $	*/
/*	$NetBSD: dsclock.c,v 1.5 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2001 Rafal K. Boni
 * Copyright (c) 2001 Christopher Sekiya
 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Portions of this code are derived from software contributed to The
 * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
 * Simulation Facility, NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <machine/bus.h>

#include <mips64/dev/clockvar.h>

#include <dev/ic/ds1286reg.h>
#include <sgi/hpc/hpcvar.h>
#include <sgi/sgi/ip22.h>

struct dsclock_softc {
	struct device		sc_dev;

	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	uint			sc_base;
};

int	dsclock_match(struct device *, void *, void *);
void	dsclock_attach(struct device *, struct device *, void *);

struct cfdriver dsclock_cd = {
	NULL, "dsclock", DV_DULL
};

const struct cfattach dsclock_ca = {
	sizeof(struct dsclock_softc), dsclock_match, dsclock_attach
};

#define	ds1286_read(sc,r) \
	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
#define	ds1286_write(sc,r,v) \
	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))

static inline int frombcd(int);
static inline int tobcd(int);

static inline int
frombcd(int x)
{
	return (x >> 4) * 10 + (x & 0xf);
}
static inline int
tobcd(int x)
{
	return (x / 10 * 16) + (x % 10);
}

void	dsclock_gettime(void *, time_t, struct tod_time *);
void	dsclock_settime(void *, struct tod_time *);

int
dsclock_match(struct device *parent, void *vcf, void *aux)
{
	struct hpc_attach_args *haa = aux;

	if (strcmp(haa->ha_name, dsclock_cd.cd_name) != 0)
		return 0;

	return 1;
}

void
dsclock_attach(struct device *parent, struct device *self, void *aux)
{
	struct dsclock_softc *sc = (void *)self;
	struct hpc_attach_args *haa = aux;
	ds1286_todregs regs;

	sc->sc_iot = haa->ha_st;
	if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
	    4 * 8192, &sc->sc_ioh) != 0) {
		printf(": can't map registers\n");
		return;
	}

	printf("\n");

	sys_tod.tod_get = dsclock_gettime;
	sys_tod.tod_set = dsclock_settime;
	sys_tod.tod_cookie = self;

	/*
	 * Try and figure out what year the chip time is relative to.
	 * Different Indy PROM versions appear to use different base:
	 *  PROM Monitor SGI Version 5.1 Rev B3 IP24 Sep 17, 1993 (BE)
	 * uses 1970, while
	 *  PROM Monitor SGI Version 5.3 Rev B10 R4X00/R5000 IP24 Feb 12, 1996 (BE)
	 * uses 1940.
	 */

	DS1286_GETTOD(sc, &regs);
	sc->sc_base = bios_year - frombcd(regs[DS1286_YEAR]);
	/* year might have changed between the ARCBios call and now... */
	if ((sc->sc_base % 10) == 9)
		sc->sc_base++;

	/*
	 * If the data in the chip does not make sense, assume the usual
	 * IRIX timebase (1940 because it's a leap year).
	 */
	if (sc->sc_base != 1940 && sc->sc_base != POSIX_BASE_YEAR)
		sc->sc_base = 1940;

	/* mips64 clock code expects year relative to 1900 */
	sc->sc_base -= 1900;
}

/*
 * Get the time of day, based on the clock's value and/or the base value.
 */
void
dsclock_gettime(void *cookie, time_t base, struct tod_time *ct)
{
	struct dsclock_softc *sc = (void *)cookie;
	ds1286_todregs regs;
	int s;

	s = splhigh();
	DS1286_GETTOD(sc, &regs)
	splx(s);

	ct->sec = frombcd(regs[DS1286_SEC]);
	ct->min = frombcd(regs[DS1286_MIN]);

	if (regs[DS1286_HOUR] & DS1286_HOUR_12MODE) {
		ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_12HR_MASK) +
		    ((regs[DS1286_HOUR] & DS1286_HOUR_12HR_PM) ? 12 : 0);

		/*
		 * In AM/PM mode, hour range is 01-12, so adding in 12 hours
		 * for PM gives us 01-24, whereas we want 00-23, so map hour
		 * 24 to hour 0.
		 */
		if (ct->hour == 24)
			ct->hour = 0;
	} else {
		 ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_24HR_MASK);
	}

	ct->day = frombcd(regs[DS1286_DOM]);
	ct->mon = frombcd(regs[DS1286_MONTH] & DS1286_MONTH_MASK);
	ct->year = frombcd(regs[DS1286_YEAR]) + sc->sc_base;
}

/*
 * Reset the TODR based on the time value.
 */
void
dsclock_settime(void *cookie, struct tod_time *ct)
{
	struct dsclock_softc *sc = (void *)cookie;
	ds1286_todregs regs;
	int s;

	s = splhigh();
	DS1286_GETTOD(sc, &regs);
	splx(s);

	regs[DS1286_SUBSEC] = 0;
	regs[DS1286_SEC] = tobcd(ct->sec);
	regs[DS1286_MIN] = tobcd(ct->min);
	regs[DS1286_HOUR] = tobcd(ct->hour) & DS1286_HOUR_24HR_MASK;
	regs[DS1286_DOW] = tobcd(ct->dow);
	regs[DS1286_DOM] = tobcd(ct->day);

	/* Leave wave-generator bits as set originally */
	regs[DS1286_MONTH] &=  ~DS1286_MONTH_MASK;
	regs[DS1286_MONTH] |=  tobcd(ct->mon) & DS1286_MONTH_MASK;

	regs[DS1286_YEAR] = tobcd(ct->year - sc->sc_base);

	s = splhigh();
	DS1286_PUTTOD(sc, &regs);
	splx(s);
}


code:
# $OpenBSD: files.hpc,v 1.6 2015/05/11 06:46:21 ratchov Exp $
# $NetBSD: files.hpc,v 1.14 2009/05/14 01:10:19 macallan Exp $

# IP20 RTC
device	dpclock
attach	dpclock at hpc
file	arch/sgi/hpc/dpclock.c			dpclock

# IP22/24 RTC
device	dsclock
attach	dsclock at hpc
file	arch/sgi/hpc/dsclock.c			dsclock

device	sq: ether, ifnet, ifmedia
attach	sq at hpc
file	arch/sgi/hpc/if_sq.c			sq

define	hpcdma
file	arch/sgi/hpc/hpcdma.c			hpcdma

device	wdsc: wd33c93ctrl, scsi, hpcdma
attach	wdsc at hpc
file	arch/sgi/hpc/wdsc.c			wdsc

device	haltwo: audio
attach	haltwo at hpc
file	arch/sgi/hpc/haltwo.c			haltwo

device	zs {[channel = -1]}
attach	zs at hpc with zs_hpc
file 	arch/sgi/hpc/zs.c			zs needs-flag
file 	dev/ic/z8530sc.c			zs

device	zstty: tty
attach	zstty at zs
file 	dev/ic/z8530tty.c			zstty needs-flag

device	zskbd: wskbddev
attach	zskbd at zs
file	arch/sgi/hpc/z8530kbd.c			zskbd needs-flag
file	arch/sgi/hpc/wskbdmap_sgi.c		zskbd

device	zsms: wsmousedev
attach	zsms at zs
file	arch/sgi/hpc/z8530ms.c			zsms

attach	pckbc at hpc with pckbc_hpc
file	arch/sgi/hpc/pckbc_hpc.c		pckbc_hpc

#device	pione
#attach	pione at hpc
#file	arch/sgi/hpc/pione.c			pione

device	panel
attach	panel at hpc
file	arch/sgi/hpc/panel.c			panel