code:
/*	$OpenBSD: hpc.c,v 1.16 2013/09/28 14:00:00 miod Exp $	*/
/*	$NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $	*/
/*	$NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $	 */

/*
 * Copyright (c) 2003 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. 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.
 */
/*
 * Copyright (c) 2000 Soren S. Jorvang
 * Copyright (c) 2001 Rafal K. Boni
 * Copyright (c) 2001 Jason R. Thorpe
 * 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.
 */

/*
 * Combined driver for the HPC (High performance Peripheral Controller)
 * and IOC2 (I/O Controller) chips.
 *
 * It would theoretically be better to attach an IOC driver to HPC on
 * IOC systems (IP22/24/26/28), and attach the few onboard devices
 * which attach directly to HPC on IP20, to IOC. But since IOC depends
 * too much on HPC, the complexity this would introduce is not worth
 * the hassle.
 */

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

#include <mips64/archtype.h>

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

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

#include <sgi/hpc/hpcreg.h>
#include <sgi/hpc/hpcvar.h>
#include <sgi/localbus/imcvar.h>
#include <sgi/localbus/intreg.h>
#include <sgi/localbus/intvar.h>
#include <sgi/hpc/iocreg.h>
#include <sgi/sgi/ip22.h>

#include <dev/ic/smc93cx6var.h>

struct hpc_device {
	const char *hd_name;
	bus_addr_t hd_base;
	bus_addr_t hd_devoff;
	bus_addr_t hd_dmaoff;
	int hd_irq;
	int hd_sysmask;
};

#define	HPCDEV_IP20		(1U << 1)	/* Indigo R4k */
#define	HPCDEV_IP22		(1U << 2)	/* Indigo2 */
#define	HPCDEV_IP24		(1U << 3)	/* Indy, Challenge S */
#define	HPCDEV_IP24_INDY	(1U << 4)	/* Indy only */

/*
 * On-board HPC1 devices (IP20 only)
 */
static const struct hpc_device hpc1_onboard[] = {
	/* probe order is important for IP20 zs */
	{ "zs",		/* serial 0/1 duart 1 */
	  HPC_BASE_ADDRESS_0,
	  0x0d10, 0,
	  INT2_L0_INTR(INT2_L0_IP20_SERIAL),
	  HPCDEV_IP20 },
	{ "zs",		/* kbd/ms duart 0 */
	  HPC_BASE_ADDRESS_0,
	  0x0d00, 0,
	  INT2_L0_INTR(INT2_L0_IP20_SERIAL),
	  HPCDEV_IP20 },
	{ "sq",		/* onboard Ethernet */
	  HPC_BASE_ADDRESS_0,
	  HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
	  INT2_L0_INTR(INT2_L0_ENET),
	  HPCDEV_IP20 },
	{ "wdsc",	/* onboard SCSI */
	  HPC_BASE_ADDRESS_0,
	  HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
	  INT2_L0_INTR(INT2_L0_SCSI1),
	  HPCDEV_IP20 },
	{ NULL }
};

/*
 * On-board HPC3 devices (IP22, IP24)
 */
static const struct hpc_device hpc3_onboard[] = {
	{ "zs",		/* serial 0/1 duart 0 */
	  HPC_BASE_ADDRESS_0,
	  IOC_BASE + IOC_SERIAL_REGS, 0,
	  INT2_MAP1_INTR(INT2_MAP_SERIAL),
	  HPCDEV_IP22 | HPCDEV_IP24 },
	{ "pckbc",	/* PS/2 keyboard/mouse controller */
	  HPC_BASE_ADDRESS_0,
	  IOC_BASE + IOC_KB_REGS, 0,
	  INT2_MAP1_INTR(INT2_MAP_PCKBC),
	  HPCDEV_IP22 | HPCDEV_IP24_INDY },
	{ "sq",		/* onboard Ethernet */
	  HPC_BASE_ADDRESS_0,
	  HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
	  INT2_L0_INTR(INT2_L0_ENET),
	  HPCDEV_IP22 | HPCDEV_IP24 },
	{ "wdsc",	/* onboard SCSI */
	  HPC_BASE_ADDRESS_0,
	  HPC3_SCSI0_DEVREGS, HPC3_SCSI0_REGS,
	  INT2_L0_INTR(INT2_L0_IP22_SCSI0),
	  HPCDEV_IP22 | HPCDEV_IP24 },
	{ "wdsc",	/* Indigo2/Challenge M secondary onboard SCSI */
	  HPC_BASE_ADDRESS_0,
	  HPC3_SCSI1_DEVREGS, HPC3_SCSI1_REGS,
	  INT2_L0_INTR(INT2_L0_SCSI1),
	  HPCDEV_IP22 },
	{ "haltwo",	/* onboard audio */
	  HPC_BASE_ADDRESS_0,
	  HPC3_PBUS_CH0_DEVREGS, HPC3_PBUS_DMAREGS,
	  INT2_L1_INTR(INT2_L1_IP22_HPC_DMA),
	  HPCDEV_IP22 | HPCDEV_IP24_INDY },
	{ "pione",	/* onboard parallel port */
	  HPC_BASE_ADDRESS_0,
	  IOC_BASE + IOC_PLP_REGS, 0,
	  INT2_L0_INTR(INT2_L0_IP22_PARALLEL),
	  HPCDEV_IP22 | HPCDEV_IP24 },
	{ "panel",	/* Indy front panel */
	  HPC_BASE_ADDRESS_0,
	  IOC_BASE + IOC_PANEL, 0,
	  INT2_L1_INTR(INT2_L1_IP22_PANEL),
	  HPCDEV_IP22 | HPCDEV_IP24 },
	{ NULL }
};

/*
 * Expansion HPC1 devices
 */
static const struct hpc_device hpc1_devices[] = {
	{ "sq",		/* E++ GIO adapter */
	  0,
	  HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
	  -1,
	  HPCDEV_IP20 | HPCDEV_IP24 },
	{ "wdsc",	/* GIO32 SCSI adapter */
	  0,
	  HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
	  -1,
	  HPCDEV_IP20 | HPCDEV_IP24 },
	{ NULL }
};

/*
 * Expansion HPC3 devices
 */
static const struct hpc_device hpc3_devices[] = {
	{ "sq",		/* Challenge S IO+ secondary ethernet */
	  HPC_BASE_ADDRESS_1,
	  HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
	  INT2_L0_INTR(INT2_L0_GIO_SLOT0),
	  HPCDEV_IP24 },

	{ NULL }
};

struct hpc_softc {
	struct device		sc_dev;

	bus_addr_t		sc_base;

	bus_space_tag_t		sc_ct;
	bus_space_handle_t	sc_ch;
	bus_dma_tag_t		sc_dmat;

	struct timeout		sc_blink_tmo;
};

static struct hpc_values hpc1_values = {
	.revision =		1,
	.scsi0_regs =		HPC1_SCSI0_REGS,
	.scsi0_regs_size =	HPC1_SCSI0_REGS_SIZE,
	.scsi0_cbp =		HPC1_SCSI0_CBP,
	.scsi0_ndbp = 		HPC1_SCSI0_NDBP,
	.scsi0_bc =		HPC1_SCSI0_BC,
	.scsi0_ctl =		HPC1_SCSI0_CTL,
	.scsi0_gio =		HPC1_SCSI0_GIO,
	.scsi0_dev =		HPC1_SCSI0_DEV,
	.scsi0_dmacfg =		HPC1_SCSI0_DMACFG,
	.scsi0_piocfg =		HPC1_SCSI0_PIOCFG,
	.scsi1_regs =		0,
	.scsi1_regs_size =	0,
	.scsi1_cbp =		0,
	.scsi1_ndbp =		0,
	.scsi1_bc =		0,
	.scsi1_ctl =		0,
	.scsi1_gio =		0,
	.scsi1_dev =		0,
	.scsi1_dmacfg =		0,
	.scsi1_piocfg =		0,
	.enet_regs =		HPC1_ENET_REGS,
	.enet_regs_size =	HPC1_ENET_REGS_SIZE,
	.enet_intdelay =	HPC1_ENET_INTDELAY,
	.enet_intdelayval =	HPC1_ENET_INTDELAY_OFF,
	.enetr_cbp =		HPC1_ENETR_CBP,
	.enetr_ndbp =		HPC1_ENETR_NDBP,
	.enetr_bc =		HPC1_ENETR_BC,
	.enetr_ctl =		HPC1_ENETR_CTL,
	.enetr_ctl_active =	HPC1_ENETR_CTL_ACTIVE,
	.enetr_reset =		HPC1_ENETR_RESET,
	.enetr_dmacfg =		0,
	.enetr_piocfg =		0,
	.enetx_cbp =		HPC1_ENETX_CBP,
	.enetx_ndbp =		HPC1_ENETX_NDBP,
	.enetx_bc =		HPC1_ENETX_BC,
	.enetx_ctl =		HPC1_ENETX_CTL,
	.enetx_ctl_active =	HPC1_ENETX_CTL_ACTIVE,
	.enetx_dev =		0,
	.enetr_fifo =		HPC1_ENETR_FIFO,
	.enetr_fifo_size =	HPC1_ENETR_FIFO_SIZE,
	.enetx_fifo =		HPC1_ENETX_FIFO,
	.enetx_fifo_size =	HPC1_ENETX_FIFO_SIZE,
	.enet_devregs =		HPC1_ENET_DEVREGS,
	.enet_devregs_size =	HPC1_ENET_DEVREGS_SIZE,
	.pbus_fifo =		0,
	.pbus_fifo_size =	0,
	.pbus_bbram =		0,
#define MAX_SCSI_XFER   (roundup(MAXPHYS, PAGE_SIZE))
	.scsi_dma_segs =       (MAX_SCSI_XFER / 4096),
	.scsi_dma_segs_size =	4096,
	.scsi_dma_datain_cmd = (HPC1_SCSI_DMACTL_ACTIVE | HPC1_SCSI_DMACTL_DIR),
	.scsi_dma_dataout_cmd =	HPC1_SCSI_DMACTL_ACTIVE,
	.scsi_dmactl_flush =	HPC1_SCSI_DMACTL_FLUSH,
	.scsi_dmactl_active =	HPC1_SCSI_DMACTL_ACTIVE,
	.scsi_dmactl_reset =	HPC1_SCSI_DMACTL_RESET
};

