code:
/*	$OpenBSD: owmac.c,v 1.2 2009/04/13 21:14:41 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * DS1981/1982/2502 1-Wire Add-only memory driver, for SGI machines.
 *
 * SGI uses DS1981 (or compatibles) to store the Ethernet address
 * on IOC boards.
 */

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

#include <dev/onewire/onewiredevs.h>
#include <dev/onewire/onewirereg.h>
#include <dev/onewire/onewirevar.h>

#include <sgi/dev/owmem_subr.h>
#include <sgi/dev/owmacvar.h>

int	owmac_match(struct device *, void *, void *);
void	owmac_attach(struct device *, struct device *, void *);

struct cfattach owmac_ca = {
	sizeof(struct owmac_softc), owmac_match, owmac_attach,
};

struct cfdriver owmac_cd = {
	NULL, "owmac", DV_DULL
};

#define	EEPROM_NPAGES		4

static const struct onewire_matchfam owmac_fams[] = {
	{ ONEWIRE_FAMILY_DS1982 }
};

int	owmac_read_page(struct owmac_softc *, int, uint8_t *);
int	owmac_read_redirect(struct owmac_softc *);

void	owmac_read_mac(struct owmac_softc *);

int
owmac_match(struct device *parent, void *match, void *aux)
{
	struct onewire_attach_args *oa = aux;

	if (ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom) == ONEWIRE_FAMILY_DS1982)
		return 1;

	/*
	 * Also match on UniqueWare devices with specific 0x91 family code.
	 */
	if ((ONEWIRE_ROM_SN(oa->oa_rom) >> (48 - 12)) == 0x5e7 &&
	    ONEWIRE_ROM_FAMILY_CUSTOM(oa->oa_rom) &&
	    ONEWIRE_ROM_FAMILY(oa->oa_rom) == 0x91)
		return 1;

	return 0;
}

void
owmac_attach(struct device *parent, struct device *self, void *aux)
{
	struct owmac_softc *sc = (struct owmac_softc *)self;
	struct onewire_attach_args *oa = aux;

	sc->sc_onewire = oa->oa_onewire;
	sc->sc_rom = oa->oa_rom;

	/*
	 * Read the redirection table.
	 */
	if (owmac_read_redirect(sc) != 0) {
		printf(": unable to read redirection data\n");
		return;
	}

	printf("\n");

	/*
	 * Read the data.
	 */
	owmac_read_mac(sc);
}

int
owmac_read_redirect(struct owmac_softc *sc)
{
	int rc = 0;
	int status_offset;

	status_offset = 0x0001;		/* 1..4 */

	onewire_lock(sc->sc_onewire, 0);
	if ((rc = onewire_reset(sc->sc_onewire)) != 0)
		goto unlock;

	onewire_matchrom(sc->sc_onewire, sc->sc_rom);

	/*
	 * Start reading the EEPROM status block, at the page redirection
	 * offset.
	 */
	onewire_write_byte(sc->sc_onewire, ONEWIRE_CMD_READ_STATUS);
	onewire_write_byte(sc->sc_onewire, status_offset & 0xff);
	onewire_write_byte(sc->sc_onewire, status_offset >> 8);
	/* XXX should verify this crc value */
	(void)onewire_read_byte(sc->sc_onewire);

	onewire_read_block(sc->sc_onewire, &sc->sc_redir, EEPROM_NPAGES);

	onewire_reset(sc->sc_onewire);
unlock:
	onewire_unlock(sc->sc_onewire);

	return rc;
}

int
owmac_read_page(struct owmac_softc *sc, int page, uint8_t *buf)
{
	int rc = 0;
	int pg;

	/*
	 * Follow the redirection information.
	 */
	if ((pg = owmem_redirect(sc->sc_redir, EEPROM_NPAGES, page)) < 0)
		return EINVAL;

	pg = page * EEPROM_PAGE_SIZE;

	onewire_lock(sc->sc_onewire, 0);
	if ((rc = onewire_reset(sc->sc_onewire)) != 0)
		goto unlock;

	onewire_matchrom(sc->sc_onewire, sc->sc_rom);

	/*
	 * Start reading the EEPROM data.
	 */
	onewire_write_byte(sc->sc_onewire, ONEWIRE_CMD_READ_MEMORY);
	onewire_write_byte(sc->sc_onewire, pg & 0xff);
	onewire_write_byte(sc->sc_onewire, 0);
	/* XXX should verify this crc value */
	(void)onewire_read_byte(sc->sc_onewire);

	onewire_read_block(sc->sc_onewire, buf, EEPROM_PAGE_SIZE);

	onewire_reset(sc->sc_onewire);
unlock:
	onewire_unlock(sc->sc_onewire);

	return rc;
}

void
owmac_read_mac(struct owmac_softc *sc)
{
	uint8_t buf[EEPROM_PAGE_SIZE];

	if (owmac_read_page(sc, 0, buf) != 0)
		return;

	if (buf[0] != 0x0a)
		return;

	sc->sc_enaddr[0] = buf[10];
	sc->sc_enaddr[1] = buf[9];
	sc->sc_enaddr[2] = buf[8];
	sc->sc_enaddr[3] = buf[7];
	sc->sc_enaddr[4] = buf[6];
	sc->sc_enaddr[5] = buf[5];

	printf("%s: Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    sc->sc_dev.dv_xname,
	    sc->sc_enaddr[0], sc->sc_enaddr[1], sc->sc_enaddr[2],
	    sc->sc_enaddr[3], sc->sc_enaddr[4], sc->sc_enaddr[5]);
}


code:
/*	$OpenBSD: owmacvar.h,v 1.1 2008/04/07 22:55:57 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * DS1981/1982/2502 1-Wire Add-only memory driver, for SGI machines.
 *
 * SGI uses DS1981 (or compatibles) to store the Ethernet address
 * on IOC boards.
 */

struct owmac_softc {
	struct device	 sc_dev;

	void		*sc_onewire;
	uint64_t	 sc_rom;

	uint8_t		 sc_redir[4];		/* redirection table */

	uint8_t		 sc_enaddr[6];
};

license: unknown


code:
/*	$OpenBSD: owmem_subr.c,v 1.1 2008/04/07 22:55:57 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Common routines to owmac and owserial drivers.
 */

#include <sys/param.h>

#include <sgi/dev/owmem_subr.h>

int
owmem_redirect(uint8_t *redir, u_int npages, u_int page)
{
	int skips = 0;

	/*
	 * Follow the redirecting table until we end up in our final
	 * position. We have to be careful not to loop if the table
	 * is wrong.
	 */
	while (redir[page] != 0xff) {
		if (++skips >= npages)
			return -1;
		page = 0xff ^ redir[page];
		if (page >= npages)
			return -1;
	}

	return page;
}


code:
/*	$OpenBSD: owmem_subr.h,v 1.1 2008/04/07 22:55:57 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Common routines to owmac and owserial drivers.
 */

#define	EEPROM_PAGE_SIZE	(256 / NBBY)	/* 256 bits per page */

int	owmem_redirect(uint8_t *, u_int, u_int);


code:
/*	$OpenBSD: owserial.c,v 1.2 2009/04/19 18:33:53 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * DS2505 1-Wire Add-only memory driver, for SGI machines.
 *
 * SGI seems to use DS2505 (or compatibles) to store serial numbers.
 */

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

#include <dev/onewire/onewiredevs.h>
#include <dev/onewire/onewirereg.h>
#include <dev/onewire/onewirevar.h>

#include <sgi/dev/owmem_subr.h>
#include <sgi/dev/owserialvar.h>

int	owserial_match(struct device *, void *, void *);
void	owserial_attach(struct device *, struct device *, void *);

struct cfattach owserial_ca = {
	sizeof(struct owserial_softc), owserial_match, owserial_attach,
};

struct cfdriver owserial_cd = {
	NULL, "owserial", DV_DULL
};

#define	EEPROM_PAGE_SIZE	(256 / NBBY)	/* 256 bits per page */

static const struct onewire_matchfam owserial_fams[] = {
	{ ONEWIRE_FAMILY_DS2505 },
	{ ONEWIRE_FAMILY_DS2506 }
};

int	owserial_read_page(struct owserial_softc *, int, uint8_t *);
int	owserial_read_redirect(struct owserial_softc *);

void	owserial_read_serial(struct owserial_softc *);

int
owserial_match(struct device *parent, void *match, void *aux)
{
	return (onewire_matchbyfam(aux, owserial_fams,
	    sizeof(owserial_fams) /sizeof(owserial_fams[0])));
}

void
owserial_attach(struct device *parent, struct device *self, void *aux)
{
	struct owserial_softc *sc = (struct owserial_softc *)self;
	struct onewire_attach_args *oa = aux;

	sc->sc_onewire = oa->oa_onewire;
	sc->sc_rom = oa->oa_rom;

	/*
	 * Decide how many pages of 256 bits we have.
	 */

	if (ONEWIRE_ROM_FAMILY_TYPE(sc->sc_rom) == ONEWIRE_FAMILY_DS2506)
		sc->sc_npages = 256;
	else
		sc->sc_npages = 64;

	/*
	 * Read the redirection table.
	 */
	if (owserial_read_redirect(sc) != 0) {
		printf(": unable to read redirection data\n");
		return;
	}

	printf("\n");

	/*
	 * Read the data.
	 */
	owserial_read_serial(sc);
}

int
owserial_read_redirect(struct owserial_softc *sc)
{
	int rc = 0;
	int status_offset, pos;

	status_offset = 0x0100;		/* 100..13f or 100..1ff */
	pos = 0;

	onewire_lock(sc->sc_onewire, 0);
	if ((rc = onewire_reset(sc->sc_onewire)) != 0)
		goto unlock;

	onewire_matchrom(sc->sc_onewire, sc->sc_rom);

	/*
	 * Start reading the EEPROM status block, at the page redirection
	 * offset.
	 */
	onewire_write_byte(sc->sc_onewire, ONEWIRE_CMD_READ_STATUS);
	onewire_write_byte(sc->sc_onewire, status_offset & 0xff);
	onewire_write_byte(sc->sc_onewire, status_offset >> 8);

	for (pos = 0; pos < sc->sc_npages; pos += 8) {
		onewire_read_block(sc->sc_onewire, sc->sc_redir + pos, 8);
		/* XXX check crc */
		(void)onewire_read_byte(sc->sc_onewire);
		(void)onewire_read_byte(sc->sc_onewire);
	}

	onewire_reset(sc->sc_onewire);
unlock:
	onewire_unlock(sc->sc_onewire);

	return rc;
}

int
owserial_read_page(struct owserial_softc *sc, int page, uint8_t *buf)
{
	int rc = 0;
	int pg;

	/*
	 * Follow the redirection information.
	 */
	if ((pg = owmem_redirect(sc->sc_redir, sc->sc_npages, page)) < 0)
		return EINVAL;

	pg = page * EEPROM_PAGE_SIZE;

	onewire_lock(sc->sc_onewire, 0);
	if ((rc = onewire_reset(sc->sc_onewire)) != 0)
		goto unlock;

	onewire_matchrom(sc->sc_onewire, sc->sc_rom);

	/*
	 * Start reading the EEPROM data.
	 */
	onewire_write_byte(sc->sc_onewire, ONEWIRE_CMD_READ_MEMORY);
	onewire_write_byte(sc->sc_onewire, pg & 0xff);
	onewire_write_byte(sc->sc_onewire, pg >> 8);

	onewire_read_block(sc->sc_onewire, buf, EEPROM_PAGE_SIZE);

	onewire_reset(sc->sc_onewire);
unlock:
	onewire_unlock(sc->sc_onewire);

	return rc;
}

void
owserial_read_serial(struct owserial_softc *sc)
{
	uint8_t buf[EEPROM_PAGE_SIZE * 2];
	char name[1 + OWSERIAL_NAME_LEN];
	char product[1 + OWSERIAL_PRODUCT_LEN];
	char serial[1 + OWSERIAL_SERIAL_LEN];
	char *s, *e;
	int pg;
	int i;

	pg = owmem_redirect(sc->sc_redir, sc->sc_npages, 0);
	if (pg < 0 || owserial_read_page(sc, pg, buf) != 0)
		return;

	pg = owmem_redirect(sc->sc_redir, sc->sc_npages, 1);
	if (pg < 0 || owserial_read_page(sc, pg, buf + EEPROM_PAGE_SIZE) != 0)
		return;

	/* minimal sanity check */
	if (buf[0] != 0x01)
		return;
	for (i = EEPROM_PAGE_SIZE + 10; i < EEPROM_PAGE_SIZE + 16; i++)
		if (buf[i] != 0xff)
			return;

	bcopy(buf + 21, product, 9);
	bcopy(buf + EEPROM_PAGE_SIZE + 3, product + 9, 3);
	product[OWSERIAL_PRODUCT_LEN] = '\0';
	for (i = 0; i < OWSERIAL_PRODUCT_LEN; i++)
		if (product[i] != '-' && (product[i] < '0' || product[i] > '9'))
			return;

	bcopy(buf + EEPROM_PAGE_SIZE + 16, name, OWSERIAL_NAME_LEN);
	name[OWSERIAL_NAME_LEN] = '\0';
	for (i = 0; i < OWSERIAL_NAME_LEN; i++)
		if (name[i] < ' ' || name[i] > '~')
			return;

	bcopy(buf + 1, serial, OWSERIAL_SERIAL_LEN);
	serial[OWSERIAL_SERIAL_LEN] = '\0';
	for (i = 0; i < OWSERIAL_SERIAL_LEN; i++)
		if (serial[i] < ' ' || serial[i] > '~')
			return;

	/*
	 * Trim leading and trailing spaces from name and serial #
	 */

	strlcpy(sc->sc_product, product, sizeof sc->sc_product);

	s = name;
	while (*s == ' ')
		s++;
	e = name + OWSERIAL_NAME_LEN - 1;
	while (*e == ' ' && e >= s)
		*e-- = '\0';
	strlcpy(sc->sc_name, s, sizeof sc->sc_name);

	s = serial;
	while (*s == ' ')
		s++;
	e = serial + OWSERIAL_SERIAL_LEN - 1;
	while (*e == ' ' && e >= s)
		*e-- = '\0';
	strlcpy(sc->sc_serial, s, sizeof sc->sc_serial);

	printf("%s: \"%s\" p/n %s, serial %s\n",
	    sc->sc_dev.dv_xname, sc->sc_name, sc->sc_product, sc->sc_serial);
}


code:
/*	$OpenBSD: owserialvar.h,v 1.2 2009/04/19 18:33:53 miod Exp $	*/

/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * DS2505 1-Wire Add-only memory driver, for SGI machines.
 *
 * SGI seems to use DS2505 (or compatibles) to store serial numbers.
 */

#define	OWSERIAL_NAME_LEN	14
#define	OWSERIAL_PRODUCT_LEN	12
#define	OWSERIAL_SERIAL_LEN	20

struct owserial_softc {
	struct device	 sc_dev;

	void		*sc_onewire;
	uint64_t	 sc_rom;

	int		 sc_npages;		/* number of pages */
	uint8_t		 sc_redir[256];		/* redirection table */

	char		 sc_name[1 + OWSERIAL_NAME_LEN];
	char		 sc_product[1 + OWSERIAL_PRODUCT_LEN];
	char		 sc_serial[1 + OWSERIAL_SERIAL_LEN];
};


code:
/*	$OpenBSD: power.c,v 1.15 2014/07/11 08:18:30 guenther Exp $	*/

/*
 * Copyright (c) 2007 Jasper Lievisse Adriaanse <jasper@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/signalvar.h>

#include <machine/autoconf.h>
#include <mips64/archtype.h>

#include <dev/ic/ds1687reg.h>
#include <sgi/dev/dsrtcvar.h>

#include "power.h"

/*
 * Power button driver for the SGI O2 and Octane.
 */

int	power_intr(void *);

struct cfdriver power_cd = {
	NULL, "power", DV_DULL
};

#if NPOWER_MACEBUS > 0

#include <sgi/localbus/macebusvar.h>

void	power_macebus_attach(struct device *, struct device *, void *);
int	power_macebus_match(struct device *, void *, void *);

struct cfattach power_macebus_ca = {
	sizeof(struct device), power_macebus_match, power_macebus_attach
};

int
power_macebus_match(struct device *parent, void *match, void *aux)
{
	return (1);
}

void
power_macebus_attach(struct device *parent, struct device *self, void *aux)
{
	struct macebus_attach_args *maa = aux;

	/* Establish interrupt handler. */
	if (macebus_intr_establish(maa->maa_intr, maa->maa_mace_intr,
	    IST_EDGE, IPL_TTY, power_intr, self, self->dv_xname))
		printf("\n");
	else
		printf(": unable to establish interrupt!\n");
}

#endif

#if NPOWER_MAINBUS > 0

#include <sgi/xbow/xbow.h>
#include <sgi/xbow/xheartreg.h>

void	power_mainbus_attach(struct device *, struct device *, void *);
int	power_mainbus_match(struct device *, void *, void *);
int	power_mainbus_intr(void *);

struct cfattach power_mainbus_ca = {
	sizeof(struct device), power_mainbus_match, power_mainbus_attach
};

int
power_mainbus_match(struct device *parent, void *match, void *aux)
{
	struct mainbus_attach_args *maa = aux;

	if (strcmp(maa->maa_name, power_cd.cd_name) != 0)
		return 0;

	return sys_config.system_type == SGI_OCTANE ? 1 : 0;
}

void
power_mainbus_attach(struct device *parent, struct device *self, void *aux)
{
	/* Establish interrupt handler. */
	if (xbow_intr_establish(power_mainbus_intr, self, HEART_ISR_POWER,
	    IPL_TTY, self->dv_xname, NULL) != 0) {
		printf(": unable to establish interrupt!\n");
		return;
	}

	printf("\n");
}

int
power_mainbus_intr(void *v)
{
	/*
	 * Clear interrupt condition; debouncing the kickstart bit will not
	 * suffice.
	 */
	xbow_intr_clear(HEART_ISR_POWER);

	return power_intr(v);
}

#endif

int
power_intr(void *unused)
{
	extern int allowpowerdown;
	int val;

	/*
	 * Prevent further interrupts by clearing the kickstart flag
	 * in the DS1687's extended control register.
	 */
	val = dsrtc_register_read(DS1687_EXT_CTRL);
	if (val == -1)
		return 1;		/* no rtc attached */

	/* debounce condition */
	dsrtc_register_write(DS1687_EXT_CTRL, val & ~DS1687_KICKSTART);

	if (allowpowerdown == 1) {
		allowpowerdown = 0;
		prsignal(initprocess, SIGUSR2);
	}

	return 1;
}


code:
/*	$OpenBSD: spdmem_mainbus.c,v 1.2 2014/07/12 18:44:42 tedu Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

/*
 * Display SPD memory information obtained from an IP35 brick L1 controller.
 */

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

#include <dev/spdmemvar.h>

#include <mips64/archtype.h>

#include <machine/autoconf.h>

#include <sgi/sgi/l1.h>

struct spdmem_mainbus_softc {
	struct spdmem_softc	 sc_base;
	uint8_t			*sc_spd;
	size_t			 sc_spdlen;
};

int	spdmem_mainbus_match(struct device *, void *, void *);
void	spdmem_mainbus_attach(struct device *, struct device *, void *);
uint8_t	spdmem_mainbus_read(struct spdmem_softc *, uint8_t);

struct cfattach spdmem_mainbus_ca = {
	sizeof(struct spdmem_mainbus_softc),
	spdmem_mainbus_match, spdmem_mainbus_attach
};

int
spdmem_mainbus_match(struct device *parent, void *vcf, void *aux)
{
	struct spdmem_attach_args *saa = (struct spdmem_attach_args *)aux;
	extern struct cfdriver spdmem_cd;
	int rc;
	uint8_t *spd;
	size_t spdlen;

	if (sys_config.system_type != SGI_IP35)
		return 0;

	if (strcmp(saa->maa.maa_name, spdmem_cd.cd_name) != 0)
		return 0;

	rc = l1_get_brick_spd_record(saa->maa.maa_nasid, saa->dimm,
	    &spd, &spdlen);
	if (rc == 0) {
		free(spd, M_DEVBUF, 0);
		return 1;
	} else
		return 0;
}

void
spdmem_mainbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct spdmem_mainbus_softc *sc = (struct spdmem_mainbus_softc *)self;
	struct spdmem_attach_args *saa = (struct spdmem_attach_args *)aux;
	int rc;

	printf(" dimm %d:", saa->dimm);

	rc = l1_get_brick_spd_record(saa->maa.maa_nasid, saa->dimm,
	    &sc->sc_spd, &sc->sc_spdlen);
	if (rc != 0) {
		printf(" can't get SPD record from L1, error %d\n", rc);
		return;
	}

	sc->sc_base.sc_read = spdmem_mainbus_read;
	spdmem_attach_common(&sc->sc_base);
	/* free record, as it won't be accessed anymore */
	sc->sc_spdlen = 0;
	free(sc->sc_spd, M_DEVBUF, 0);
}

uint8_t
spdmem_mainbus_read(struct spdmem_softc *v, uint8_t reg)
{
	struct spdmem_mainbus_softc *sc = (struct spdmem_mainbus_softc *)v;

	if (reg < sc->sc_spdlen)
		return sc->sc_spd[reg];
	else
		return 0;
}


code: src/sys/arch/sgi/gio

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


code:
#	$OpenBSD: Makefile,v 1.1 2012/03/28 20:44:23 miod Exp $
#	$NetBSD: Makefile.giodevs,v 1.5 2008/10/19 22:05:21 apb Exp $

AWK=	awk

giodevs.h giodevs_data.h: giodevs devlist2h.awk
	/bin/rm -f giodevs.h giodevs_data.h
	${AWK} -f devlist2h.awk giodevs

path: sys/arch/sgi/gio/Makefile


code:
#! /usr/bin/awk -f
#	$OpenBSD: devlist2h.awk,v 1.2 2012/04/18 17:18:10 miod Exp $
#	$NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $
#
# Copyright (c) 1998 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Christos Zoulas.
#
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
#
# Copyright (c) 1995, 1996 Christopher G. Demetriou
# 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. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#      This product includes software developed by Christopher G. Demetriou.
#      This product includes software developed by Christos Zoulas
# 4. The name of the author(s) 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.
#
function collectline(_f, _line) {
	_oparen = 0
	_line = ""
	while (_f <= NF) {
		if ($_f == "#") {
			_line = _line "("
			_oparen = 1
			_f++
			continue
		}
		if (_oparen) {
			_line = _line $_f
			if (_f < NF)
				_line = _line " "
			_f++
			continue
		}
		_line = _line $_f
		if (_f < NF)
			_line = _line " "
		_f++
	}
	if (_oparen)
		_line = _line ")"
	return _line
}
BEGIN {
	nproducts = nvendors = blanklines = 0
	dfile="giodevs_data.h"
	hfile="giodevs.h"
	line=""
}
NR == 1 {
	VERSION = $0
	gsub("\\$", "", VERSION)

	printf("/*\n") > hfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > hfile
	printf(" *\n") > hfile
	printf(" * generated from:\n") > hfile
	printf(" *\t%s\n", VERSION) > hfile
	printf(" */\n\n") > hfile

	printf("/*\n") > dfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > dfile
	printf(" *\n") > dfile
	printf(" * generated from:\n") > dfile
	printf(" *\t%s\n", VERSION) > dfile
	printf(" */\n\n") > dfile

	next
}
NF > 0 && $1 == "product" {
	nproducts++

	products[nproducts, 1] = $2;
	products[nproducts, 2] = $3
	products[nproducts, 3] = collectline(4, line)

	next
}
{
	if ($0 == "")
		blanklines++
	if (blanklines < 2)
		print $0 > dfile
}
END {
	# print out the match tables

	printf("\n") > dfile

	printf("struct gio_knowndev {\n") > dfile
	printf("\tint productid;\n") > dfile
	printf("\tconst char *product;\n") > dfile
	printf("};\n") > dfile
	printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile

	printf("\n") > hfile
	for (i = 1; i <= nproducts; i++) {
		printf("#define GIO_PRODUCT_%s\t%s\t/* %s */\n",
		    products[i, 1], products[i,2], products[i, 3]) > hfile

		printf("\t{ GIO_PRODUCT_%s, \"%s\" },\n",
		    products[i, 1], products[i, 3]) > dfile
	}
	printf("\t{ 0, NULL }\n") > dfile
	printf("};\n") > dfile
	close(dfile)
	close(hfile)
}


code:
# $OpenBSD: files.gio,v 1.4 2012/05/10 21:30:09 miod Exp $
# $NetBSD: files.gio,v 1.11 2009/02/12 06:33:57 rumble Exp $

device	gio {[slot = -1], [addr = -1]}
attach	gio at giobus

file	arch/sgi/gio/gio.c			gio		needs-flag

device	hpc {[offset = -1]}: smc93cx6
attach	hpc at gio
file	arch/sgi/hpc/hpc.c			hpc