static struct hpc_values hpc3_values = {
	.revision =		3,
	.scsi0_regs =		HPC3_SCSI0_REGS,
	.scsi0_regs_size =	HPC3_SCSI0_REGS_SIZE,
	.scsi0_cbp =		HPC3_SCSI0_CBP,
	.scsi0_ndbp =		HPC3_SCSI0_NDBP,
	.scsi0_bc =		HPC3_SCSI0_BC,
	.scsi0_ctl =		HPC3_SCSI0_CTL,
	.scsi0_gio =		HPC3_SCSI0_GIO,
	.scsi0_dev =		HPC3_SCSI0_DEV,
	.scsi0_dmacfg =		HPC3_SCSI0_DMACFG,
	.scsi0_piocfg =		HPC3_SCSI0_PIOCFG,
	.scsi1_regs =		HPC3_SCSI1_REGS,
	.scsi1_regs_size =	HPC3_SCSI1_REGS_SIZE,
	.scsi1_cbp =		HPC3_SCSI1_CBP,
	.scsi1_ndbp =		HPC3_SCSI1_NDBP,
	.scsi1_bc =		HPC3_SCSI1_BC,
	.scsi1_ctl =		HPC3_SCSI1_CTL,
	.scsi1_gio =		HPC3_SCSI1_GIO,
	.scsi1_dev =		HPC3_SCSI1_DEV,
	.scsi1_dmacfg =		HPC3_SCSI1_DMACFG,
	.scsi1_piocfg =		HPC3_SCSI1_PIOCFG,
	.enet_regs =		HPC3_ENET_REGS,
	.enet_regs_size =	HPC3_ENET_REGS_SIZE,
	.enet_intdelay =	0,
	.enet_intdelayval =	0,
	.enetr_cbp =		HPC3_ENETR_CBP,
	.enetr_ndbp =		HPC3_ENETR_NDBP,
	.enetr_bc =		HPC3_ENETR_BC,
	.enetr_ctl =		HPC3_ENETR_CTL,
	.enetr_ctl_active =	HPC3_ENETR_CTL_ACTIVE,
	.enetr_reset =		HPC3_ENETR_RESET,
	.enetr_dmacfg =		HPC3_ENETR_DMACFG,
	.enetr_piocfg =		HPC3_ENETR_PIOCFG,
	.enetx_cbp =		HPC3_ENETX_CBP,
	.enetx_ndbp =		HPC3_ENETX_NDBP,
	.enetx_bc =		HPC3_ENETX_BC,
	.enetx_ctl =		HPC3_ENETX_CTL,
	.enetx_ctl_active =	HPC3_ENETX_CTL_ACTIVE,
	.enetx_dev =		HPC3_ENETX_DEV,
	.enetr_fifo =		HPC3_ENETR_FIFO,
	.enetr_fifo_size =	HPC3_ENETR_FIFO_SIZE,
	.enetx_fifo =		HPC3_ENETX_FIFO,
	.enetx_fifo_size =	HPC3_ENETX_FIFO_SIZE,
	.enet_devregs =		HPC3_ENET_DEVREGS,
	.enet_devregs_size =	HPC3_ENET_DEVREGS_SIZE,
	.pbus_fifo =		HPC3_PBUS_FIFO,
	.pbus_fifo_size =	HPC3_PBUS_FIFO_SIZE,
	.pbus_bbram =		HPC3_PBUS_BBRAM,
	.scsi_dma_segs =       (MAX_SCSI_XFER / 8192),
	.scsi_dma_segs_size =	8192,
	.scsi_dma_datain_cmd =	HPC3_SCSI_DMACTL_ACTIVE,
	.scsi_dma_dataout_cmd =(HPC3_SCSI_DMACTL_ACTIVE | HPC3_SCSI_DMACTL_DIR),
	.scsi_dmactl_flush =	HPC3_SCSI_DMACTL_FLUSH,
	.scsi_dmactl_active =	HPC3_SCSI_DMACTL_ACTIVE,
	.scsi_dmactl_reset =	HPC3_SCSI_DMACTL_RESET
};

int	hpc_match(struct device *, void *, void *);
void	hpc_attach(struct device *, struct device *, void *);
int	hpc_print(void *, const char *);

int	hpc_revision(struct hpc_softc *, struct gio_attach_args *);
int	hpc_submatch(struct device *, void *, void *);
int	hpc_power_intr(void *);
void	hpc_blink(void *);
void	hpc_blink_ioc(void *);
int	hpc_read_eeprom(int, bus_space_tag_t, bus_space_handle_t, uint8_t *,
	    size_t);

struct hpc_dma_desc *hpc_read_dma_desc_par(struct hpc_dma_desc *,
	    struct hpc_dma_desc *);
struct hpc_dma_desc *hpc_read_dma_desc_ecc(struct hpc_dma_desc *,
	    struct hpc_dma_desc *);
void	hpc_write_dma_desc_par(struct hpc_dma_desc *, struct hpc_dma_desc *);
void	hpc_write_dma_desc_ecc(struct hpc_dma_desc *, struct hpc_dma_desc *);

/* globals since they depend upon the system type, not the hpc version */
struct hpc_dma_desc *(*hpc_read_dma_desc_fn)(struct hpc_dma_desc *,
	    struct hpc_dma_desc *);
void	(*hpc_write_dma_desc_fn)(struct hpc_dma_desc *, struct hpc_dma_desc *);

const struct cfattach hpc_ca = {
	sizeof(struct hpc_softc), hpc_match, hpc_attach
};

struct cfdriver hpc_cd = {
	NULL, "hpc", DV_DULL
};

void	hpc3_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    bus_size_t, int);

bus_space_t hpc3bus_tag = {
	PHYS_TO_XKPHYS(0, CCA_NC),
	NULL,
	imc_read_1, imc_write_1,
	imc_read_2, imc_write_2,
	imc_read_4, imc_write_4,
	imc_read_8, imc_write_8,
	imc_read_raw_2, imc_write_raw_2,
	imc_read_raw_4, imc_write_raw_4,
	imc_read_raw_8, imc_write_raw_8,
	imc_space_map, imc_space_unmap, imc_space_region,
	imc_space_vaddr, hpc3_space_barrier
};

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

	/* Make sure it's actually there and readable */
	if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr, CCA_NC), &dummy) == 0)
		return 1;

	return 0;
}

void
hpc_attach(struct device *parent, struct device *self, void *aux)
{
	struct hpc_softc *sc = (struct hpc_softc *)self;
	struct gio_attach_args* ga = aux;
	struct hpc_attach_args ha;
	const struct hpc_device *hd;
	struct hpc_values *hv;
	uint32_t probe32;
	uint8_t probe8;
	uint32_t hpctype;
	int isonboard;
	int isioplus;
	int giofast;
	int needprobe;
	int sysmask = 0;

	sc->sc_base = ga->ga_addr;
	sc->sc_ct = ga->ga_iot;
	sc->sc_ch = PHYS_TO_XKPHYS(sc->sc_base, CCA_NC);
	sc->sc_dmat = ga->ga_dmat;

	/* setup HPC DMA helpers if not done already */
	if (hpc_read_dma_desc_fn == NULL) {
		if (ip22_ecc) {
			hpc_read_dma_desc_fn = hpc_read_dma_desc_ecc;
			hpc_write_dma_desc_fn = hpc_write_dma_desc_ecc;
		} else {
			hpc_read_dma_desc_fn = hpc_read_dma_desc_par;
			hpc_write_dma_desc_fn = hpc_write_dma_desc_par;
		}
	}

	switch (sys_config.system_type) {
	case SGI_IP20:
		sysmask = HPCDEV_IP20;
		break;
	case SGI_IP22:
	case SGI_IP26:
	case SGI_IP28:
		switch (sys_config.system_subtype) {
		default:
		case IP22_INDIGO2:
			sysmask = HPCDEV_IP22;
			break;
		case IP22_CHALLS:
			sysmask = HPCDEV_IP24;
			break;
		case IP22_INDY:
			sysmask = HPCDEV_IP24 | HPCDEV_IP24_INDY;
			break;
		}
		break;
	};

	if ((hpctype = hpc_revision(sc, ga)) == 0) {
		printf(": could not identify HPC revision\n");
		return;
	}

	if (hpctype != 3)
		hpc_old = 1;

	/* force big-endian mode */
	if (hpctype == 15)
		bus_space_write_4(sc->sc_ct, sc->sc_ch, HPC1_BIGENDIAN, 0);

	/*
	 * Select the proper bus_space_tag for child devices. HPC3 need a
	 * specific barrier function.
	 */
	if (hpctype == 3)
		sc->sc_ct = &hpc3bus_tag;

	/*
	 * All machines have only one HPC on the mainboard itself. ''Extra''
	 * HPCs require bus arbiter and other magic to run happily.
	 */
	isonboard = (sc->sc_base == HPC_BASE_ADDRESS_0);
	isioplus = (sc->sc_base == HPC_BASE_ADDRESS_1 && hpctype == 3 &&
	    (sysmask & HPCDEV_IP24) != 0);

	printf(": SGI HPC%d%s (%s)\n", (hpctype ==  3) ? 3 : 1,
	    (hpctype == 15) ? ".5" : "", (isonboard) ? "onboard" :
	    (isioplus) ? "IO+ mezzanine" : "GIO slot");

	/*
	 * Configure the IOC.
	 */
	if (isonboard && sys_config.system_type != SGI_IP20) {
		/* Reset IOC */
		bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET,
		    IOC_RESET_PARALLEL | IOC_RESET_PCKBC | IOC_RESET_EISA |
		    IOC_RESET_ISDN | IOC_RESET_LED_GREEN );

		/*
		 * Set the two serial ports to PC mode.
		 */
		bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_WRITE,
		    bus_space_read_4(sc->sc_ct, sc->sc_ch,
		      IOC_BASE + IOC_WRITE) |
		    IOC_WRITE_PC_UART2 | IOC_WRITE_PC_UART1);

		/* XXX: the firmware should have taken care of this already */