# XL graphics
device	newport: wsemuldisplaydev, rasops8
attach	newport at gio
file	arch/sgi/gio/newport.c			newport		needs-flag

# GR2 graphics
device	grtwo: wsemuldisplaydev, rasops8
attach	grtwo at gio
file	arch/sgi/gio/grtwo.c			grtwo		needs-flag

# LG1/LG2 graphics
device	light: wsemuldisplaydev, rasops8
attach	light at gio
file	arch/sgi/gio/light.c			light		needs-flag

# Impact graphics
attach	impact at gio with impact_gio
file	arch/sgi/gio/impact_gio.c		impact_gio

# PCI cards glued to the GIO bus
device	giopci: pcibus
attach	giopci at gio
file	arch/sgi/gio/pci_gio.c			giopci


code:
/*	$OpenBSD: gio.c,v 1.18 2014/05/19 21:18:42 miod Exp $	*/
/*	$NetBSD: gio.c,v 1.32 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) 2000 Soren S. Jorvang
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *          This product includes software developed for the
 *          NetBSD Project.  See http://www.NetBSD.org/ for
 *          information about NetBSD.
 * 4. 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/systm.h>
#include <sys/device.h>

#include <mips64/archtype.h>

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

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

#include <sgi/gio/grtworeg.h>
#include <sgi/gio/lightreg.h>
#include <sgi/gio/newportreg.h>

#include <sgi/localbus/imcvar.h>
#include <sgi/localbus/intreg.h>
#include <sgi/localbus/intvar.h>
#include <sgi/sgi/ip22.h>

#include "grtwo.h"
#include "impact.h"
#include "light.h"
#include "newport.h"

#if NGRTWO > 0
#include <sgi/gio/grtwovar.h>
#endif
#if NIMPACT_GIO > 0
#include <sgi/dev/impactvar.h>
#endif
#if NLIGHT > 0
#include <sgi/gio/lightvar.h>
#endif
#if NNEWPORT > 0
#include <sgi/gio/newportvar.h>
#endif

int	 gio_match(struct device *, void *, void *);
void	 gio_attach(struct device *, struct device *, void *);
int	 gio_print(void *, const char *);
int	 gio_print_fb(void *, const char *);
int	 gio_search(struct device *, void *, void *);
int	 gio_submatch(struct device *, void *, void *);
uint32_t gio_id(vaddr_t, paddr_t, int);
int	 gio_is_framebuffer_id(uint32_t);

struct gio_softc {
	struct device	sc_dev;

	bus_space_tag_t	sc_iot;
	bus_dma_tag_t	sc_dmat;
};

const struct cfattach gio_ca = {
	sizeof(struct gio_softc), gio_match, gio_attach
};

struct cfdriver gio_cd = {
	NULL, "gio", DV_DULL
};

/* Address of the console frame buffer registers, if applicable */
paddr_t		giofb_consaddr;
/* Id of the console frame buffer */
uint32_t	giofb_consid;
/* Names of the frame buffers, as obtained by ARCBios */
const char	*giofb_names[GIO_MAX_FB];

struct gio_probe {
	uint32_t slot;
	uint64_t base;
	uint32_t mach_type;
	uint32_t mach_subtype;
};

/*
 * Expansion Slot Base Addresses
 *
 * IP20 and IP24 have two GIO connectors: GIO_SLOT_EXP0 and
 * GIO_SLOT_EXP1.
 *
 * On IP24 these slots exist on the graphics board or the IOPLUS
 * "mezzanine" on Indy and Challenge S, respectively. The IOPLUS or
 * graphics board connects to the mainboard via a single GIO64 connector.
 *
 * IP22 has either three or four physical connectors, but only two
 * electrically distinct slots: GIO_SLOT_GFX and GIO_SLOT_EXP0.
 *
 * It should also be noted that DMA is (mostly) not supported in Challenge S's
 * GIO_SLOT_EXP1. See gio(4) for the story.
 */
static const struct gio_probe slot_bases[] = {
	/* GFX is only a slot on Indigo 2 */
	{ GIO_SLOT_GFX, GIO_ADDR_GFX, SGI_IP22, IP22_INDIGO2 },

	/* EXP0 is available on all systems */
	{ GIO_SLOT_EXP0, GIO_ADDR_EXP0, SGI_IP20, -1 },
	{ GIO_SLOT_EXP0, GIO_ADDR_EXP0, SGI_IP22, -1 },

	/* EXP1 does not exist on Indigo 2 */
	{ GIO_SLOT_EXP1, GIO_ADDR_EXP1, SGI_IP20, -1 },
	{ GIO_SLOT_EXP1, GIO_ADDR_EXP1, SGI_IP22, IP22_INDY },
	{ GIO_SLOT_EXP1, GIO_ADDR_EXP1, SGI_IP22, IP22_CHALLS },

	{ 0, 0, 0, 0 }
};

/*
 * Graphic Board Base Addresses
 *
 * Graphics boards are not treated like expansion slot cards. Their base
 * addresses do not necessarily correspond to GIO slot addresses and they
 * do not contain product identification words.
 *
 * This list needs to be sorted in address order, to match the descriptions
 * obtained from ARCBios.
 */
static const struct gio_probe gfx_bases[] = {
	{ -1, GIO_ADDR_GFX, SGI_IP20, -1 },
	{ -1, GIO_ADDR_GFX, SGI_IP22, -1 },

	/* IP20 LG1/LG2 */
	{ -1, GIO_ADDR_GFX + 0x003f0000, SGI_IP20, -1 },
	{ -1, GIO_ADDR_GFX + 0x003f8000, SGI_IP20, -1 }, /* second head */

	{ -1, GIO_ADDR_EXP0, SGI_IP22, -1 },
	{ -1, GIO_ADDR_EXP1, SGI_IP22, -1 },

	{ 0, 0, 0, 0 }
};

int
gio_match(struct device *parent, void *match, void *aux)
{
	struct imc_attach_args *iaa = aux;

	if (strcmp(iaa->iaa_name, gio_cd.cd_name) != 0)
		return 0;

	return 1;
}

void
gio_attach(struct device *parent, struct device *self, void *aux)
{
	struct gio_softc *sc = (struct gio_softc *)self;
	struct imc_attach_args *iaa = (struct imc_attach_args *)aux;
	struct gio_attach_args ga;
	uint32_t gfx[GIO_MAX_FB], id;
	uint i, j, ngfx;
	int sys_type;

	printf("\n");

	sc->sc_iot = iaa->iaa_st;
	sc->sc_dmat = iaa->iaa_dmat;

	switch (sys_config.system_type) {
	case SGI_IP20:
		sys_type = SGI_IP20;
		break;
	default:
	case SGI_IP22:
	case SGI_IP26:
	case SGI_IP28:
		sys_type = SGI_IP22;
		break;
	}

	ngfx = 0;
	memset(gfx, 0, sizeof(gfx));

	/*
	 * Try and attach graphics devices first.
	 * Unfortunately, they - not being GIO devices after all (except for
	 * Impact) - do not contain a Product Identification Word, nor have
	 * a slot number.
	 *
	 * Record addresses to which graphics devices attach so that
	 * we do not confuse them with expansion slots, should the
	 * addresses coincide.
	 *
	 * If only the ARCBios component tree would be so kind as to give
	 * us the address of the frame buffer components...
	 */
	if (sys_type != SGI_IP22 ||
	    sys_config.system_subtype != IP22_CHALLS) {
		for (i = 0; gfx_bases[i].base != 0; i++) {
			/* skip slots that don't apply to us */
			if (gfx_bases[i].mach_type != sys_type)
				continue;

			if (gfx_bases[i].mach_subtype != -1 &&
			    gfx_bases[i].mach_subtype !=
			      sys_config.system_subtype)
				continue;

			ga.ga_addr = gfx_bases[i].base;
			ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);

			/* no need to probe a glass console again */
			if (ga.ga_addr == giofb_consaddr && giofb_consid != 0)
				id = giofb_consid;
			else {
				id = gio_id(ga.ga_ioh, ga.ga_addr, 1);
				if (!gio_is_framebuffer_id(id))
					continue;
			}

			ga.ga_iot = sc->sc_iot;
			ga.ga_dmat = sc->sc_dmat;
			ga.ga_slot = -1;
			ga.ga_product = id;
			/*
			 * Note that this relies upon ARCBios listing frame
			 * buffers in ascending address order, which seems
			 * to be the case so far on multihead Indigo2 systems.
			 */
			if (ngfx < GIO_MAX_FB)
				ga.ga_descr = giofb_names[ngfx];
			else
				ga.ga_descr = NULL;	/* shouldn't happen */

			if (config_found_sm(self, &ga, gio_print_fb,
			    gio_submatch))
				gfx[ngfx] = gfx_bases[i].base;

			ngfx++;
		}
	}

	/*
	 * Now attach any GIO expansion cards.
	 *
	 * Be sure to skip any addresses to which a graphics device has
	 * already been attached.
	 */
	for (i = 0; slot_bases[i].base != 0; i++) {
		int skip = 0;

		/* skip slots that don't apply to us */
		if (slot_bases[i].mach_type != sys_type)
			continue;

		if (slot_bases[i].mach_subtype != -1 &&
		    slot_bases[i].mach_subtype != sys_config.system_subtype)
			continue;

		for (j = 0; j < ngfx; j++) {
			if (slot_bases[i].base == gfx[j]) {
				skip = 1;
				break;
			}
		}
		if (skip)
			continue;

		ga.ga_addr = slot_bases[i].base;
		ga.ga_iot = sc->sc_iot;
		ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);

		id = gio_id(ga.ga_ioh, ga.ga_addr, 0);
		if (id == 0)
			continue;

		ga.ga_dmat = sc->sc_dmat;
		ga.ga_slot = slot_bases[i].slot;
		ga.ga_product = id;
		ga.ga_descr = NULL;

		config_found_sm(self, &ga, gio_print, gio_submatch);
	}

	config_search(gio_search, self, aux);
}

/*
 * Try and figure out whether there is a device at the given slot address.
 */
uint32_t
gio_id(vaddr_t va, paddr_t pa, int maybe_gfx)
{
	uint32_t id32, mystery;
	uint16_t id16 = 0;
	uint8_t id8 = 0;

	/*
	 * First, attempt to read the address with various sizes.
	 *
	 * - GIO32 devices will only support reads from 32-bit aligned
	 *   addresses, in all sizes (at least for the ID register).
	 * - frame buffers will support aligned reads from any size at
	 *   any address, but will actually return the access width if
	 *   the slot is pipelined.
	 */

	if (guarded_read_4(va, &id32) != 0)
		return 0;

	/*
	 * If the address doesn't match a base slot address, then we are
	 * only probing for a light(4) frame buffer.
	 */

	if (pa != GIO_ADDR_GFX && pa != GIO_ADDR_EXP0 && pa != GIO_ADDR_EXP1) {
		if (maybe_gfx == 0)
			return 0;
		else {
			if (pa == LIGHT_ADDR_0 || pa == LIGHT_ADDR_1) {
				if (guarded_read_4(va + REX_PAGE1_SET +
				    REX_P1REG_XYOFFSET, &id32) != 0)
					return 0;
				if (id32 == 0x08000800)
					return GIO_PRODUCT_FAKEID_LIGHT;
			}
			return 0;
		}
	}

	/*
	 * GIO32 devices with a 32-bit ID register will not necessarily
	 * answer to addresses not aligned on 32 bit boundaries.
	 */

	if (guarded_read_2(va | 2, &id16) != 0 ||
	    guarded_read_1(va | 3, &id8) != 0) {
		if (GIO_PRODUCT_32BIT_ID(id32))
			return id32;
		else /* not a frame buffer anyway */
			return GIO_PRODUCT_PRODUCTID(id32);
	}

	/*
	 * Of course, GIO32 devices with a 8-bit ID register can use the
	 * other bytes in the first 32-bit word for other purposes.
	 */

	if ((id32 & 0xffff) == id16 && (id32 & 0xff) == id8) {
		if (GIO_PRODUCT_32BIT_ID(id32))
			return id32;
		else if (!GIO_PRODUCT_32BIT_ID(id8) && id8 != 0x00)
			return /*GIO_PRODUCT_PRODUCTID*/(id8);
	}

	/*
	 * If there is a frame buffer device, then either we have hit a
	 * device register (grtwo), or we did not fault because the slot
	 * is pipelined (newport).
	 * In the latter case, we attempt to probe a known register offset.
	 */

	if (maybe_gfx) {
		/*
		 * On (at least) Indy systems with newport graphics, the
		 * presence of a SCSI Expansion board (030-8133) in either
		 * slot will cause extra bits to be set in the topmost byte
		 * of the 32-bit access to the pipelined slot (i.e. the
		 * value of id32 is 0x18000004, not 0x00000004).
		 *
		 * This would prevent newport from being recognized
		 * properly.
		 *
		 * This behaviour seems to be specific to the SCSI board,
		 * since the E++ board does not trigger it. This would
		 * rule out an HPC1.x-specific cause.
		 *
		 * We work around this by ignoring the topmost byte of id32
		 * from this point on, but it's ugly and isaish...
		 *
		 * Note that this is not necessary on Indigo 2 since this
		 * troublesome board can not be installed on such a system.
		 * Indigo are probably safe from this issues, for they can't
		 * use newport graphics; but the issue at hand might be
		 * HPC 1.x related, so better play safe.
		 */
		if (sys_config.system_type == SGI_IP20 ||
		    (sys_config.system_type == SGI_IP22 &&
		     sys_config.system_subtype != IP22_INDIGO2))
			id32 &= ~0xff000000;

		if (id32 != 4 || id16 != 2 || id8 != 1) {
			if (guarded_read_4(va + HQ2_MYSTERY, &mystery) == 0 &&
			    mystery == HQ2_MYSTERY_VALUE)
				return GIO_PRODUCT_FAKEID_GRTWO;
			else
				return 0;
		}

		/* could be newport(4) */
		if (pa == GIO_ADDR_GFX || pa == GIO_ADDR_EXP0) {
			va += NEWPORT_REX3_OFFSET;
			if (guarded_read_4(va, &id32) == 0 &&
			    guarded_read_2(va | 2, &id16) == 0 &&
			    guarded_read_1(va | 3, &id8) == 0) {
				if (id32 != 4 || id16 != 2 || id8 != 1)
					return GIO_PRODUCT_FAKEID_NEWPORT;
			}
		}

		return 0;
	}

	return 0;
}

int
gio_print(void *aux, const char *pnp)
{
	struct gio_attach_args *ga = aux;
	const char *descr;
	int product, revision;
	uint i;

	product = GIO_PRODUCT_PRODUCTID(ga->ga_product);
	if (GIO_PRODUCT_32BIT_ID(ga->ga_product))
		revision = GIO_PRODUCT_REVISION(ga->ga_product);
	else
		revision = 0;

	descr = "unknown GIO card";
	for (i = 0; gio_knowndevs[i].productid != 0; i++) {
		if (gio_knowndevs[i].productid == product) {
			descr = gio_knowndevs[i].product;
			break;
		}
	}

	if (pnp != NULL) {
		printf("%s", descr);
		if (ga->ga_product != -1)
			printf(" (product 0x%02x revision 0x%02x)",
			    product, revision);
		printf(" at %s", pnp);
	}

	if (ga->ga_slot != -1)
		printf(" slot %d", ga->ga_slot);
	printf(" addr 0x%llx", ga->ga_addr);

	return UNCONF;
}

int
gio_print_fb(void *aux, const char *pnp)
{
	struct gio_attach_args *ga = aux;
	const char *fbname;

	if (pnp != NULL) {
		switch (ga->ga_product) {
		case GIO_PRODUCT_FAKEID_GRTWO:
			fbname = "grtwo";
			break;
		case GIO_PRODUCT_FAKEID_LIGHT:
			fbname = "light";
			break;
		case GIO_PRODUCT_FAKEID_NEWPORT:
			fbname = "newport";
			break;
		default:
			if (GIO_PRODUCT_32BIT_ID(ga->ga_product) &&
			    GIO_PRODUCT_PRODUCTID(ga->ga_product) ==
			      GIO_PRODUCT_IMPACT)
				fbname = "impact";
			else	/* should never happen */
				fbname = "framebuffer";
			break;
		}
		printf("%s at %s", fbname, pnp);
	}

	printf(" addr 0x%llx", ga->ga_addr);

	return UNCONF;
}

int
gio_search(struct device *parent, void *vcf, void *aux)
{
	struct gio_softc *sc = (struct gio_softc *)parent;
	struct cfdata *cf = (struct cfdata *)vcf;
	struct gio_attach_args ga;

	/* Handled by direct configuration, so skip here */
	if (cf->cf_loc[1 /*GIOCF_ADDR*/] == -1)
		return 0;

	ga.ga_addr = (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/];
	ga.ga_iot = sc->sc_iot;
	ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
	ga.ga_dmat = sc->sc_dmat;
	ga.ga_slot = cf->cf_loc[0 /*GIOCF_SLOT*/];
	ga.ga_product = -1;
	ga.ga_descr = NULL;

	if ((*cf->cf_attach->ca_match)(parent, cf, &ga) == 0)
		return 0;

	config_attach(parent, cf, &ga, gio_print);

	return 1;
}

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

	if (cf->cf_loc[0 /*GIOCF_SLOT*/] != -1 &&
	    cf->cf_loc[0 /*GIOCF_SLOT*/] != ga->ga_slot)
		return 0;

	if (cf->cf_loc[1 /*GIOCF_ADDR*/] != -1 &&
	    (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/] != ga->ga_addr)
		return 0;

	return (*cf->cf_attach->ca_match)(parent, cf, aux);
}

int
giofb_cnprobe()
{
	struct gio_attach_args ga;
	uint32_t id;
	int i;
	int sys_type;

	switch (sys_config.system_type) {
	case SGI_IP20:
		sys_type = SGI_IP20;
		break;
	default:
	case SGI_IP22:
	case SGI_IP26:
	case SGI_IP28:
		sys_type = SGI_IP22;
		break;
	}

	for (i = 0; gfx_bases[i].base != 0; i++) {
		if (giofb_consaddr != 0 &&
		    gfx_bases[i].base != giofb_consaddr)
			continue;

		/* skip bases that don't apply to us */
		if (gfx_bases[i].mach_type != sys_type)
			continue;

		if (gfx_bases[i].mach_subtype != -1 &&
		    gfx_bases[i].mach_subtype != sys_config.system_subtype)
			continue;

		ga.ga_addr = gfx_bases[i].base;
		ga.ga_iot = &imcbus_tag;
		ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
		ga.ga_dmat = &imc_bus_dma_tag;
		ga.ga_slot = -1;
		ga.ga_descr = NULL;

		id = gio_id(ga.ga_ioh, ga.ga_addr, 1);
		if (!gio_is_framebuffer_id(id))
			continue;

		ga.ga_product = giofb_consid = id;
		switch (id) {
		default:
#if NIMPACT_GIO > 0
			if (GIO_PRODUCT_32BIT_ID(id) &&
			    GIO_PRODUCT_PRODUCTID(id) == GIO_PRODUCT_IMPACT) {
				if (impact_gio_cnprobe(&ga) != 0)
					return 0;
			}
#endif
			break;
		case GIO_PRODUCT_FAKEID_GRTWO:
#if NGRTWO > 0
			if (grtwo_cnprobe(&ga) != 0)
				return 0;
#endif
			break;
		case GIO_PRODUCT_FAKEID_LIGHT:
#if NLIGHT > 0
			if (light_cnprobe(&ga) != 0)
				return 0;
#endif
			break;
		case GIO_PRODUCT_FAKEID_NEWPORT:
#if NNEWPORT > 0
			if (newport_cnprobe(&ga) != 0)
				return 0;
#endif
			break;
		}
	}

	return ENXIO;
}

int
giofb_cnattach()
{
	struct gio_attach_args ga;

	ga.ga_addr = giofb_consaddr;
	ga.ga_iot = &imcbus_tag;
	ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
	ga.ga_dmat = &imc_bus_dma_tag;
	ga.ga_slot = -1;
	ga.ga_product = giofb_consid;
	ga.ga_descr = NULL;

	switch (giofb_consid) {
	default:
#if NIMPACT_GIO > 0
		if (GIO_PRODUCT_32BIT_ID(giofb_consid) &&
		    GIO_PRODUCT_PRODUCTID(giofb_consid) == GIO_PRODUCT_IMPACT) {
			if (impact_gio_cnattach(&ga) == 0)
				return 0;
		}
#endif
		break;
	case GIO_PRODUCT_FAKEID_GRTWO:
#if NGRTWO > 0
		if (grtwo_cnattach(&ga) == 0)
			return 0;
#endif
		break;
	case GIO_PRODUCT_FAKEID_LIGHT:
#if NLIGHT > 0
		if (light_cnattach(&ga) == 0)
			return 0;
#endif
		break;
	case GIO_PRODUCT_FAKEID_NEWPORT:
#if NNEWPORT > 0
		if (newport_cnattach(&ga) == 0)
			return 0;
#endif
		break;
	}

	giofb_consaddr = 0;
	return ENXIO;
}

int
gio_is_framebuffer_id(uint32_t id)
{
	switch (id) {
	case GIO_PRODUCT_FAKEID_GRTWO:
	case GIO_PRODUCT_FAKEID_LIGHT:
	case GIO_PRODUCT_FAKEID_NEWPORT:
		return 1;
	default:
		if (GIO_PRODUCT_32BIT_ID(id) &&
		    GIO_PRODUCT_PRODUCTID(id) == GIO_PRODUCT_IMPACT)
			return 1;
		else
			return 0;
	}
}

/*
 * Devices living in the expansion slots must enable or disable some
 * GIO arbiter settings. This is accomplished via imc(4) registers.
 */
int
gio_arb_config(int slot, uint32_t flags)
{
	if (flags == 0)
		return (EINVAL);

	if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV |
	    GIO_ARB_PIPE | GIO_ARB_NOPIPE | GIO_ARB_32BIT | GIO_ARB_64BIT |
	    GIO_ARB_HPC2_32BIT | GIO_ARB_HPC2_64BIT))
		return (EINVAL);

	if (((flags & GIO_ARB_RT)   && (flags & GIO_ARB_LB))  ||
	    ((flags & GIO_ARB_MST)  && (flags & GIO_ARB_SLV)) ||
	    ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE)) ||
	    ((flags & GIO_ARB_32BIT) && (flags & GIO_ARB_64BIT)) ||
	    ((flags & GIO_ARB_HPC2_32BIT) && (flags & GIO_ARB_HPC2_64BIT)))
		return (EINVAL);

	return (imc_gio64_arb_config(slot, flags));
}

/*
 * Return the logical interrupt number for an expansion board (not a frame
 * buffer!) in the specified slot.
 *
 * Indy and Challenge S have a single GIO interrupt per GIO slot, but
 * distinct slot interrups. Indigo and Indigo2 have three GIO interrupts per
 * slot, but at a given GIO interrupt level, all slots share the same
 * interrupt on the interrupt controller.
 *
 * Expansion boards appear to always use the intermediate level.
 */
int
gio_intr_map(int slot)
{
	switch (sys_config.system_type) {
	case SGI_IP20:
		if (slot == GIO_SLOT_GFX)
			return -1;
		return INT2_L0_INTR(INT2_L0_GIO_LVL1);
	case SGI_IP22:
	case SGI_IP26:
	case SGI_IP28:
		if (sys_config.system_subtype == IP22_INDIGO2) {
			if (slot == GIO_SLOT_EXP1)
				return -1;
			return INT2_L0_INTR(INT2_L0_GIO_LVL1);
		} else {
			if (slot == GIO_SLOT_GFX)
				return -1;
			return INT2_MAP1_INTR(slot == GIO_SLOT_EXP0 ?
			    INT2_MAP_GIO_SLOT0 : INT2_MAP_GIO_SLOT1);
		}
	default:
		return -1;
	}
}

void *
gio_intr_establish(int intr, int level, int (*func)(void *), void *arg,
    const char *what)
{
	return int2_intr_establish(intr, level, func, arg, what);
}

const char *
gio_product_string(int prid)
{
	int i;

	for (i = 0; gio_knowndevs[i].product != NULL; i++)
		if (gio_knowndevs[i].productid == prid)
			return (gio_knowndevs[i].product);

	return (NULL);
}


code:
$OpenBSD: giodevs,v 1.5 2014/08/19 19:01:15 miod Exp $
/*	$NetBSD: giodevs,v 1.8 2007/02/19 04:46:33 rumble Exp $	*/

/* devices with 8-bit identification registers */
product XPI		0x01	XPI low cost FDDI
product GTR		0x02	GTR TokenRing
product ISDN		0x04	Synchronous ISDN
product CANON		0x06	Canon Interface
product JPEG_D		0x08	JPEG (Double Wide)
product JPEG_S		0x09	JPEG (Single Wide)
product XPI_M0		0x0a	XPI mez. FDDI device 0
product XPI_M1		0x0b	XPI mez. FDDI device 1
product EP		0x0e	E-Plex 8-port Ethernet
product IVAS		0x30	Lyon Lamb IVAS
product	FORE_ATM	0x5c	FORE Systems GIA-200 ATM
product	GIOCLC		0x7f	Cyclone Colorbus