#if 0
		if (sys_config.system_subtype != IP22_INDIGO2) {
			bus_space_write_4(sc->sc_ct, sc->sc_ch,
			    IOC_BASE + IOC_GCSEL, 0xff);
			bus_space_write_4(sc->sc_ct, sc->sc_ch,
			    IOC_BASE + IOC_GCREG, 0xff);
		}
#endif
	}

	/*
	 * Configure the bus arbiter appropriately.
	 *
	 * In the case of Challenge S, we must tell the IO+ board which
	 * DMA channel to use (we steal it from one of the slots). SGI allows
	 * an HPC1.5 in slot 1, in which case IO+ must use EXP0, or any
	 * other DMA-capable board in slot 0, which leaves us to use EXP1. Of
	 * course, this means that only one GIO board may use DMA.
	 *
	 * Note that this never happens on Indigo2.
	 */
	if (isioplus) {
		int arb_slot;

		if (guarded_read_4(PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_2, CCA_NC),
		    &probe32) != 0)
			arb_slot = GIO_SLOT_EXP1;
		else
			arb_slot = GIO_SLOT_EXP0;

		if (gio_arb_config(arb_slot, GIO_ARB_LB | GIO_ARB_MST |
		    GIO_ARB_64BIT | GIO_ARB_HPC2_64BIT)) {
			printf("%s: failed to configure GIO bus arbiter\n",
			    sc->sc_dev.dv_xname);
			return;
		}

		printf("%s: using EXP%d's DMA channel\n",
		    sc->sc_dev.dv_xname,
		    (arb_slot == GIO_SLOT_EXP0) ? 0 : 1);

		bus_space_write_4(sc->sc_ct, sc->sc_ch,
		    HPC3_PBUS_CFGPIO_REGS, 0x0003ffff);

		if (arb_slot == GIO_SLOT_EXP0)
			bus_space_write_4(sc->sc_ct, sc->sc_ch,
			    HPC3_PBUS_CH0_DEVREGS, 0x20202020);
		else
			bus_space_write_4(sc->sc_ct, sc->sc_ch,
			    HPC3_PBUS_CH0_DEVREGS, 0x30303030);
	} else if (!isonboard) {
		int arb_slot;

		arb_slot = (sc->sc_base == HPC_BASE_ADDRESS_1) ?
		    GIO_SLOT_EXP0 : GIO_SLOT_EXP1;

		if (gio_arb_config(arb_slot, GIO_ARB_RT | GIO_ARB_MST)) {
			printf("%s: failed to configure GIO bus arbiter\n",
			    sc->sc_dev.dv_xname);
			return;
		}
	}

	hpc_read_eeprom(hpctype, sc->sc_ct, sc->sc_ch,
	    ha.hpc_eeprom, sizeof(ha.hpc_eeprom));

	if (hpctype == 3) {
		hv = &hpc3_values;
		if (isonboard) {
			hd = hpc3_onboard;
			if (sys_config.system_subtype == IP22_INDIGO2) {
				/* wild guess */
				giofast = 1;
			} else {
				/*
				 * According to IRIX hpc3.h, the fast GIO bit
				 * is active high, but the register value has
				 * been found to be 0xf8 on slow GIO systems
				 * and 0xf1 on fast ones, which tends to prove
				 * the opposite...
				 */
				if (bus_space_read_4(sc->sc_ct, sc->sc_ch,
				    IOC_BASE + IOC_GCREG) & IOC_GCREG_GIO_33MHZ)
					giofast = 0;
				else
					giofast = 1;
			}
		} else {
			hd = hpc3_devices;
			/*
			 * XXX should IO+ Mezzanine use the same settings as
			 * XXX the onboard HPC3?
			 */
			giofast = 0;
		}
		needprobe = 0;
	} else {
		hv = &hpc1_values;
		hv->revision = hpctype;
		giofast = 0;
		if (isonboard) {
			hd = hpc1_onboard;
			needprobe = 0;
		} else {
			hd = hpc1_devices;
			/*
			 * Until a reliable way of telling E++ and GIO32 SCSI
			 * boards apart is found, we will need to do basic
			 * chip existence checks before attempting to attach.
			 */
			needprobe = 1;
		}
	}
	for (; hd->hd_name != NULL; hd++) {
		if ((hd->hd_sysmask & sysmask) == 0 ||
		    (hd->hd_base != 0 && hd->hd_base != sc->sc_base))
			continue;

		ha.ha_name = hd->hd_name;
		ha.ha_base = sc->sc_base;
		ha.ha_devoff = hd->hd_devoff;
		ha.ha_dmaoff = hd->hd_dmaoff;
		/*
		 * Compute the interrupt line for HPC1 expansion boards.
		 * This allows the hpc1_devices[] array to remain compact.
		 */
		if (hd->hd_irq < 0) {
			if (sys_config.system_type == SGI_IP20)
				ha.ha_irq = INT2_L0_INTR(INT2_L0_GIO_LVL1);
			else {
				if (sc->sc_base == HPC_BASE_ADDRESS_1)
					ha.ha_irq =
					    INT2_MAP0_INTR(INT2_MAP_GIO_SLOT0);
				else
					ha.ha_irq =
					    INT2_MAP0_INTR(INT2_MAP_GIO_SLOT1);
			}
		} else
			ha.ha_irq = hd->hd_irq;

		ha.ha_st = sc->sc_ct;
		ha.ha_sh = sc->sc_ch;
		ha.ha_dmat = sc->sc_dmat;
		ha.hpc_regs = hv;
		ha.ha_giofast = giofast;

		/*
		 * On hpc@gio boards such as the E++, we want to avoid
		 * `wdsc not configured' messages (or sq on SCSI boards).
		 * The following checks are borrowed from the sq(4) and
		 * wdsc(4) respective probes.
		 */
		if (needprobe) {
			paddr_t pa;
			volatile uint32_t *reg;

			if (strcmp(hd->hd_name, "sq") == 0) {
				/*
				 * E++ registers aren't accessible until
				 * the reset register is written to.
				 */
				pa = sc->sc_ch + hd->hd_dmaoff +
				    hv->enetr_reset;
				reg = (volatile uint32_t *)
				    PHYS_TO_XKPHYS(pa, CCA_NC);
				if (guarded_read_4((vaddr_t)reg, &probe32) != 0)
					continue;
				*reg = 0x01;
				delay(20);
				*reg = 0x00;

				pa = sc->sc_ch + hd->hd_devoff +
				    (7 << 2);		/* SEEQ_TXSTAT */
				reg = (volatile uint32_t *)
				    PHYS_TO_XKPHYS(pa, CCA_NC);
				if (guarded_read_4((vaddr_t)reg, &probe32) != 0)
					continue;
				if ((probe32 & 0xff) != 0x80) /*TXSTAT_OLDNEW*/
					continue;
			} else
			/* if (strcmp(hd->hd_name, "wdsc") == 0) */ {
				/*
				 * wdsc registers may not be accessible
				 * until the dma engine is reset.
				 */
				pa = sc->sc_ch + hd->hd_dmaoff +
				    hv->scsi0_ctl;
				reg = (volatile uint32_t *)
				    PHYS_TO_XKPHYS(pa, CCA_NC);
				if (guarded_read_4((vaddr_t)reg, &probe32) != 0)
					continue;
				*reg = hv->scsi_dmactl_reset;
				delay(1000);
				*reg = 0;
				delay(1000);

				pa = sc->sc_ch + hd->hd_devoff + 3;
				if (guarded_read_1(PHYS_TO_XKPHYS(pa, CCA_NC),
				    &probe8) != 0)
					continue;
				if (probe8 == 0xff)
					continue;
			}
		}

		config_found_sm(self, &ha, hpc_print, hpc_submatch);
	}

	/*
	 * Attach the clock chip as well if on hpc0.
	 */
	if (isonboard) {
		if (sys_config.system_type == SGI_IP20) {
			ha.ha_name = "dpclock";
			ha.ha_devoff = HPC1_PBUS_BBRAM;
		} else {
			ha.ha_name = "dsclock";
			ha.ha_devoff = HPC3_PBUS_BBRAM;
		}
		ha.ha_base = sc->sc_base;
		ha.ha_dmaoff = 0;
		ha.ha_irq = -1;
		ha.ha_st = sc->sc_ct;
		ha.ha_sh = sc->sc_ch;
		ha.ha_dmat = sc->sc_dmat;
		ha.hpc_regs = NULL;
		ha.ha_giofast = giofast;

		config_found_sm(self, &ha, hpc_print, hpc_submatch);

		if (sys_config.system_type == SGI_IP20) {
			timeout_set(&sc->sc_blink_tmo, hpc_blink, sc);
			hpc_blink(sc);
		} else {
			timeout_set(&sc->sc_blink_tmo, hpc_blink_ioc, sc);
			hpc_blink_ioc(sc);
		}
	}
}