/* devices with 32-bit identification registers */
product ATM		0x05	ATM board
product SCSI		0x07	16 bit SCSI Card
product SMPTE		0x0c	SMPTE 259M Video
product BABBLE		0x0d	Babblefish Compression
product	IMPACT		0x10	Impact
product PHOBOS_G160	0x35	Phobos G160 10/100 Ethernet
product PHOBOS_G130	0x36	Phobos G130 10/100 Ethernet
product PHOBOS_G100	0x37	Phobos G100 100baseTX Fast Ethernet
product SETENG_GFE	0x38	Set Engineering GFE 10/100 Ethernet

path: sys/arch/sgi/gio/giodevs


code:
/*
 * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
 *
 * generated from:
 *	OpenBSD: giodevs,v 1.4 2012/07/18 20:10:12 miod Exp
 */

#define GIO_PRODUCT_XPI	0x01	/* XPI low cost FDDI */
#define GIO_PRODUCT_GTR	0x02	/* GTR TokenRing */
#define GIO_PRODUCT_ISDN	0x04	/* Synchronous ISDN */
#define GIO_PRODUCT_CANON	0x06	/* Canon Interface */
#define GIO_PRODUCT_JPEG_D	0x08	/* JPEG (Double Wide) */
#define GIO_PRODUCT_JPEG_S	0x09	/* JPEG (Single Wide) */
#define GIO_PRODUCT_XPI_M0	0x0a	/* XPI mez. FDDI device 0 */
#define GIO_PRODUCT_XPI_M1	0x0b	/* XPI mez. FDDI device 1 */
#define GIO_PRODUCT_EP	0x0e	/* E-Plex 8-port Ethernet */
#define GIO_PRODUCT_IVAS	0x30	/* Lyon Lamb IVAS */
#define GIO_PRODUCT_SETENG_GFE	0x38	/* Set Engineering GFE 10/100 Ethernet */
#define GIO_PRODUCT_FORE_ATM	0x5c	/* FORE Systems GIA-200 ATM */
#define GIO_PRODUCT_GIOCLC	0x7f	/* Cyclone Colorbus */
#define GIO_PRODUCT_ATM	0x05	/* ATM board */
#define GIO_PRODUCT_SCSI	0x07	/* 16 bit SCSI Card */
#define GIO_PRODUCT_SMPTE	0x0c	/* SMPTE 259M Video */
#define GIO_PRODUCT_BABBLE	0x0d	/* Babblefish Compression */
#define GIO_PRODUCT_IMPACT	0x10	/* Impact */
#define GIO_PRODUCT_PHOBOS_G160	0x35	/* Phobos G160 10/100 Ethernet */
#define GIO_PRODUCT_PHOBOS_G130	0x36	/* Phobos G130 10/100 Ethernet */
#define GIO_PRODUCT_PHOBOS_G100	0x37	/* Phobos G100 100baseTX Fast Ethernet */


code:
/*
 * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
 *
 * generated from:
 *	OpenBSD: giodevs,v 1.4 2012/07/18 20:10:12 miod Exp
 */

/*	$NetBSD: giodevs,v 1.8 2007/02/19 04:46:33 rumble Exp $	*/

/* devices with 8-bit identification registers */

struct gio_knowndev {
	int productid;
	const char *product;
};

struct gio_knowndev gio_knowndevs[] = {
	{ GIO_PRODUCT_XPI, "XPI low cost FDDI" },
	{ GIO_PRODUCT_GTR, "GTR TokenRing" },
	{ GIO_PRODUCT_ISDN, "Synchronous ISDN" },
	{ GIO_PRODUCT_CANON, "Canon Interface" },
	{ GIO_PRODUCT_JPEG_D, "JPEG (Double Wide)" },
	{ GIO_PRODUCT_JPEG_S, "JPEG (Single Wide)" },
	{ GIO_PRODUCT_XPI_M0, "XPI mez. FDDI device 0" },
	{ GIO_PRODUCT_XPI_M1, "XPI mez. FDDI device 1" },
	{ GIO_PRODUCT_EP, "E-Plex 8-port Ethernet" },
	{ GIO_PRODUCT_IVAS, "Lyon Lamb IVAS" },
	{ GIO_PRODUCT_SETENG_GFE, "Set Engineering GFE 10/100 Ethernet" },
	{ GIO_PRODUCT_FORE_ATM, "FORE Systems GIA-200 ATM" },
	{ GIO_PRODUCT_GIOCLC, "Cyclone Colorbus" },
	{ GIO_PRODUCT_ATM, "ATM board" },
	{ GIO_PRODUCT_SCSI, "16 bit SCSI Card" },
	{ GIO_PRODUCT_SMPTE, "SMPTE 259M Video" },
	{ GIO_PRODUCT_BABBLE, "Babblefish Compression" },
	{ GIO_PRODUCT_IMPACT, "Impact" },
	{ GIO_PRODUCT_PHOBOS_G160, "Phobos G160 10/100 Ethernet" },
	{ GIO_PRODUCT_PHOBOS_G130, "Phobos G130 10/100 Ethernet" },
	{ GIO_PRODUCT_PHOBOS_G100, "Phobos G100 100baseTX Fast Ethernet" },
	{ 0, NULL }
};


code:
/*	$OpenBSD: gioreg.h,v 1.4 2014/07/02 17:44:35 miod Exp $	*/
/*	$NetBSD: gioreg.h,v 1.4 2006/08/31 00:01:10 rumble 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>>
 */

/*
 * The GIO Product Identification Word is the first word (1 or 4 bytes)
 * in each GIO device's address space. It is the same format for GIO32,
 * GIO32-bis, and GIO64 devices. The macros below extract the following
 * fields:
 *
 * Bits:
 *    0-6 Product ID Code
 *	7 Product Identification Word size (0: 8 bits, 1: 32 bits)
 *   8-15 Product Revision
 *     16 GIO Interface Size (0: 32, 1: 64; NB: GIO64 devices may be 32)
 *     17 Rom Present (1: present)
 *  18-31 Manufacturer-specific Code
 *
 * The upper three bytes containing the Product Revision, GIO Interface
 * Size, Rom Presence indicator, and Manufacturer-specific Code are only
 * valid if bit 7 is set in the Product ID Word. If it is not set, all
 * values default to 0.
 *
 * If the Rom Present bit is set, the three words after the Product ID are
 * reserved for three ROM registers:
 *	Board Serial Number Register	(base_address + 0x4)
 *	ROM Index Register		(base_address + 0x8)
 *	ROM Read Register		(base_address + 0xc)
 *
 * The ROM Index Register is initialised by the CPU to 0 and incremented by
 * 4 on each read from the ROM Read Register. The Board Serial Number
 * Register contains a manufacturer-specific serial number.
 */

#define GIO_PRODUCT_32BIT_ID(x)		((x) & 0x80)
#define GIO_PRODUCT_PRODUCTID(x)	((x) & 0x7f)
#define GIO_PRODUCT_REVISION(x)		(((x) >> 8) & 0xff)
#define GIO_PRODUCT_IS_64BIT(x)		(!!((x) & 0x10000))
#define GIO_PRODUCT_HAS_ROM(x)		(!!((x) & 0x20000))
#define GIO_PRODUCT_MANUCODE(x)		((x) >> 18)

#define	GIO_ADDR_GFX			0x1f000000	/* 4MB */
#define	GIO_ADDR_EXP0			0x1f400000	/* 2MB */
#define	GIO_ADDR_EXP1			0x1f600000	/* 4MB */
#define	GIO_ADDR_END			0x1fa00000

#define	IS_GIO_ADDRESS(pa)	((pa) >= GIO_ADDR_GFX && (pa) < GIO_ADDR_END)


code:
/*	$OpenBSD: giovar.h,v 1.4 2012/05/17 19:46:52 miod Exp $	*/
/*	$NetBSD: giovar.h,v 1.10 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2000 Soren S. Jorvang
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *          This product includes software developed for the
 *          NetBSD Project.  See http://www.NetBSD.org/ for
 *          information about NetBSD.
 * 4. 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.
 */

/*
 * GIO 32/32-bis/64 bus
 */

struct gio_attach_args {
	bus_space_tag_t		 ga_iot;
	bus_space_handle_t	 ga_ioh;
	bus_dma_tag_t		 ga_dmat;

	int			 ga_slot;	/* -1 if graphics */
	u_int64_t		 ga_addr;

	u_int32_t		 ga_product;	/* not valid if graphics */
	const char		*ga_descr;	/* only valid if graphics */
};

#define GIO_SLOT_GFX		0
#define GIO_SLOT_EXP0		1
#define GIO_SLOT_EXP1		2

#define GIO_ARB_RT		0x001	/* real-time device */
#define GIO_ARB_LB		0x002	/* long-burst device */

#define GIO_ARB_MST		0x004	/* bus master enable */
#define GIO_ARB_SLV		0x008	/* slave */

#define GIO_ARB_PIPE		0x010	/* pipelining enable */
#define GIO_ARB_NOPIPE		0x020	/* pipelining disable */

#define GIO_ARB_32BIT		0x040	/* 32-bit transfers */
#define GIO_ARB_64BIT		0x080	/* 64-bit transfers */

#define GIO_ARB_HPC2_32BIT	0x100	/* 32-bit secondary HPC (ignores slot)*/
#define GIO_ARB_HPC2_64BIT	0x200	/* 64-bit secondary HPC (ignores slot)*/

/*
 * Maximum number of graphics boards installed. The known limit is 2,
 * but we're allowing room for some surprises.
 */
#define	GIO_MAX_FB		3

int		gio_arb_config(int, uint32_t);
int		gio_intr_map(int);
void	       *gio_intr_establish(int, int, int (*)(void *), void *,
		    const char *);
const char     *gio_product_string(int);

int		giofb_cnattach(void);
int		giofb_cnprobe(void);

extern paddr_t	giofb_consaddr;
extern const char *giofb_names[GIO_MAX_FB];

/*
 * Fake GIO device IDs to identify frame buffers without GIO IDs.
 * These are built as 32-bit GIO IDs without the `32-bit ID' bit set.
 */

#define	GIO_PRODUCT_FAKEID_LIGHT	0xff010000
#define	GIO_PRODUCT_FAKEID_NEWPORT	0xff020000
#define	GIO_PRODUCT_FAKEID_GRTWO	0xff030000


code:
/*	$OpenBSD: grtwo.c,v 1.11 2014/12/09 06:58:29 doug Exp $	*/
/* $NetBSD: grtwo.c,v 1.11 2009/11/22 19:09:15 mbalmer 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) 2004 Christopher SEKIYA
 * 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>>
 */

/* wscons driver for SGI GR2 family of framebuffers
 *
 * Heavily based on the newport wscons driver.
 */

/*
 * GR2 coordinates start from (0,0) in the lower left corner, to (1279,1023)
 * in the upper right. The low-level drawing routines will take care of
 * converting the traditional ``y goes down'' coordinates to those expected
 * by the hardware.
 */

#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/grtworeg.h>
#include <dev/ic/bt458reg.h>
#include <sgi/gio/grtwovar.h>
#include <sgi/localbus/intreg.h>
#include <sgi/localbus/intvar.h>

#include <dev/cons.h>

#define	GRTWO_WIDTH	1280
#define	GRTWO_HEIGHT	1024

struct grtwo_softc {
	struct device		sc_dev;

	struct grtwo_devconfig *sc_dc;

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

struct grtwo_devconfig {
	struct rasops_info		dc_ri;
	long				dc_defattr;
	struct wsdisplay_charcell	*dc_bs;

	uint32_t			dc_addr;
	bus_space_tag_t			iot;
	bus_space_handle_t		ioh;

	uint32_t			xmapmode;

	uint8_t				boardrev;
	uint8_t				backendrev;
	int				hq2rev;
	int				ge7rev;
	int				vc1rev;
	int				zbuffer;
	int				depth;
	int				monitor;

	struct grtwo_softc		*dc_sc;
	struct wsscreen_descr		dc_wsd;
};

int	grtwo_match(struct device *, void *, void *);
void	grtwo_attach(struct device *, struct device *, void *);

struct cfdriver grtwo_cd = {
	NULL, "grtwo", DV_DULL
};

const struct cfattach grtwo_ca = {
	sizeof(struct grtwo_softc), grtwo_match, grtwo_attach
};

/* accessops */
int	grtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t	grtwo_mmap(void *, off_t, int);
int	grtwo_alloc_screen(void *, const struct wsscreen_descr *, void **,
	    int *, int *, long *);
void	grtwo_free_screen(void *, void *);
int	grtwo_show_screen(void *, void *, int, void (*)(void *, int, int),
	    void *);
int	grtwo_load_font(void *, void *, struct wsdisplay_font *);
int	grtwo_list_font(void *, struct wsdisplay_font *);
void	grtwo_burner(void *, u_int, u_int);

static struct wsdisplay_accessops grtwo_accessops = {
	.ioctl = grtwo_ioctl,
	.mmap = grtwo_mmap,
	.alloc_screen = grtwo_alloc_screen,
	.free_screen = grtwo_free_screen,
	.show_screen = grtwo_show_screen,
	.load_font = grtwo_load_font,
	.list_font = grtwo_list_font,
	.burn_screen = grtwo_burner
};

int	grtwo_cursor(void *, int, int, int);
int	grtwo_putchar(void *, int, int, u_int, long);
int	grtwo_copycols(void *, int, int, int, int);
int	grtwo_erasecols(void *, int, int, int, long);
int	grtwo_copyrows(void *, int, int, int);
int	grtwo_eraserows(void *, int, int, long);

void	grtwo_wait_gfifo(struct grtwo_devconfig *);
static __inline__
void	grtwo_set_color(bus_space_tag_t, bus_space_handle_t, int);
void	grtwo_fillrect(struct grtwo_devconfig *, int, int, int, int, int);
void	grtwo_copyrect(struct grtwo_devconfig *, int, int, int, int, int, int);
int	grtwo_setup_hw(struct grtwo_devconfig *);
static __inline__
int	grtwo_attach_common(struct grtwo_devconfig *, struct gio_attach_args *);
int	grtwo_init_screen(struct grtwo_devconfig *, int);
int	grtwo_putchar_internal(struct rasops_info *, int, int, u_int, int, int,
	    int);

static struct grtwo_devconfig grtwo_console_dc;
/* console backing store, worst cast font selection */
static struct wsdisplay_charcell
	grtwo_console_bs[(GRTWO_WIDTH / 8) * (GRTWO_HEIGHT / 16)];

void
grtwo_wait_gfifo(struct grtwo_devconfig *dc)
{
	int i;

	/*
	 * This loop is for paranoia. Of course there is currently no
	 * known way to whack the FIFO (or reset the board) in case it
	 * gets stuck... but this code is careful to avoid this situation
	 * and it should never happen (famous last words)
	 */
	for (i = 100000; i != 0; i--) {
		if (!int2_is_intr_pending(INT2_L0_FIFO))
			break;
		delay(1);
	}
#ifdef DIAGNOSTIC
	if (i == 0) {
		if (dc != &grtwo_console_dc && dc->dc_sc != NULL)
			printf("%s: FIFO is stuck\n",
			    dc->dc_sc->sc_dev.dv_xname);
	}
#endif
}

static __inline__ void
grtwo_set_color(bus_space_tag_t iot, bus_space_handle_t ioh, int color)
{
	bus_space_write_4(iot, ioh, GR2_FIFO_COLOR, color);
}

/*
 * Rectangle fill with the given background.
 */
void
grtwo_fillrect(struct grtwo_devconfig *dc, int x1, int y1, int x2,
    int y2, int bg)
{
	grtwo_wait_gfifo(dc);
	grtwo_set_color(dc->iot, dc->ioh, bg);

	grtwo_wait_gfifo(dc);
	bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_RECTI2D, x1);
	bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA,
	    GRTWO_HEIGHT - 1 - y1);
	bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, x2);
	bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA,
	    GRTWO_HEIGHT - 1 - y2);
}

/*
 * Rectangle copy.
 * Does not handle overlapping copies; this is handled at the wsdisplay
 * emulops level by splitting overlapping copies in smaller, non-overlapping,
 * operations.
 */
void
grtwo_copyrect(struct grtwo_devconfig *dc, int x1, int y1, int x2,
    int y2, int width, int height)
{
	int length = (width + 3) >> 2;
	int lines = 4864 / length;
	int step;

	y1 += height; y2 += height;
	while (height != 0) {
		step = imin(height, lines);
		y1 -= step; y2 -= step;

		grtwo_wait_gfifo(dc);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_RECTCOPY, length);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, lines);
		/* source */
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, x1);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, y1);
		/* span */
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, width);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, step);
		/* dest */
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, x2);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, y2);

		height -= step;
	}
}

int
grtwo_setup_hw(struct grtwo_devconfig *dc)
{
	int i = 0;
	uint8_t rd0, rd1, rd2, rd3;
	uint32_t vc1;

	rd0 = bus_space_read_1(dc->iot, dc->ioh, GR2_REVISION_RD0);
	rd1 = bus_space_read_1(dc->iot, dc->ioh, GR2_REVISION_RD1);
	rd2 = bus_space_read_1(dc->iot, dc->ioh, GR2_REVISION_RD2);
	rd3 = bus_space_read_1(dc->iot, dc->ioh, GR2_REVISION_RD3);

	/* Get various revisions */
	dc->boardrev = ~rd0 & GR2_REVISION_RD0_VERSION_MASK;

	/*
	 * Boards prior to rev 4 have a pretty whacky config scheme.
	 * What is doubly weird is that i have a rev 2 board, but the rev 4
	 * probe routines work just fine.
	 * We'll trust SGI, though, and separate things a bit. It's only
	 * critical for the display depth calculation.
	 */

	if (dc->boardrev < 4) {
		dc->backendrev = ~(rd2 & GR2_REVISION_RD2_BACKEND_REV) >>
		    GR2_REVISION_RD2_BACKEND_SHIFT;
		if (dc->backendrev == 0)
			return ENXIO;
		dc->zbuffer = ~rd1 & GR2_REVISION_RD1_ZBUFFER;
		if ((rd3 & GR2_REVISION_RD3_VMA) != GR2_REVISION_RD3_VMA)
			i++;
		if ((rd3 & GR2_REVISION_RD3_VMB) != GR2_REVISION_RD3_VMB)
			i++;
		if ((rd3 & GR2_REVISION_RD3_VMC) != GR2_REVISION_RD3_VMC)
			i++;
		dc->depth = 8 * i;
		dc->monitor = ((rd2 & 0x03) << 1) | (rd1 & 0x01);
	} else {
		dc->backendrev = ~rd1 & GR2_REVISION4_RD1_BACKEND;
		if (dc->backendrev == 0)
			return ENXIO;
		dc->zbuffer = rd1 & GR2_REVISION4_RD1_ZBUFFER;
		dc->depth = (rd1 & GR2_REVISION4_RD1_24BPP) ? 24 : 8;
		dc->monitor = (rd0 & GR2_REVISION4_RD0_MONITOR_MASK) >>
		    GR2_REVISION4_RD0_MONITOR_SHIFT;
	}

	dc->hq2rev = (bus_space_read_4(dc->iot, dc->ioh, HQ2_VERSION) &
	    HQ2_VERSION_MASK) >> HQ2_VERSION_SHIFT;
	dc->ge7rev = (bus_space_read_4(dc->iot, dc->ioh, GE7_REVISION) &
	    GE7_REVISION_MASK) >> GE7_REVISION_SHIFT;
	/* dc->vc1rev = vc1_read_ireg(dc, 5) & 0x07; */

	vc1 = bus_space_read_4(dc->iot, dc->ioh, VC1_SYSCTL);
	if (vc1 == -1)
		return ENXIO;	/* XXX would need a reset */

	/* Turn on display, DID, disable cursor display */
	bus_space_write_4(dc->iot, dc->ioh, VC1_SYSCTL,
	    VC1_SYSCTL_VC1 | VC1_SYSCTL_DID);

	dc->xmapmode = bus_space_read_4(dc->iot, dc->ioh,
	    XMAP5_BASEALL + XMAP5_MODE);

	/*
	 * Setup Bt457 RAMDACs
	 */
	/* enable all planes */
	bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_CTRL, 0xff);
	bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_CTRL, 0xff);
	bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_CTRL, 0xff);
	/* setup a regular gamma ramp */
	bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_ADDR, 0);
	bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_ADDR, 0);
	bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_ADDR, 0);
	for (i = 0; i < 256; i++) {
		bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_CMAPDATA,
		    i);
		bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_CMAPDATA,
		    i);
		bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_CMAPDATA,
		    i);
	}

	/*
	 * Setup Bt479 RAMDAC
	 */
	grtwo_wait_gfifo(dc);
	bus_space_write_1(dc->iot, dc->ioh, XMAP5_BASEALL + XMAP5_ADDRHI,
	    GR2_CMAP8 >> 8);
	bus_space_write_1(dc->iot, dc->ioh, XMAP5_BASEALL + XMAP5_ADDRLO,
	    GR2_CMAP8 & 0xff);
	bus_space_write_multi_1(dc->iot, dc->ioh, XMAP5_BASEALL + XMAP5_CLUT,
	    rasops_cmap, sizeof(rasops_cmap));

	return 0;
}

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

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

	return 1;
}

void
grtwo_attach(struct device *parent, struct device *self, void *aux)
{
	struct grtwo_softc *sc = (struct grtwo_softc *)self;
	struct gio_attach_args *ga = aux;
	struct grtwo_devconfig *dc;
	struct wsemuldisplaydev_attach_args waa;
	const char *descr;
	extern struct consdev wsdisplay_cons;

	descr = ga->ga_descr;
	if (descr == NULL || *descr == '\0')
		descr = "GR2";
	printf(": %s", descr);

	if (cn_tab == &wsdisplay_cons &&
	    ga->ga_addr == grtwo_console_dc.dc_addr) {
		waa.console = 1;
		dc = &grtwo_console_dc;
		sc->sc_nscreens = 1;
	} else {
		/*
		 * XXX The driver will not work correctly if we are not the
		 * XXX console device. An initialization is missing - it
		 * XXX seems that everything works, but the colormap is
		 * XXX stuck as black, which makes the device unusable.
		 */
		printf("\n%s: device has not been setup by firmware!\n",
		    self->dv_xname);
		return;
#if 0
		waa.console = 0;
		dc = malloc(sizeof(struct grtwo_devconfig),
		    M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
		if (dc == NULL)
			goto out;
		if (grtwo_attach_common(dc, ga) != 0) {
			printf("\n%s: not responding\n", self->dv_xname);
			free(dc, M_DEVBUF, 0);
			return;
		}
		if (grtwo_init_screen(dc, M_WAITOK | M_CANFAIL) != 0) {
			free(dc, M_DEVBUF, 0);
			goto out;
		}
#endif
	}
	sc->sc_dc = dc;
	dc->dc_sc = sc;

	printf(", revision %d, monitor sense %d\n", dc->boardrev, dc->monitor);
	printf("%s: %dx%d %d-bit frame buffer\n",
	    self->dv_xname, GRTWO_WIDTH, GRTWO_HEIGHT, dc->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 = &grtwo_accessops;
	waa.accesscookie = dc;
	waa.defaultscreens = 0;

	config_found(self, &waa, wsemuldisplaydevprint);
	return;

#if 0
out:
	printf("\n%s: failed to allocate memory\n", self->dv_xname);
	return;
#endif
}

int
grtwo_cnprobe(struct gio_attach_args *ga)
{
	return grtwo_match(NULL, NULL, ga);
}

int
grtwo_cnattach(struct gio_attach_args *ga)
{
	struct rasops_info *ri = &grtwo_console_dc.dc_ri;
	struct wsdisplay_charcell *cell;
	long defattr;
	int rc;
	int i;

	rc = grtwo_attach_common(&grtwo_console_dc, ga);
	if (rc != 0)
		return rc;
	grtwo_console_dc.dc_bs = grtwo_console_bs;
	rc = grtwo_init_screen(&grtwo_console_dc, M_NOWAIT);
	if (rc != 0)
		return rc;

	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
	cell = grtwo_console_bs;
	for (i = ri->ri_cols * ri->ri_rows; i != 0; i--, cell++)
		cell->attr = defattr;

	wsdisplay_cnattach(&grtwo_console_dc.dc_wsd, ri, 0, 0, defattr);

	return 0;
}

static __inline__ int
grtwo_attach_common(struct grtwo_devconfig *dc, struct gio_attach_args * ga)
{
	dc->dc_addr = ga->ga_addr;
	dc->iot = ga->ga_iot;
	dc->ioh = ga->ga_ioh;

	return grtwo_setup_hw(dc);
}

int
grtwo_init_screen(struct grtwo_devconfig *dc, int malloc_flags)
{
	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 = GRTWO_WIDTH;
	ri->ri_width = GRTWO_WIDTH;
	ri->ri_height = GRTWO_HEIGHT;
	rasops_init(ri, 160, 160);

	/*
	 * Allocate backing store to remember character cells, to
	 * be able to paint an inverted cursor.
	 */
	if (dc->dc_bs == NULL) {
		dc->dc_bs = mallocarray(ri->ri_rows, ri->ri_cols *
		    sizeof(struct wsdisplay_charcell), M_DEVBUF,
		    malloc_flags | M_ZERO);
		if (dc->dc_bs == NULL)
			return ENOMEM;
	}

	ri->ri_ops.cursor = grtwo_cursor;
	ri->ri_ops.copyrows = grtwo_copyrows;
	ri->ri_ops.eraserows = grtwo_eraserows;
	ri->ri_ops.copycols = grtwo_copycols;
	ri->ri_ops.erasecols = grtwo_erasecols;
	ri->ri_ops.putchar = grtwo_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;

	grtwo_fillrect(dc, 0, 0, GRTWO_WIDTH - 1, GRTWO_HEIGHT - 1,
	    ri->ri_devcmap[WSCOL_BLACK]);

	return 0;
}

/* wsdisplay textops */

int
grtwo_cursor(void *c, int on, int row, int col)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_charcell *cell;
	int bg, fg, ul;

	cell = dc->dc_bs + row * ri->ri_cols + col;
	ri->ri_ops.unpack_attr(ri, cell->attr, &fg, &bg, &ul);

	if (on) {
		/* redraw the existing character with inverted colors */
		return grtwo_putchar_internal(ri, row, col, cell->uc,
		    ~ri->ri_devcmap[fg], ~ri->ri_devcmap[bg], ul);
	} else {
		/* redraw the existing character with correct colors */
		return grtwo_putchar_internal(ri, row, col, cell->uc,
		    ri->ri_devcmap[fg], ri->ri_devcmap[bg], ul);
	}
}

int
grtwo_putchar(void *c, int row, int col, u_int ch, long attr)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_charcell *cell;
	int bg, fg, ul;

	/* Update backing store. */
	cell = dc->dc_bs + row * ri->ri_cols + col;
	cell->uc = ch;
	cell->attr = attr;

	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);
	return grtwo_putchar_internal(ri, row, col, ch, ri->ri_devcmap[fg],
	    ri->ri_devcmap[bg], ul);
}