/*
 * HPC revision detection isn't as simple as it should be. Devices probe
 * differently depending on their slots, but luckily there is only one
 * instance in which we have to decide the major revision (HPC1 vs HPC3).
 *
 * The HPC is found in the following configurations:
 *	o Indigo R4k
 * 		One on-board HPC1 or HPC1.5.
 * 		Up to two additional HPC1.5's in GIO slots 0 and 1.
 *	o Indy
 * 		One on-board HPC3.
 *		Up to two additional HPC1.5's in GIO slots 0 and 1.
 *	o Challenge S
 * 		One on-board HPC3.
 * 		Up to one additional HPC3 on the IO+ board (if installed).
 *		Up to one additional HPC1.5 in slot 1 of the IO+ board.
 *	o Indigo2, Challenge M
 *		One on-board HPC3.
 *
 * All we really have to worry about is the IP24 case.
 */
int
hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga)
{
	uint32_t reg;

	/* No hardware ever supported the last hpc base address. */
	if (ga->ga_addr == HPC_BASE_ADDRESS_3)
		return 0;

	switch (sys_config.system_type) {
	case SGI_IP20:
		if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr + HPC1_BIGENDIAN,
		    CCA_NC), &reg) != 0) {
			if (((reg >> HPC1_REVSHIFT) & HPC1_REVMASK) ==
			    HPC1_REV15)
				return 15;
			else
				return 1;
		}
		return 1;

	case SGI_IP22:
	case SGI_IP26:
	case SGI_IP28:
		if (ga->ga_addr == HPC_BASE_ADDRESS_0)
			return 3;

		if (sys_config.system_subtype == IP22_INDIGO2)
			return 0;

		/*
		 * If IP24, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1
		 * must be HPC1.5.
		 */

		if (ga->ga_addr == HPC_BASE_ADDRESS_2)
			return 15;

		/*
		 * Probe for it. We use one of the PBUS registers. Note
		 * that this probe succeeds with my E++ adapter in slot 1
		 * (bad), but it appears to always do the right thing in
		 * slot 0 (good!) and we're only worried about that one
		 * anyhow.
		 */
		if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr +
		    HPC3_PBUS_CH7_BP, CCA_NC), &reg) != 0)
			return 15;
		else
			return 3;
	}

	return 0;
}

int
hpc_submatch(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = (struct cfdata *)vcf;
	struct hpc_attach_args *ha = (struct hpc_attach_args *)aux;

	if (cf->cf_loc[0 /*HPCCF_OFFSET*/] != -1 &&
	    (bus_addr_t)cf->cf_loc[0 /*HPCCF_OFFSET*/] != ha->ha_devoff)
		return 0;

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

int
hpc_print(void *aux, const char *pnp)
{
	struct hpc_attach_args *ha = aux;

	if (pnp)
		printf("%s at %s", ha->ha_name, pnp);

	printf(" offset 0x%08lx", ha->ha_devoff);
	if (ha->ha_irq >= 0)
		printf(" irq %d", ha->ha_irq);

	return UNCONF;
}

void *
hpc_intr_establish(int irq, int level, int (*handler)(void *), void *arg,
    const char *what)
{
	return int2_intr_establish(irq, level, handler, arg, what);
}

int
hpc_is_intr_pending(int irq)
{
	return int2_is_intr_pending(irq);
}

void
hpc_intr_disable(void *v)
{
	int2_intr_disable(v);
}

void
hpc_intr_enable(void *v)
{
	int2_intr_enable(v);
}

/*
 * bus_space_barrier() function for HPC3 (which have a write buffer)
 */
void
hpc3_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs,
    bus_size_t sz, int how)
{
	mips_sync();
	/* just read a side-effect free register */
	(void)*(volatile uint32_t *)
	    PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_0 + HPC3_INTRSTAT_40, CCA_NC);
}

void
hpc_blink(void *arg)
{
	struct hpc_softc *sc = arg;

	bus_space_write_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS,
	    bus_space_read_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS) ^
	      HPC1_AUX_CONSLED);

	timeout_add(&sc->sc_blink_tmo,
	    (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
}

void
hpc_blink_ioc(void *arg)
{
	struct hpc_softc *sc = arg;
	uint32_t value;

	/* This is a bit odd.  To strobe the green LED, we have to toggle the
	   red control bit. */
	value = bus_space_read_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET) &
	    0xff;
	value ^= IOC_RESET_LED_RED;
	bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET, value);

	timeout_add(&sc->sc_blink_tmo,
	    (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
}

/*
 * Read the eeprom associated with one of the HPC's.
 *
 * NB: An eeprom is not always present, but the HPC should be able to
 *     handle this gracefully. Any consumers should validate the data to
 *     ensure it's reasonable.
 */
int
hpc_read_eeprom(int hpctype, bus_space_tag_t t, bus_space_handle_t h,
    uint8_t *buf, size_t len)
{
	struct seeprom_descriptor sd;
	bus_space_handle_t bsh;
	bus_size_t offset;

	if (!len || len & 0x1)
		return (1);

	offset = (hpctype == 3) ? HPC3_EEPROM_DATA : HPC1_AUX_REGS;

	if (bus_space_subregion(t, h, offset, 1, &bsh) != 0)
		return (1);

	sd.sd_chip = C56_66;
	sd.sd_tag = t;
	sd.sd_bsh = bsh;
	sd.sd_regsize = 1;
	sd.sd_control_offset = 0;
	sd.sd_status_offset = 0;
	sd.sd_dataout_offset = 0;
	sd.sd_DI = 0x10;	/* EEPROM -> CPU */
	sd.sd_DO = 0x08;	/* CPU -> EEPROM */
	sd.sd_CK = 0x04;
	sd.sd_CS = 0x02;
	sd.sd_MS = 0;
	sd.sd_RDY = 0;

	if (read_seeprom(&sd, (uint16_t *)buf, 0, len / 2) != 1)
		return (1);

	bus_space_unmap(t, bsh, 1);

	return 0;
}

/*
 * Routines to copy and update HPC DMA descriptors in uncached memory.
 */

struct hpc_dma_desc *
hpc_read_dma_desc(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
{
	return (*hpc_read_dma_desc_fn)(src, store);
}

void
hpc_write_dma_desc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
{
	(*hpc_write_dma_desc_fn)(dst, src);
}

/* parity MC flavour: no copy */
struct hpc_dma_desc *
hpc_read_dma_desc_par(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
{
	return src;
}

void
hpc_write_dma_desc_par(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
{
}

/* ECC MC flavour: copy, and update in slow mode */
struct hpc_dma_desc *
hpc_read_dma_desc_ecc(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
{
	bcopy(src, store, sizeof(struct hpc_dma_desc));
	return store;
}

void
hpc_write_dma_desc_ecc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
{
	register_t sr;
	int mode;

	sr = disableintr();
	mode = ip22_slow_mode();
	bcopy(src, dst, sizeof(struct hpc_dma_desc));
	ip22_restore_mode(mode);
	setsr(sr);
}


code:
/*	$OpenBSD: hpcdma.c,v 1.1 2012/03/28 20:44:23 miod Exp $	*/
/*	$NetBSD: hpcdma.c,v 1.21 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2001 Wayne Knowles
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Wayne Knowles
 *
 * 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 the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE 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.
 */

/*
 * Support for SCSI DMA provided by the HPC.
 *
 * Note: We use SCSI0 offsets, etc. here.  Since the layout of SCSI0
 * and SCSI1 are the same, this is no problem.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <sgi/hpc/hpcreg.h>
#include <sgi/hpc/hpcvar.h>
#include <sgi/hpc/hpcdma.h>

/*
 * Allocate DMA Chain descriptor list
 */
void
hpcdma_init(struct hpc_attach_args *haa, struct hpc_dma_softc *sc, int ndesc)
{
	bus_dma_segment_t seg;
	int rseg, allocsz;

	sc->sc_bst = haa->ha_st;
	sc->sc_dmat = haa->ha_dmat;
	sc->sc_ndesc = ndesc;
	sc->sc_flags = 0;

	if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff,
	    sc->hpc->scsi0_regs_size, &sc->sc_bsh) != 0) {
		printf(": can't map DMA registers\n");
		return;
	}

	/* Alloc 1 additional descriptor - needed for DMA bug fix */
	allocsz = sizeof(struct hpc_dma_desc) * (ndesc + 1);

	/*
	 * Allocate a block of memory for dma chaining pointers
	 */
	if (bus_dmamem_alloc(sc->sc_dmat, allocsz, 0, 0, &seg, 1, &rseg,
	    BUS_DMA_NOWAIT)) {
		printf(": can't allocate sglist\n");
		return;
	}
	/* Map pages into kernel memory */
	if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, allocsz,
	    (caddr_t *)&sc->sc_desc_kva, BUS_DMA_NOWAIT)) {
		printf(": can't map sglist\n");
		bus_dmamem_free(sc->sc_dmat, &seg, rseg);
		return;
	}

	if (bus_dmamap_create(sc->sc_dmat, allocsz, 1 /*seg*/, allocsz, 0,
	    BUS_DMA_WAITOK, &sc->sc_dmamap) != 0) {
		printf(": failed to create dmamap\n");
		return;
	}

	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
	    sc->sc_desc_kva, allocsz, NULL, BUS_DMA_NOWAIT)) {
		printf(": can't load sglist\n");
		return;
	}

	sc->sc_desc_pa = sc->sc_dmamap->dm_segs[0].ds_addr;
}