int
grtwo_putchar_internal(struct rasops_info *ri, int row, int col, u_int ch,
    int fg, int bg, int ul)
{
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	uint8_t *bitmap;
	uint32_t pattern;
	int x, y;
	int h = font->fontheight;
	int w = font->fontwidth;
	int i;

	/*
	 * The `draw char' operation below writes on top of the existing
	 * background. We need to paint the background first.
	 */
	x = ri->ri_xorigin + col * w;
	y = ri->ri_yorigin + row * h;
	grtwo_fillrect(dc, x, y, x + w - 1, y + h - 1, bg);

	if ((ch == ' ' || ch == 0) && ul == 0)
		return 0;

	/* Set the drawing color */
	grtwo_wait_gfifo(dc);
	grtwo_set_color(dc->iot, dc->ioh, fg);

	/*
	 * This character drawing operation apparently expects a 18 pixel
	 * character cell height. We will perform as many cell fillings as
	 * necessary to draw a complete glyph.
	 */
	bitmap = (uint8_t *)font->data +
	    (ch - font->firstchar + 1) * ri->ri_fontscale;
	y = ri->ri_height - h - y;
	while (h != 0) {
		/* Set drawing coordinates */
		grtwo_wait_gfifo(dc);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_CMOV2I, x);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, y);

		grtwo_wait_gfifo(dc);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DRAWCHAR, w);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA,
		    h > GR2_DRAWCHAR_HEIGHT ? GR2_DRAWCHAR_HEIGHT : h);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, 2);
		/* (x,y) offset */
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, 0);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, 0);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, 0);
		bus_space_write_4(dc->iot, dc->ioh, GR2_FIFO_DATA, 0);

		grtwo_wait_gfifo(dc);
		if (w <= 8) {
			for (i = 0; i < GR2_DRAWCHAR_HEIGHT; i++) {
				if (h != 0) {
					bitmap -= font->stride;
					if (ul && h == font->fontheight - 1)
						pattern = 0xff << 8;
					else
						pattern = *bitmap << 8;
					h--;
				} else
					pattern = 0;

				bus_space_write_4(dc->iot, dc->ioh,
				    GR2_FIFO_DATA, pattern);
			}
		} else {
			for (i = 0; i < GR2_DRAWCHAR_HEIGHT; i++) {
				if (h != 0) {
					bitmap -= font->stride;
					if (ul && h == font->fontheight - 1)
						pattern = 0xffff;
					else
						pattern = *(uint16_t *)bitmap;
					h--;
				} else
					pattern = 0;

				bus_space_write_4(dc->iot, dc->ioh,
				    GR2_FIFO_DATA, pattern);
			}
		}

		y += GR2_DRAWCHAR_HEIGHT;
	}

	return 0;
}

int
grtwo_copycols(void *c, int row, int src, int dst, int ncol)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	struct wsdisplay_charcell *cell;
	int y = ri->ri_yorigin + row * font->fontheight;
	int delta, chunk;

	/* Copy columns in backing store. */
	cell = dc->dc_bs + row * ri->ri_cols;
	memmove(cell + dst, cell + src, ncol * sizeof(*cell));

	if (src > dst) {
		/* may overlap, copy in non-overlapping blocks */
		delta = src - dst;
		while (ncol > 0) {
			chunk = ncol <= delta ? ncol : delta;
			grtwo_copyrect(dc,
			    ri->ri_xorigin + src * font->fontwidth, y,
			    ri->ri_xorigin + dst * font->fontwidth, y,
			    chunk * font->fontwidth, font->fontheight);
			src += chunk;
			dst += chunk;
			ncol -= chunk;
		}
	} else {
		grtwo_copyrect(dc,
		    ri->ri_xorigin + src * font->fontwidth, y,
		    ri->ri_xorigin + dst * font->fontwidth, y,
		    ncol * font->fontwidth, font->fontheight);
	}

	return 0;
}

int
grtwo_erasecols(void *c, int row, int startcol, int ncol, long attr)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	struct wsdisplay_charcell *cell;
	int y = ri->ri_yorigin + row * font->fontheight;
	int i, bg, fg;

	/* Erase columns in backing store. */
	cell = dc->dc_bs + row * ri->ri_cols + startcol;
	for (i = ncol; i != 0; i--, cell++) {
		cell->uc = 0;
		cell->attr = attr;
	}

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

	grtwo_fillrect(dc, ri->ri_xorigin + startcol * font->fontwidth, y,
	    ri->ri_xorigin + (startcol + ncol) * font->fontwidth - 1,
	    y + font->fontheight - 1, ri->ri_devcmap[bg]);

	return 0;
}

int
grtwo_copyrows(void *c, int src, int dst, int nrow)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	struct wsdisplay_charcell *cell;
	int delta, chunk;

	/* Copy rows in backing store. */
	cell = dc->dc_bs + dst * ri->ri_cols;
	memmove(cell, dc->dc_bs + src * ri->ri_cols,
	    nrow * ri->ri_cols * sizeof(*cell));

	if (src > dst) {
		/* may overlap, copy in non-overlapping blocks */
		delta = src - dst;
		while (nrow > 0) {
			chunk = nrow <= delta ? nrow : delta;
			grtwo_copyrect(dc, ri->ri_xorigin,
			    ri->ri_yorigin + src * font->fontheight,
			    ri->ri_xorigin,
			    ri->ri_yorigin + dst * font->fontheight,
			    ri->ri_emuwidth, chunk * font->fontheight);
			src += chunk;
			dst += chunk;
			nrow -= chunk;
		}
	} else {
		grtwo_copyrect(dc, ri->ri_xorigin,
		    ri->ri_yorigin + src * font->fontheight, ri->ri_xorigin,
		    ri->ri_yorigin + dst * font->fontheight, ri->ri_emuwidth,
		    nrow * font->fontheight);
	}

	return 0;
}

int
grtwo_eraserows(void *c, int startrow, int nrow, long attr)
{
	struct rasops_info *ri = c;
	struct grtwo_devconfig *dc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	struct wsdisplay_charcell *cell;
	int i, bg, fg;

	/* Erase rows in backing store. */
	cell = dc->dc_bs + startrow * ri->ri_cols;
	for (i = ri->ri_cols; i != 0; i--, cell++) {
		cell->uc = 0;
		cell->attr = attr;
	}
	for (i = 1; i < nrow; i++)
		memmove(dc->dc_bs + (startrow + i) * ri->ri_cols,
		    dc->dc_bs + startrow * ri->ri_cols,
		    ri->ri_cols * sizeof(*cell));

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

	if (nrow == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) {
		grtwo_fillrect(dc, 0, 0, GRTWO_WIDTH - 1, GRTWO_HEIGHT - 1,
		    ri->ri_devcmap[bg]);
		return 0;
	}

	grtwo_fillrect(dc, ri->ri_xorigin,
	    ri->ri_yorigin + startrow * font->fontheight,
	    ri->ri_xorigin + ri->ri_emuwidth - 1,
	    ri->ri_yorigin + (startrow + nrow) * font->fontheight - 1,
	    ri->ri_devcmap[bg]);

	return 0;
}

/* wsdisplay accessops */

int
grtwo_alloc_screen(void *v, const struct wsscreen_descr * type, void **cookiep,
    int *curxp, int *curyp, long *attrp)
{
	struct grtwo_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;
	struct grtwo_softc *sc = dc->dc_sc;
	struct wsdisplay_charcell *cell;
	int i;

	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;

	cell = dc->dc_bs;
	for (i = ri->ri_cols * ri->ri_rows; i != 0; i--, cell++)
		cell->attr = dc->dc_defattr;

	return 0;
}

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

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

int
grtwo_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct grtwo_devconfig *dc = v;
	struct rasops_info *ri = &dc->dc_ri;
	struct wsdisplay_fbinfo *fb;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *) data = WSDISPLAY_TYPE_GRTWO;
		break;
	case WSDISPLAYIO_GINFO:
		fb = (struct wsdisplay_fbinfo *)data;
		fb->width = ri->ri_width;
		fb->height = ri->ri_height;
		fb->depth = dc->depth;		/* real depth */
		if (dc->depth > 8)
			fb->cmsize = 0;
		else
			fb->cmsize = 1 << dc->depth;
		break;
	default:
		return -1;
	}

	return 0;
}

paddr_t
grtwo_mmap(void *v, off_t offset, int prot)
{
	/* no directly accessible frame buffer memory */
	return -1;
}

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

	return rasops_load_font(ri, emulcookie, font);
}

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

	return rasops_list_font(ri, font);
}

void
grtwo_burner(void *v, u_int on, u_int flags)
{
	struct grtwo_devconfig *dc = v;

	on = on ? 0xff : 0x00;

	bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_R + BT457_CTRL, on);
	bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_G + BT457_CTRL, on);
	bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_ADDR, BT_RMR);
	bus_space_write_1(dc->iot, dc->ioh, BT457_B + BT457_CTRL, on);
}


code:
/*	$OpenBSD: grtworeg.h,v 1.3 2014/03/27 20:15:00 miod Exp $	*/
/* $NetBSD: grtworeg.h,v 1.2 2005/12/11 12:18:53 christos Exp $	 */

/*
 * Copyright (c) 2004 Christopher SEKIYA
 * 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>>
 */

/*
 * Memory map:
 *
 * 0x1f000000 - 0x1f01ffff	Shared data RAM
 * 0x1f020000 - 0x1f03ffff	(unused)
 * 0x1f040000 - 0x1f05ffff	FIFO
 * 0x1f060000 - 0x1f068000	HQ2 ucode
 * 0x1f068000 - 0x1f069fff	GE7 (eight of them)
 * 0x1f06a000 - 0x1f06b004	HQ2
 * 0x1f06c000			Board revision register
 * 0x1f06c020			clock
 * 0x1f06c040			VC1
 * 0x1f06c060			BT479 Triple-DAC (read)
 * 0x1f06c080			BT479 Triple-DAC (write)
 * 0x1f06c0a0			BT457 DAC (red)
 * 0x1f06c0c0			BT457 DAC (green)
 * 0x1f06c0e0			BT457 DAC (blue)
 * 0x1f06c100			XMAP5 (five of them)
 * 0x1f06c1a0			XMAP5 ("xmap all")
 * 0x1f06c1c0			Kaleidoscope (AB1)
 * 0x1f06c1e0			Kaleidoscope (CC1)
 * 0x1f06c200			RE3 (27-bit registers)
 * 0x1f06c280			RE3 (24-bit registers)
 * 0x1f06c600			RE3 (32-bit registers)
 */