void
hpcdma_sglist_create(struct hpc_dma_softc *sc, bus_dmamap_t dmamap)
{
	struct hpc_dma_desc *hva;
	bus_addr_t hpa;
	bus_dma_segment_t *segp;
	int i;

	KASSERT(dmamap->dm_nsegs <= sc->sc_ndesc);

	hva  = sc->sc_desc_kva;
	hpa  = sc->sc_desc_pa;
	segp = dmamap->dm_segs;

#ifdef DMA_DEBUG
	printf("DMA_SGLIST<");
#endif
	for (i = dmamap->dm_nsegs; i; i--) {
#ifdef DMA_DEBUG
		printf("%p:%ld, ", (void *)segp->ds_addr, segp->ds_len);
#endif
		hpa += sizeof(struct hpc_dma_desc);	/* next chain desc */
		if (sc->hpc->revision == 3) {
			hva->hpc3_hdd_bufptr = segp->ds_addr;
			hva->hpc3_hdd_ctl    = segp->ds_len;
			hva->hdd_descptr     = hpa;
		} else /* HPC 1/1.5 */ {
			/*
			 * there doesn't seem to be any good way of doing this
		   	 * via an abstraction layer
			 */
			hva->hpc1_hdd_bufptr = segp->ds_addr;
			hva->hpc1_hdd_ctl    = segp->ds_len;
			hva->hdd_descptr     = hpa;
		}
		++hva;
		++segp;
	}

	/* Work around HPC3 DMA bug */
	if (sc->hpc->revision == 3) {
		hva->hpc3_hdd_bufptr  = 0;
		hva->hpc3_hdd_ctl     = HPC3_HDD_CTL_EOCHAIN;
		hva->hdd_descptr = 0;
	} else {
		hva--;
		hva->hpc1_hdd_bufptr |= HPC1_HDD_CTL_EOCHAIN;
		hva->hdd_descptr = 0;
	}

#ifdef DMA_DEBUG
	printf(">\n");
#endif
	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
	    0, sizeof(struct hpc_dma_desc) * (dmamap->dm_nsegs + 1),
	    BUS_DMASYNC_PREWRITE);

	/* Load DMA Descriptor list */
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ndbp,
	    sc->sc_desc_pa);
}

void
hpcdma_cntl(struct hpc_dma_softc *sc, uint32_t mode)
{
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, mode);
}

void
hpcdma_reset(struct hpc_dma_softc *sc)
{
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl,
	    sc->hpc->scsi_dmactl_reset);
	delay(100);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 0);
	delay(1000);
}

void
hpcdma_flush(struct hpc_dma_softc *sc)
{
	uint32_t mode;

	mode = bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
	    sc->hpc->scsi0_ctl, mode | sc->hpc->scsi_dmactl_flush);

	/* Wait for Active bit to drop */
	while (bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl) &
	    sc->hpc->scsi_dmactl_active) {
		bus_space_barrier(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 4,
		    BUS_SPACE_BARRIER_READ);
	}
}

license: unknown


code:
/*	$OpenBSD: hpcdma.h,v 1.1 2012/03/28 20:44:23 miod Exp $	*/
/*	$NetBSD: hpcdma.h,v 1.11 2011/07/01 18:53:46 dyoung Exp $	*/

/*
 * Copyright (c) 2001 Wayne Knowles
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Wayne Knowles
 *
 * 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 the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE 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.
 */

struct hpc_dma_softc {
	bus_space_tag_t		sc_bst;
	bus_space_handle_t	sc_bsh;
	bus_dma_tag_t		sc_dmat;

	uint32_t		sc_flags;
#define	HPCDMA_READ	0x20		/* direction of transfer */
#define	HPCDMA_LOADED	0x40		/* bus_dmamap loaded */
#define	HPCDMA_ACTIVE	0x80		/* DMA engine is busy */
	uint32_t		sc_dmacmd;
	int			sc_ndesc;
	bus_dmamap_t		sc_dmamap;
	struct hpc_dma_desc    *sc_desc_kva;	/* Virtual address */
	bus_addr_t		sc_desc_pa;	/* DMA address */
	ssize_t			sc_dlen;	/* number of bytes transfered */
	struct hpc_values       *hpc;		/* constants for HPC1/3 */
};

void hpcdma_init(struct hpc_attach_args *, struct hpc_dma_softc *, int);
void hpcdma_sglist_create(struct hpc_dma_softc *, bus_dmamap_t);
void hpcdma_cntl(struct hpc_dma_softc *, uint32_t);
void hpcdma_reset(struct hpc_dma_softc *);
void hpcdma_flush(struct hpc_dma_softc *);


code:
/*	$OpenBSD: hpcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $	*/
/*	$NetBSD: hpcreg.h,v 1.20 2011/01/25 12:21:04 tsutsui Exp $	*/

/*
 * Copyright (c) 2001 Rafal K. Boni
 * 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.
 */

/*
 * HPC locations are identical across all HPC-supported
 * platforms.
 */
#define HPC_BASE_ADDRESS_0	0x1fb80000	/* Primary onboard */
#define HPC_BASE_ADDRESS_1	0x1fb00000
#define HPC_BASE_ADDRESS_2	0x1f980000
#define HPC_BASE_ADDRESS_3	0x1f900000	/* NB: Never supported in h/w */

/*
 * HPC3 descriptor layout.
 */
struct hpc_dma_desc {
	uint32_t	hdd_bufptr;	/* Physical address of buffer */
	uint32_t	hdd_ctl;	/* Control flags and byte count */
	uint32_t	hdd_descptr;	/* Physical address of next descr. */
	uint32_t	hdd_pad;	/* Pad out to quadword alignment */
};

/*
 * The hdd_bufptr and hdd_ctl fields are swapped between HPC1 and
 * HPC3. These fields are referenced by macro for readability.
 */
#define hpc1_hdd_ctl	hdd_bufptr
#define hpc1_hdd_bufptr	hdd_ctl
#define hpc3_hdd_ctl	hdd_ctl
#define hpc3_hdd_bufptr	hdd_bufptr

/*
 * Control flags
 */
#define HPC3_HDD_CTL_EOCHAIN	0x80000000	/* End of descriptor chain */
#define HPC3_HDD_CTL_EOPACKET	0x40000000	/* Ethernet: end of packet */
#define HPC3_HDD_CTL_INTR	0x20000000	/* Interrupt when finished */
#define HPC3_HDD_CTL_XMITDONE	0x00008000	/* Ethernet transmit done */
#define HPC3_HDD_CTL_OWN	0x00004000	/* CPU owns this frame */

#define HPC3_HDD_CTL_BYTECNT(x)	((x) & 0x3fff)	/* Byte count: for ethernet
						 * rcv channel also doubles as
						 * length of packet received
						 */

/*
 * HPC memory map, as offsets from HPC base
 *
 * XXXrkb: should each section be used as a base and have the specific
 * registers offset from there??
 *
 * XXX: define register values as well as their offsets.
 *
 */
#define HPC3_PBUS_DMAREGS	0x00000000	/* DMA registers for PBus */
#define HPC3_PBUS_DMAREGS_SIZE	0x0000ffff	/* channels 0 - 7 */

#define HPC3_PBUS_CH0_BP	0x00000000	/* Chan 0 Buffer Ptr */
#define HPC3_PBUS_CH0_DP	0x00000004	/* Chan 0 Descriptor Ptr */
#define HPC3_PBUS_CH0_CTL	0x00001000	/* Chan 0 Control Register */

#define HPC3_PBUS_CH1_BP	0x00002000	/* Chan 1 Buffer Ptr */
#define HPC3_PBUS_CH1_DP	0x00002004	/* Chan 1 Descriptor Ptr */
#define HPC3_PBUS_CH1_CTL	0x00003000	/* Chan 1 Control Register */

#define HPC3_PBUS_CH2_BP	0x00004000	/* Chan 2 Buffer Ptr */
#define HPC3_PBUS_CH2_DP	0x00004004	/* Chan 2 Descriptor Ptr */
#define HPC3_PBUS_CH2_CTL	0x00005000	/* Chan 2 Control Register */

#define HPC3_PBUS_CH3_BP	0x00006000	/* Chan 3 Buffer Ptr */
#define HPC3_PBUS_CH3_DP	0x00006004	/* Chan 3 Descriptor Ptr */
#define HPC3_PBUS_CH3_CTL	0x00007000	/* Chan 3 Control Register */

#define HPC3_PBUS_CH4_BP	0x00008000	/* Chan 4 Buffer Ptr */
#define HPC3_PBUS_CH4_DP	0x00008004	/* Chan 4 Descriptor Ptr */
#define HPC3_PBUS_CH4_CTL	0x00009000	/* Chan 4 Control Register */

#define HPC3_PBUS_CH5_BP	0x0000a000	/* Chan 5 Buffer Ptr */
#define HPC3_PBUS_CH5_DP	0x0000a004	/* Chan 5 Descriptor Ptr */
#define HPC3_PBUS_CH5_CTL	0x0000b000	/* Chan 5 Control Register */

#define HPC3_PBUS_CH6_BP	0x0000c000	/* Chan 6 Buffer Ptr */
#define HPC3_PBUS_CH6_DP	0x0000c004	/* Chan 6 Descriptor Ptr */
#define HPC3_PBUS_CH6_CTL	0x0000d000	/* Chan 6 Control Register */

#define HPC3_PBUS_CH7_BP	0x0000e000	/* Chan 7 Buffer Ptr */
#define HPC3_PBUS_CH7_DP	0x0000e004	/* Chan 7 Descriptor Ptr */
#define HPC3_PBUS_CH7_CTL	0x0000f000	/* Chan 7 Control Register */

#define HPC3_SCSI0_REGS		0x00010000	/* SCSI channel 0 registers */
#define HPC3_SCSI0_REGS_SIZE	0x00001fff

#define HPC3_SCSI0_CBP		0x00000000	/* Current buffer ptr */
#define HPC3_SCSI0_NDBP		0x00000004	/* Next descriptor ptr */

#define HPC3_SCSI0_BC		0x00001000	/* DMA byte count & flags */
#define HPC3_SCSI0_CTL		0x00001004	/* DMA control flags */
#define HPC3_SCSI0_GIO		0x00001008	/* GIO DMA FIFO pointer */
#define HPC3_SCSI0_DEV		0x0000100c	/* Device DMA FIFO pointer */
#define HPC3_SCSI0_DMACFG	0x00001010	/* DMA configuration */
#define HPC3_SCSI0_PIOCFG	0x00001014	/* PIO configuration */

#define HPC3_SCSI1_REGS		0x00012000	/* SCSI channel 1 registers */
#define HPC3_SCSI1_REGS_SIZE	0x00001fff

#define HPC3_SCSI1_CBP		0x00000000	/* Current buffer ptr */
#define HPC3_SCSI1_NDBP		0x00000004	/* Next descriptor ptr */

#define HPC3_SCSI1_BC		0x00001000	/* DMA byte count & flags */
#define HPC3_SCSI1_CTL		0x00001004	/* DMA control flags */
#define HPC3_SCSI1_GIO		0x00001008	/* GIO DMA FIFO pointer */
#define HPC3_SCSI1_DEV		0x0000100c	/* Device DMA FIFO pointer */
#define HPC3_SCSI1_DMACFG	0x00001010	/* DMA configuration */
#define HPC3_SCSI1_PIOCFG	0x00001014	/* PIO configuration */

/* HPC3_SCSIx_CTL "SCSI control register" flags: */
#define HPC3_SCSI_DMACTL_IRQ    0x01 /* IRQ asserted, dma done or parity */
#define HPC3_SCSI_DMACTL_ENDIAN 0x02 /* DMA endian mode, 0=BE, 1=LE */
#define HPC3_SCSI_DMACTL_DIR    0x04 /* DMA direction, 0=dev->mem, 1=mem->dev */
#define HPC3_SCSI_DMACTL_FLUSH  0x08 /* Flush DMA FIFO's */
#define HPC3_SCSI_DMACTL_ACTIVE 0x10 /* DMA channel is active */
#define HPC3_SCSI_DMACTL_AMASK  0x20 /* DMA active inhibits PIO */
#define HPC3_SCSI_DMACTL_RESET  0x40 /* Reset dma channel and ext. controller */
#define HPC3_SCSI_DMACTL_PERR   0x80 /* Parity error: interface to controller */

/* HPC_PBUS_CHx_CTL read: */
#define HPC3_PBUS_DMACTL_IRQ	0x01 /* IRQ asserted, DMA done */
#define HPC3_PBUS_DMACTL_ISACT	0x02 /* DMA channel is active */

/* HPC_PBUS_CHx_CTL write: */
#define HPC3_PBUS_DMACTL_ENDIAN	0x02 /* DMA endianness, 0=BE 1=LE */
#define HPC3_PBUS_DMACTL_RECEIVE 0x04 /* DMA direction, 1=dev->mem, 0=mem->dev*/
#define HPC3_PBUS_DMACTL_FLUSH	0x08 /* Flush DMA FIFO */
#define HPC3_PBUS_DMACTL_ACT	0x10 /* Activate DMA channel */
#define HPC3_PBUS_DMACTL_ACT_LD	0x20 /* Load enable for ACT */
#define HPC3_PBUS_DMACTL_RT	0x40 /* Enable real time GIO service for DMA */
#define HPC3_PBUS_DMACTL_HIGHWATER_SHIFT 8
#define HPC3_PBUS_DMACTL_FIFOBEG_SHIFT	16
#define HPC3_PBUS_DMACTL_FIFOEND_SHIFT	24

#define HPC3_ENET_REGS		0x00014000	/* Ethernet registers */
#define HPC3_ENET_REGS_SIZE	0x00003fff

#define HPC3_ENETR_CBP		0x00000000	/* Recv: Current buffer ptr */
#define HPC3_ENETR_NDBP		0x00000004	/* Recv: Next descriptor ptr */

#define HPC3_ENETR_BC		0x00001000	/* Recv: DMA byte cnt/flags */
#define HPC3_ENETR_CTL		0x00001004	/* Recv: DMA control flags */

#define HPC3_ENETR_CTL_STAT_5_0	0x003f		/* Seeq irq status: bits 0-5 */
#define HPC3_ENETR_CTL_STAT_6	0x0040		/* Irq status: late_rxdc */
#define HPC3_ENETR_CTL_STAT_7	0x0080		/* Irq status: old/new bit */
#define HPC3_ENETR_CTL_LENDIAN	0x0100		/* DMA channel endian mode */
#define HPC3_ENETR_CTL_ACTIVE	0x0200		/* DMA channel active? */
#define HPC3_ENETR_CTL_ACTIVE_MSK 0x0400	/* DMA channel active? */
#define HPC3_ENETR_CTL_RBO	0x0800		/* Recv buffer overflow */

#define HPC3_ENETR_GIO		0x00001008	/* Recv: GIO DMA FIFO ptr */
#define HPC3_ENETR_DEV		0x0000100c	/* Recv: Device DMA FIFO ptr */
#define HPC3_ENETR_RESET	0x00001014	/* Recv: Ethernet chip reset */

#define HPC3_ENETR_RESET_CH	0x0001		/* Reset controller & chan */
#define HPC3_ENETR_RESET_CLRINT	0x0002		/* Clear channel interrupt */
#define HPC3_ENETR_RESET_LOOPBK	0x0004		/* External loopback enable */
#define HPC3_ENETR_RESET_CLRRBO	0x0008		/* Clear RBO condition (??) */

#define HPC3_ENETR_DMACFG	0x00001018	/* Recv: DMA configuration */

#define	HPC3_ENETR_DMACFG_D1(_x) (((_x) << 0) & 0x000f)	/* D1 gio_clk cycles */
#define	HPC3_ENETR_DMACFG_D2(_x) (((_x) << 4) & 0x00f0)	/* D2 gio_clk cycles */
#define	HPC3_ENETR_DMACFG_D3(_x) (((_x) << 8) & 0x0f00)	/* D3 gio_clk cycles */
#define	HPC3_ENETR_DMACFG_WRCTL	0x01000		/* Enable IPG write */

/*
 * The following three bits work around bugs in the Seeq 8003; if you
 * don't set them, the Seeq gets wonky pretty often.
 */
#define	HPC3_ENETR_DMACFG_FIX_RXDC 0x02000	/* Clear EOP bits on RXDC */
#define	HPC3_ENETR_DMACFG_FIX_EOP  0x04000	/* Enable rxintr timeout */
#define	HPC3_ENETR_DMACFG_FIX_INTR 0x08000	/* Enable EOP timeout */
#define	HPC3_ENETR_DMACFG_TIMEOUT  0x30000	/* Timeout value for above two*/

#define HPC3_ENETR_PIOCFG	0x0000101c	/* Recv: PIO configuration */

#define HPC3_ENETR_PIOCFG_P1(_x) (((_x) << 0) & 0x000f)	/* P1 gio_clk cycles */
#define HPC3_ENETR_PIOCFG_P2(_x) (((_x) << 4) & 0x00f0)	/* P2 gio_clk cycles */
#define HPC3_ENETR_PIOCFG_P3(_x) (((_x) << 8) & 0x0f00)	/* P3 gio_clk cycles */

#define HPC3_ENETX_CBP		0x00002000	/* Xmit: Current buffer ptr */
#define HPC3_ENETX_NDBP		0x00002004	/* Xmit: Next descriptor ptr */

#define HPC3_ENETX_BC		0x00003000	/* Xmit: DMA byte cnt/flags */
#define HPC3_ENETX_CTL		0x00003004	/* Xmit: DMA control flags */

#define HPC3_ENETX_CTL_STAT_5_0	0x003f		/* Seeq irq status: bits 0-5 */
#define HPC3_ENETX_CTL_STAT_6	0x0040		/* Irq status: late_rxdc */
#define HPC3_ENETX_CTL_STAT_7	0x0080		/* Irq status: old/new bit */
#define HPC3_ENETX_CTL_LENDIAN	0x0100		/* DMA channel endian mode */
#define HPC3_ENETX_CTL_ACTIVE	0x0200		/* DMA channel active? */
#define HPC3_ENETX_CTL_ACTIVE_MSK 0x0400	/* DMA channel active? */
#define HPC3_ENETX_CTL_RBO	0x0800		/* Recv buffer overflow */

#define HPC3_ENETX_GIO		0x00003008	/* Xmit: GIO DMA FIFO ptr */
#define HPC3_ENETX_DEV		0x0000300c	/* Xmit: Device DMA FIFO ptr */