#define GR2_FIFO			0x40000
#define GR2_FIFO_INIT			(GR2_FIFO + 0x644)
#define GR2_FIFO_COLOR               	(GR2_FIFO + 0x648)
#define GR2_FIFO_FINISH              	(GR2_FIFO + 0x64c)
#define GR2_FIFO_PNT2I               	(GR2_FIFO + 0x650)
#define GR2_FIFO_RECTI2D             	(GR2_FIFO + 0x654)
#define GR2_FIFO_CMOV2I              	(GR2_FIFO + 0x658)
#define GR2_FIFO_LINE2I              	(GR2_FIFO + 0x65c)
#define GR2_FIFO_DRAWCHAR            	(GR2_FIFO + 0x660)
#define GR2_FIFO_RECTCOPY            	(GR2_FIFO + 0x664)
#define GR2_FIFO_DATA			(GR2_FIFO + 0x77c)

/* HQ2 */

#define	HQ2_BASE			0x6a000
#define	HQ2_ATTRJUMP			(HQ2_BASE + 0x00)
#define HQ2_VERSION			(HQ2_BASE + 0x40)
#define HQ2_VERSION_MASK		0xff000000
#define HQ2_VERSION_SHIFT		23

#define HQ2_NUMGE			(HQ2_BASE + 0x44)
#define HQ2_FIN1			(HQ2_BASE + 0x48)
#define HQ2_FIN2			(HQ2_BASE + 0x4c)
#define HQ2_DMASYNC			(HQ2_BASE + 0x50)
#define HQ2_FIFO_FULL_TIMEOUT		(HQ2_BASE + 0x54)
#define HQ2_FIFO_EMPTY_TIMEOUT		(HQ2_BASE + 0x58)
#define HQ2_FIFO_FULL			(HQ2_BASE + 0x5c)
#define HQ2_FIFO_EMPTY			(HQ2_BASE + 0x60)
#define HQ2_GE7_LOAD_UCODE		(HQ2_BASE + 0x64)
#define HQ2_GEDMA			(HQ2_BASE + 0x68)
#define HQ2_HQ_GEPC			(HQ2_BASE + 0x6c)
#define HQ2_GEPC			(HQ2_BASE + 0x70)
#define HQ2_INTR			(HQ2_BASE + 0x74)
#define HQ2_UNSTALL			(HQ2_BASE + 0x78)
#define HQ2_MYSTERY			(HQ2_BASE + 0x7c)
#define	HQ2_MYSTERY_VALUE		0xdeadbeef
#define HQ2_REFRESH			(HQ2_BASE + 0x80)
#define HQ2_FIN3			(HQ2_BASE + 0x1000)

/* GE7 */

#define GE7_REVISION			0x680fc
#define GE7_REVISION_MASK		0xe0
#define	GE7_REVISION_SHIFT		5

/* VC1 */

#define VC1_BASE			0x6c040
#define VC1_COMMAND			(VC1_BASE + 0x00)
#define VC1_XMAPMODE			(VC1_BASE + 0x04)
#define VC1_SRAM			(VC1_BASE + 0x08)
#define VC1_TESTREG			(VC1_BASE + 0x0c)
#define VC1_ADDRLO			(VC1_BASE + 0x10)
#define VC1_ADDRHI			(VC1_BASE + 0x14)
#define VC1_SYSCTL			(VC1_BASE + 0x18)

/* VC1 System Control Register */
#define VC1_SYSCTL_INTERRUPT		0x01	/* active low */
#define VC1_SYSCTL_VTG			0x02	/* active low */
#define VC1_SYSCTL_VC1			0x04
#define VC1_SYSCTL_DID			0x08
#define VC1_SYSCTL_CURSOR		0x10
#define VC1_SYSCTL_CURSOR_DISPLAY	0x20
#define VC1_SYSCTL_GENSYNC		0x40
#define VC1_SYSCTL_VIDEO		0x80

/* VC1 SRAM memory map */
#define VC1_SRAM_VIDTIM_LST_BASE	0x0000
#define VC1_SRAM_VIDTIM_CURSLST_BASE	0x0400
#define VC1_SRAM_VIDTIM_FRMT_BASE	0x0800
#define VC1_SRAM_VIDTIM_CURSFRMT_BASE	0x0900
#define VC1_SRAM_INTERLACED		0x09f0
#define VC1_SRAM_SCREENWIDTH		0x09f2
#define VC1_SRAM_NEXTDID_ADDR		0x09f4
#define VC1_SRAM_CURSOR0_BASE		0x0a00	/* 32x32 */
#define VC1_SRAM_DID_FRMT_BASE		0x0b00
#define VC1_SRAM_DID_MAX_FMTSIZE	0x0900
#define VC1_SRAM_DID_LST_END		0x8000

/* VC1 registers */
#define VC1_VIDEO_EP			0x00
#define VC1_VIDEO_LC			0x02
#define VC1_VIDEO_SC			0x04
#define VC1_VIDEO_TSA			0x06
#define VC1_VIDEO_TSB			0x07
#define VC1_VIDEO_TSC			0x08
#define VC1_VIDEO_LP			0x09
#define VC1_VIDEO_LS_EP			0x0b
#define VC1_VIDEO_LR			0x0d
#define VC1_VIDEO_FC			0x10
#define VC1_VIDEO_ENABLE		0x14

/* Cursor Generator */
#define VC1_CURSOR_EP			0x20
#define VC1_CURSOR_XL			0x22
#define VC1_CURSOR_YL			0x24
#define VC1_CURSOR_MODE			0x26
#define VC1_CURSOR_BX			0x27
#define VC1_CURSOR_LY			0x28
#define VC1_CURSOR_YC			0x2a
#define VC1_CURSOR_CC			0x2e
#define VC1_CURSOR_RC			0x30

/* Board revision register */

#define	GR2_REVISION			0x6c000
#define GR2_REVISION_RD0		0x6c000
#define GR2_REVISION_RD0_VERSION_MASK	0x0f
#define GR2_REVISION4_RD0_MONITOR_MASK	0xf0
#define GR2_REVISION4_RD0_MONITOR_SHIFT	4

#define GR2_REVISION_RD1		0x6c004
#define GR2_REVISION_RD1_BACKEND_REV	0x03
#define GR2_REVISION_RD1_ZBUFFER	0x0c

#define GR2_REVISION4_RD1_BACKEND	0x03
#define GR2_REVISION4_RD1_24BPP		0x10
#define GR2_REVISION4_RD1_ZBUFFER	0x20

#define GR2_REVISION_RD2		0x6c008
#define GR2_REVISION_RD2_BACKEND_REV	0x0c
#define GR2_REVISION_RD2_BACKEND_SHIFT	2

/* one slot = 8bpp, two slots = 16bpp, three slots = 24bpp, br < 4 only */
#define GR2_REVISION_RD3		0x6c00c
#define GR2_REVISION_RD3_VMA		0x03	/* both bits set == empty
						 * slot */
#define GR2_REVISION_RD3_VMB		0x0c
#define GR2_REVISION_RD3_VMC		0x30

/* Bt479 */

#define	BT479_R			0x6c060
#define	BT479_W			0x6c080

#define	BT479_WRADDR			0x00
#define	BT479_CMAPDATA			0x04
#define	BT479_MASK			0x08	/* pixel read mask */
#define	BT479_RDADDR			0x0c
#define	BT479_OVWRADDR			0x10
#define	BT479_OVDATA			0x14
#define	BT479_CTL			0x18
#define	BT479_OVRDADDR			0x1c

#define	GR2_CMAP12		0x0000
#define	GR2_CMAP8		0x1000
#define	GR2_CMAP4		0x1400

/* Bt457 */

#define	BT457_R			0x6c0a0
#define	BT457_G			0x6c0c0
#define	BT457_B			0x6c0e0

#define	BT457_ADDR		0x00
#define	BT457_CMAPDATA		0x04
#define	BT457_CTRL		0x08
#define	BT457_OVDATA		0x0c

/* XMAP5 */

#define	XMAP5_BASE0		0x6c100
#define	XMAP5_BASE1		0x6c120
#define	XMAP5_BASE2		0x6c140
#define	XMAP5_BASE3		0x6c160
#define	XMAP5_BASE4		0x6c180
#define	XMAP5_BASEALL		0x6c1a0

#define XMAP5_MISC		0x00
#define XMAP5_MODE		0x04
#define XMAP5_CLUT		0x08
#define XMAP5_CRC		0x0c
#define XMAP5_ADDRLO		0x10
#define XMAP5_ADDRHI		0x14
#define XMAP5_BYTECOUNT		0x18
#define XMAP5_FIFOSTATUS	0x1c

/*
 * FIFO operation constraints.
 */

#define	GR2_DRAWCHAR_HEIGHT	18


code:
/*	$OpenBSD: grtwovar.h,v 1.1 2012/04/18 11:01:55 miod Exp $	*/
/*	$NetBSD: grtwovar.h,v 1.3 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2004 Christopher SEKIYA
 * 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 grtwo_cnattach(struct gio_attach_args *);
int grtwo_cnprobe(struct gio_attach_args *);


code:
/*	$OpenBSD: impact_gio.c,v 1.6 2012/10/03 22:46:09 miod 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.
 */

/*
 * Driver for the SGI Impact graphics board (GIO attachment).
 */

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

#include <machine/autoconf.h>

#include <mips64/arcbios.h>

#include <sgi/dev/impactreg.h>
#include <sgi/dev/impactvar.h>
#include <sgi/gio/giodevs.h>
#include <sgi/gio/gioreg.h>
#include <sgi/gio/giovar.h>
#include <sgi/sgi/ip22.h>

#include <dev/cons.h>

#define	IMPACT_REG_OFFSET		0x00000000
#define	IMPACT_REG_SIZE			0x00080000

int	impact_gio_match(struct device *, void *, void *);
void	impact_gio_attach(struct device *, struct device *, void *);

const struct cfattach impact_gio_ca = {
	sizeof(struct impact_softc), impact_gio_match, impact_gio_attach
};

int
impact_gio_match(struct device *parent, void *match, void *aux)
{
	struct gio_attach_args *ga = aux;

	if (GIO_PRODUCT_32BIT_ID(ga->ga_product) &&
	    GIO_PRODUCT_PRODUCTID(ga->ga_product) == GIO_PRODUCT_IMPACT)
		return 1;

	return 0;
}

void
impact_gio_attach(struct device *parent, struct device *self, void *aux)
{
	struct gio_attach_args *ga = aux;
	struct impact_softc *sc = (struct impact_softc *)self;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	int console;
	extern struct consdev wsdisplay_cons;

	if (ga->ga_descr != NULL && *ga->ga_descr != '\0')
		printf(": %s", ga->ga_descr);

	if (strncmp(bios_graphics, "alive", 5) != 0) {
		printf("\n%s: device has not been setup by firmware!\n",
		    self->dv_xname);
		return;
	}

	printf("\n");

	console = cn_tab == &wsdisplay_cons && giofb_consaddr == ga->ga_addr;

	if (console != 0) {
		iot = NULL;
		ioh = 0;
	} else {
		iot = ga->ga_iot;

		/* Setup bus space mappings. */
		if (bus_space_map(iot, ga->ga_addr + IMPACT_REG_OFFSET,
		    IMPACT_REG_SIZE, 0, &ioh)) {
			printf("failed to map registers\n");
			return;
		}
	}

	if (impact_attach_common(sc, iot, ioh, console, 0) != 0) {
		if (console == 0)
			bus_space_unmap(iot, ioh, IMPACT_REG_SIZE);
	}
}

/*
 * Console support.
 */

int
impact_gio_cnprobe(struct gio_attach_args *ga)
{
	return impact_gio_match(NULL, NULL, ga);
}

int
impact_gio_cnattach(struct gio_attach_args *ga)
{
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	int rc;

	iot = ga->ga_iot;
	rc = bus_space_map(iot, ga->ga_addr + IMPACT_REG_OFFSET,
	    IMPACT_REG_SIZE, 0, &ioh);
	if (rc != 0)
		return rc;

	rc = impact_cnattach_common(iot, ioh, 0);
	if (rc != 0) {
		bus_space_unmap(iot, ioh, IMPACT_REG_SIZE);
		return rc;
	}

	return 0;
}