#define HPC3_PBUS_FIFO		0x00020000	/* PBus DMA FIFO */
#define HPC3_PBUS_FIFO_SIZE	0x00007fff	/* PBus DMA FIFO size */

#define HPC3_SCSI0_FIFO		0x00028000	/* SCSI0 DMA FIFO */
#define HPC3_SCSI0_FIFO_SIZE	0x00001fff	/* SCSI0 DMA FIFO size */

#define HPC3_SCSI1_FIFO		0x0002a000	/* SCSI1 DMA FIFO */
#define HPC3_SCSI1_FIFO_SIZE	0x00001fff	/* SCSI1 DMA FIFO size */

#define HPC3_ENETR_FIFO		0x0002c000	/* Ether recv DMA FIFO */
#define HPC3_ENETR_FIFO_SIZE	0x00001fff	/* Ether recv DMA FIFO size */

#define HPC3_ENETX_FIFO		0x0002e000	/* Ether xmit DMA FIFO */
#define HPC3_ENETX_FIFO_SIZE	0x00001fff	/* Ether xmit DMA FIFO size */

/*
 * HPCBUG: The interrupt status is split amongst two registers, and they're
 * not even consecutive in the HPC address space.  This is documented as a
 * bug by SGI.
 */
#define HPC3_INTRSTAT_40	0x00030000	/* Interrupt stat, bits 4:0 */
#define HPC3_INTRSTAT_95	0x0003000c	/* Interrupt stat, bits 9:5 */

#define HPC3_GIO_MISC		0x00030004	/* GIO64 misc register */

#define HPC3_EEPROM_DATA	0x0003000b	/* Serial EEPROM data reg. */
						/* (byte) */

#define HPC3_GIO_BUSERR		0x00030010	/* GIO64 bus error intr stat */

#define HPC3_SCSI0_DEVREGS	0x00044000	/* SCSI channel 0 chip regs */
#define HPC3_SCSI1_DEVREGS	0x0004c000	/* SCSI channel 1 chip regs */

#define HPC3_ENET_DEVREGS	0x00054000	/* Ethernet chip registers */
#define HPC3_ENET_DEVREGS_SIZE	0x000004ff	/* Size of chip registers */

#define HPC3_PBUS_DEVREGS	0x00054000	/* PBus PIO chip registers */
#define HPC3_PBUS_DEVREGS_SIZE	0x000003ff	/* PBus PIO chip registers */

#define HPC3_PBUS_CH0_DEVREGS	0x00058000	/* PBus ch. 0 chip registers */
#define HPC3_PBUS_CH0_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH1_DEVREGS	0x00058400	/* PBus ch. 1 chip registers */
#define HPC3_PBUS_CH1_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH2_DEVREGS	0x00058800	/* PBus ch. 2 chip registers */
#define HPC3_PBUS_CH2_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH3_DEVREGS	0x00058c00	/* PBus ch. 3 chip registers */
#define HPC3_PBUS_CH3_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH4_DEVREGS	0x00059000	/* PBus ch. 4 chip registers */
#define HPC3_PBUS_CH4_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH5_DEVREGS	0x00059400	/* PBus ch. 5 chip registers */
#define HPC3_PBUS_CH5_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH6_DEVREGS	0x00059800	/* PBus ch. 6 chip registers */
#define HPC3_PBUS_CH6_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH7_DEVREGS	0x00059c00	/* PBus ch. 7 chip registers */
#define HPC3_PBUS_CH7_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH8_DEVREGS	0x0005a000	/* PBus ch. 8 chip registers */
#define HPC3_PBUS_CH8_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH9_DEVREGS	0x0005a400	/* PBus ch. 9 chip registers */
#define HPC3_PBUS_CH9_DEVREGS_SIZE   0x03ff

#define HPC3_PBUS_CH8_DEVREGS_2	0x0005a800	/* PBus ch. 8 chip registers */
#define HPC3_PBUS_CH8_DEVREGS_2_SIZE 0x03ff

#define HPC3_PBUS_CH9_DEVREGS_2	0x0005ac00	/* PBus ch. 9 chip registers */
#define HPC3_PBUS_CH9_DEVREGS_2_SIZE 0x03ff

#define HPC3_PBUS_CH8_DEVREGS_3	0x0005b000	/* PBus ch. 8 chip registers */
#define HPC3_PBUS_CH8_DEVREGS_3_SIZE 0x03ff

#define HPC3_PBUS_CH9_DEVREGS_3	0x0005b400	/* PBus ch. 9 chip registers */
#define HPC3_PBUS_CH9_DEVREGS_3_SIZE 0x03ff

#define HPC3_PBUS_CH8_DEVREGS_4	0x0005b800	/* PBus ch. 8 chip registers */
#define HPC3_PBUS_CH8_DEVREGS_4_SIZE 0x03ff

#define HPC3_PBUS_CH9_DEVREGS_4	0x0005bc00	/* PBus ch. 9 chip registers */
#define HPC3_PBUS_CH9_DEVREGS_4_SIZE 0x03ff

#define HPC3_PBUS_CFGDMA_REGS	0x0005c000	/* PBus DMA config registers */
#define HPC3_PBUS_CFGDMA_REGS_SIZE   0x0fff

#define HPC3_PBUS_CH0_CFGDMA	0x0005c000	/* PBus Ch. 0 DMA config */
#define HPC3_PBUS_CH0_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH1_CFGDMA	0x0005c200	/* PBus Ch. 1 DMA config */
#define HPC3_PBUS_CH1_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH2_CFGDMA	0x0005c400	/* PBus Ch. 2 DMA config */
#define HPC3_PBUS_CH2_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH3_CFGDMA	0x0005c600	/* PBus Ch. 3 DMA config */
#define HPC3_PBUS_CH3_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH4_CFGDMA	0x0005c800	/* PBus Ch. 4 DMA config */
#define HPC3_PBUS_CH4_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH5_CFGDMA	0x0005ca00	/* PBus Ch. 5 DMA config */
#define HPC3_PBUS_CH5_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH6_CFGDMA	0x0005cc00	/* PBus Ch. 6 DMA config */
#define HPC3_PBUS_CH6_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CH7_CFGDMA	0x0005ce00	/* PBus Ch. 7 DMA config */
#define HPC3_PBUS_CH7_CFGDMA_SIZE    0x01ff

#define HPC3_PBUS_CFGPIO_REGS	0x0005d000	/* PBus PIO config registers */
#define HPC3_PBUS_CFGPIO_REGS_SIZE   0x0fff

#define HPC3_PBUS_CH0_CFGPIO	0x0005d000	/* PBus Ch. 0 PIO config */
#define HPC3_PBUS_CH1_CFGPIO	0x0005d100	/* PBus Ch. 1 PIO config */
#define HPC3_PBUS_CH2_CFGPIO	0x0005d200	/* PBus Ch. 2 PIO config */
#define HPC3_PBUS_CH3_CFGPIO	0x0005d300	/* PBus Ch. 3 PIO config */
#define HPC3_PBUS_CH4_CFGPIO	0x0005d400	/* PBus Ch. 4 PIO config */
#define HPC3_PBUS_CH5_CFGPIO	0x0005d500	/* PBus Ch. 5 PIO config */
#define HPC3_PBUS_CH6_CFGPIO	0x0005d600	/* PBus Ch. 6 PIO config */
#define HPC3_PBUS_CH7_CFGPIO	0x0005d700	/* PBus Ch. 7 PIO config */
#define HPC3_PBUS_CH8_CFGPIO	0x0005d800	/* PBus Ch. 8 PIO config */
#define HPC3_PBUS_CH9_CFGPIO	0x0005d900	/* PBus Ch. 9 PIO config */
#define HPC3_PBUS_CH8_CFGPIO_2	0x0005da00	/* PBus Ch. 8 PIO config */
#define HPC3_PBUS_CH9_CFGPIO_2	0x0005db00	/* PBus Ch. 9 PIO config */
#define HPC3_PBUS_CH8_CFGPIO_3	0x0005dc00	/* PBus Ch. 8 PIO config */
#define HPC3_PBUS_CH9_CFGPIO_3	0x0005dd00	/* PBus Ch. 9 PIO config */
#define HPC3_PBUS_CH8_CFGPIO_4	0x0005de00	/* PBus Ch. 8 PIO config */
#define HPC3_PBUS_CH9_CFGPIO_4	0x0005df00	/* PBus Ch. 9 PIO config */

#define HPC3_PBUS_PROM_WE	0x0005e000	/* PBus boot-prom write
						 * enable register
						 */

#define HPC3_PBUS_PROM_SWAP	0x0005e800	/* PBus boot-prom chip-select
						 * swap register
						 */

#define HPC3_PBUS_GEN_OUT	0x0005f000	/* PBus general-purpose output
						 * register
						 */

#define HPC3_PBUS_BBRAM		0x00060000	/* PBus battery-backed RAM
						 * external registers
						 */

/* HPC1/HPC1.5 differs from HPC3 in several details. */

#define HPC1_HDD_CTL_EOCHAIN	0x80000000	/* End of descriptor chain */
#define HPC1_HDD_CTL_EOPACKET	0x80000000	/* Ethernet: end of packet */
#define HPC1_HDD_CTL_INTR	0x00008000	/* Interrupt when finished */
#define HPC1_HDD_CTL_OWN	0x40000000	/* CPU owns this frame */
#define HPC1_HDD_CTL_BYTECNT(x)	((x) & 0x1fff)	/* Byte count: for ethernet */
#define HPC1_BIGENDIAN		0x000000c0	/* Endianness:5 revision:2 */
#define	HPC1_REVSHIFT		0x00000006	/* Revision rshft */
#define	HPC1_REVMASK		0x00000003	/* Revision mask */
#define HPC1_REV15		0x00000001	/* HPC Revision 1.5 */
#define HPC1_SCSI0_REGS		0x00000088
#define HPC1_SCSI0_REGS_SIZE	0x00000018
#define HPC1_SCSI0_CBP		0x00000004	/* Current buffer ptr */
#define HPC1_SCSI0_NDBP		0x00000008	/* Next descriptor ptr */
#define HPC1_SCSI0_BC		0x00000000	/* DMA byte count & flags */
#define HPC1_SCSI0_CTL		0x0000000c	/* DMA control flags */
#define HPC1_SCSI0_DEV		0x00000014	/* Device DMA FIFO pointer */
#define HPC1_SCSI0_DMACFG	0x00000010	/* DMA configuration */
#define HPC1_SCSI0_GIO		0x00001008	/* GIO DMA FIFO pointer */
#define HPC1_SCSI0_PIOCFG	0x00001014	/* PIO configuration */
#define HPC1_SCSI_DMACTL_RESET  0x01 /* Reset dma channel and ext. controller */
#define HPC1_SCSI_DMACTL_FLUSH  0x02 /* Flush DMA FIFO's */
#define HPC1_SCSI_DMACTL_DIR	0x10 /* DMA direction: 1=dev->mem, 0=mem->dev */
#define HPC1_SCSI_DMACTL_ACTIVE 0x80 /* DMA channel is active */
#define HPC1_ENET_REGS		0x00000000	/* Ethernet registers */
#define HPC1_ENET_REGS_SIZE	0x00000100
#define HPC1_ENET_INTDELAY	0x0000002c	/* Interrupt Delay Count */
#define HPC1_ENET_INTDELAY_OFF	0x01000000	/* Disable Interrupt Delay */
#define HPC1_ENETR_CBP		0x00000054	/* Recv: Current buffer ptr */
#define HPC1_ENETR_NDBP		0x00000050	/* Recv: Next descriptor ptr */
#define HPC1_ENETR_BC		0x00000048	/* Recv: DMA byte cnt/flags */
#define HPC1_ENETR_CTL		0x00000038	/* Recv: DMA control flags */
#define HPC1_ENETR_CTL_ACTIVE	0x00004000	/* DMA channel active? */
#define HPC1_ENETR_RESET	0x0000003c	/* Recv: Ethernet chip reset */
#define HPC1_ENETR_RESET_CH	0x0001		/* Reset controller & chan */
#define HPC1_ENETR_RESET_CLRINT	0x0002		/* Clear channel interrupt */
#define HPC1_ENETR_RESET_LOOPBK	0x0004		/* External loopback enable */
#define HPC1_ENETR_RESET_CLRRBO	0x0008		/* Clear RBO condition (??) */
#define HPC1_ENETX_CBP		0x00000020	/* Xmit: Current buffer ptr */
#define HPC1_ENETX_NDBP		0x00000010	/* Xmit: Next descriptor ptr */
#define HPC1_ENETX_CFXBP	0x00000024	/* Xmit: Current first buf */
#define	HPC1_ENETX_PFXBP	0x00000028	/* Xmit: Prev. first buf */
#define HPC1_ENETX_BC		0x00000014	/* Xmit: DMA byte cnt/flags */
#define HPC1_ENETX_CTL		0x00000034	/* Xmit: DMA control flags */
#define HPC1_ENETX_CTL_ACTIVE	0x00400000
#define HPC1_ENETR_FIFO		0x0002c000	/* Ether recv DMA FIFO */
#define HPC1_ENETR_FIFO_SIZE	0x00001fff	/* Ether recv DMA FIFO size */
#define HPC1_ENETX_FIFO		0x0002e000	/* Ether xmit DMA FIFO */
#define HPC1_ENETX_FIFO_SIZE	0x00001fff	/* Ether xmit DMA FIFO size */
#define HPC1_SCSI0_DEVREGS	0x0000011f	/* (actually 122) */
#define HPC1_ENET_DEVREGS	0x00000100	/* Ethernet chip registers */
#define HPC1_ENET_DEVREGS_SIZE	0x00000020	/* Size of chip registers */
#define HPC1_PBUS_BBRAM		0x00000e00	/* PBus battery-backed RAM */
#define	HPC1_LPT_REGS		0x000000a8	/* LPT HPC Registers */
#define	HPC1_LPT_REGS_SIZE	0x00000018
#define	HPC1_LPT_BC		0x00000000	/* Byte Count */
#define	HPC1_LPT_CBP		0x00000004	/* Current Buffer Ptr */
#define HPC1_LPT_NDBP		0x00000008	/* Next Buffer Ptr */
#define	HPC1_LPT_CTL		0x0000000c	/* DMA Control Flags */
#define HPC1_LPT_DEV		0x00000010	/* DMA Fifo Ptr */
#define HPC1_LPT_DMACFG		0x00000014	/* DMA Configuration */
#define HPC1_LPT_DEVREGS	0x00000132	/* Ext. Parallel Registers */
#define	HPC1_LPT_DEVREGS_SIZE	0x00000001	/* Size of External Registers */

/* AUX regs on the primary HPC */
#define HPC1_AUX_REGS		0x000001bf	/* EEPROM/LED Control (byte) */
#define HPC1_AUX_CONSLED	0x01		/* Console LED */


code:
/*	$OpenBSD: hpcvar.h,v 1.8 2012/05/27 14:27:08 miod Exp $	*/
/*	$NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $	*/

/*
 * Copyright (c) 2001 Rafal K. Boni
 * 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.
 */

/* HPC 1.5/3 differ a bit, thus we need an abstraction layer */

struct hpc_values {
	int		revision;
	uint32_t	scsi0_regs;
	uint32_t	scsi0_regs_size;
	uint32_t	scsi0_cbp;
	uint32_t	scsi0_ndbp;
	uint32_t	scsi0_bc;
	uint32_t	scsi0_ctl;
	uint32_t	scsi0_gio;
	uint32_t	scsi0_dev;
	uint32_t	scsi0_dmacfg;
	uint32_t	scsi0_piocfg;
	uint32_t	scsi1_regs;
	uint32_t	scsi1_regs_size;
	uint32_t	scsi1_cbp;
	uint32_t	scsi1_ndbp;
	uint32_t	scsi1_bc;
	uint32_t	scsi1_ctl;
	uint32_t	scsi1_gio;
	uint32_t	scsi1_dev;
	uint32_t	scsi1_dmacfg;
	uint32_t	scsi1_piocfg;
	uint32_t	enet_regs;
	uint32_t	enet_regs_size;
	uint32_t	enet_intdelay;
	uint32_t	enet_intdelayval;
	uint32_t	enetr_cbp;
	uint32_t	enetr_ndbp;
	uint32_t	enetr_bc;
	uint32_t	enetr_ctl;
	uint32_t	enetr_ctl_active;
	uint32_t	enetr_reset;
	uint32_t	enetr_dmacfg;
	uint32_t	enetr_piocfg;
	uint32_t	enetx_cbp;
	uint32_t	enetx_ndbp;
	uint32_t	enetx_bc;
	uint32_t	enetx_ctl;
	uint32_t	enetx_ctl_active;
	uint32_t	enetx_dev;
	uint32_t	enetr_fifo;
	uint32_t	enetr_fifo_size;
	uint32_t	enetx_fifo;
	uint32_t	enetx_fifo_size;
	uint32_t	enet_devregs;
	uint32_t	enet_devregs_size;
	uint32_t	pbus_fifo;
	uint32_t	pbus_fifo_size;
	uint32_t	pbus_bbram;
	uint32_t	scsi_dma_segs;
	uint32_t	scsi_dma_segs_size;
	uint32_t	scsi_dma_datain_cmd;
	uint32_t	scsi_dma_dataout_cmd;
	uint32_t	scsi_dmactl_flush;
	uint32_t	scsi_dmactl_active;
	uint32_t	scsi_dmactl_reset;
};

struct hpc_attach_args {
	const char		*ha_name;	/* name of device */
	bus_addr_t		 ha_base;	/* address of hpc device */
	bus_addr_t		 ha_devoff;	/* offset of device */
	bus_addr_t		 ha_dmaoff;	/* offset of DMA regs */
	int			 ha_irq;	/* interrupt line */

	bus_space_tag_t		 ha_st;		/* HPC space tag */
	bus_space_handle_t	 ha_sh;		/* HPC space handle XXX */
	bus_dma_tag_t		 ha_dmat;	/* HPC DMA tag */

	struct hpc_values	*hpc_regs;	/* HPC register definitions */
	int			 ha_giofast;	/* GIO bus speed */

	uint8_t			 hpc_eeprom[256];/* HPC eeprom contents */
};

void	*hpc_intr_establish(int, int, int (*)(void *), void *, const char *);
int	 hpc_is_intr_pending(int);
void	 hpc_intr_disable(void *);
void	 hpc_intr_enable(void *);

/*
 * Routines to copy and update HPC DMA descriptors in uncached memory;
 * needed for proper operation on ECC MC systems.
 */
struct hpc_dma_desc;

struct hpc_dma_desc *hpc_read_dma_desc(struct hpc_dma_desc *src,
	    struct hpc_dma_desc *store);
void	hpc_write_dma_desc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src);

extern bus_space_t hpc3bus_tag;