code:
/*	$OpenBSD: sa11x0_var.h,v 1.5 2009/08/22 02:54:50 mk Exp $ */
/*      $NetBSD: sa11x0_var.h,v 1.4 2003/04/14 14:18:41 rjs Exp $        */

/*-
 * Copyright (c) 2001, The NetBSD Foundation, Inc.  All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by IWAMOTO Toshihiro and Ichiro FUKUHARA.
 *
 * 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#ifndef _SA11X0_VAR_H
#define _SA11X0_VAR_H

#include <sys/conf.h>
#include <sys/device.h>

#include <machine/bus.h>

struct sa11x0_softc {
	struct device sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
	bus_space_handle_t sc_gpioh;
	bus_space_handle_t sc_ppch;
	bus_space_handle_t sc_dmach;
	bus_space_handle_t sc_reseth;
	u_int32_t sc_intrmask;
};

/* Attach args all devices */

typedef void *sa11x0_chipset_tag_t;

struct sa11x0_attach_args {
	sa11x0_chipset_tag_t	sa_sc;
	bus_space_tag_t		sa_iot;		/* Bus tag */
	bus_addr_t		sa_addr;	/* i/o address  */
	bus_size_t		sa_size;

	int			sa_intr;
	int			sa_gpio;
};

void *sa11x0_intr_establish(sa11x0_chipset_tag_t, int, int, int,
			    int (*)(void *), void *, const char *);
void sa11x0_intr_disestablish(sa11x0_chipset_tag_t, void *);

#endif /* _SA11X0_VAR_H */


code: src/sys/arch/arm/xscale

path: sys/arch/arm/xscale/CVS/Repository

license: unknown


code:
# $OpenBSD: files.i80321,v 1.4 2007/05/15 05:26:44 miod Exp $
device  iopxs {}: pcibus, bus_space_generic, gpiobus
file	arch/arm/xscale/i80321_space.c			iopxs
file	arch/arm/xscale/i80321_mcu.c			iopxs
file	arch/arm/xscale/i80321.c			iopxs
file	arch/arm/xscale/i80321_pci.c			iopxs

file	arch/arm/xscale/i80321_intr.c			iopxs
file	arch/arm/xscale/i80321_clock.c			iopxs
file	arch/arm/xscale/i80321_mutex.c			iopxs

# I2C controller unit
device	iopiic: i2cbus
attach	iopiic at iopxs with i80321_i2c
file	arch/arm/xscale/i80321_i2c.c			iopiic
file	arch/arm/xscale/iopi2c.c			iopiic


code:
#	$OpenBSD: files.pxa2x0,v 1.24 2014/10/18 12:21:56 miod Exp $
#	$NetBSD: files.pxa2x0,v 1.6 2004/05/01 19:09:14 thorpej Exp $
#
# Configuration info for Intel PXA2[51]0 CPU support
#

file	arch/arm/arm/softintr.c	# Use the generic ARM soft interrupt code.

# PXA2[51]0's integrated peripherals bus.
define	pxaip {[addr=-1], [size=0], [intr=-1], [index=-1]}
device	pxaip
attach	pxaip at mainbus
file	arch/arm/xscale/pxa2x0.c
file	arch/arm/arm/irq_dispatch.S
file	arch/arm/xscale/pxa2x0_space.c
#file	arch/arm/xscale/pxa2x0_freqchg.S
file	arch/arm/xscale/pxa2x0_dma.c

# Cotulla integrated peripherals.

# INTC controller
device	pxaintc
attach	pxaintc at pxaip
file	arch/arm/xscale/pxa2x0_intr.c		pxaintc
file	arch/arm/xscale/pxa2x0_mutex.c		pxaintc
#defflag  opt_pxa2x0_gpio.h		PXAGPIO_HAS_GPION_INTRS

# GPIO controller
device	pxagpio
attach	pxagpio at pxaip
file	arch/arm/xscale/pxa2x0_gpio.c		pxagpio needs-flag

# DMA controller
device	pxadmac
attach	pxadmac at pxaip
file	arch/arm/xscale/pxa2x0_dmac.c		pxadmac needs-flag

# PXA2x0's built-in timer.
device	pxaost
attach	pxaost at pxaip
file	arch/arm/xscale/pxa2x0_clock.c		pxaost

# NS16550 compatible serial ports
attach	com at pxaip with com_pxaip
file	arch/arm/xscale/pxa2x0_com.c		com_pxaip
file	arch/arm/xscale/pxa2x0_a4x_space.c	com_pxaip
file	arch/arm/xscale/pxa2x0_a4x_io.S		com_pxaip

# PXA27x USB Device Controller
device	pxaudc: usbdev
file	arch/arm/xscale/pxa27x_udc.c		pxaudc

# OHCI USB Controller
attach	ohci at pxaip with pxaohci
file	arch/arm/xscale/pxa2x0_ohci.c		pxaohci

# LCD controller
device	lcd: wsemuldisplaydev, rasops16, rasops8, rasops4, rasops_rotation
file	arch/arm/xscale/pxa2x0_lcd.c		lcd needs-flag

# Inter-Integrated Circuit controller
device	i2c {}
file	arch/arm/xscale/pxa2x0_i2c.c		i2c

# Inter-IC Sound controller
device	i2s {}
file	arch/arm/xscale/pxa2x0_i2s.c		i2s

# Power manager and APM emulation
device	apm
file	arch/arm/xscale/pxa2x0_apm.c		apm needs-flag
file	arch/arm/xscale/pxa2x0_apm_asm.S	apm

include	"dev/pcmcia/files.pcmcia"

# PCMCIA controller
device	pxapcic: pcmciabus
file	arch/arm/xscale/pxa2x0_pcic.c		pxapcic

# XXX this is a hack to use dev/pcmcia without fdc.c
device	fdc

# MMC/SD/SDIO controller
device	pxammc: sdmmcbus
file	arch/arm/xscale/pxa2x0_mmc.c		pxammc

# PXA27x keypad
device	pxa27x_kpc: wskbddev
file	arch/arm/xscale/pxa27x_kpc.c		pxa27x_kpc


code:
/*	$OpenBSD: i80321.c,v 1.6 2009/03/30 09:28:12 kettenis Exp $	*/
/*	$NetBSD: i80321.c,v 1.18 2006/02/25 02:28:56 wiz Exp $	*/

/*
 * Copyright (c) 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Autoconfiguration support for the Intel i80321 I/O Processor.
 */

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

#define	_ARM32_BUS_DMA_PRIVATE
#include <machine/bus.h>

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

/*
 * Statically-allocated bus_space structure used to access the
 * i80321's own registers.
 */
struct bus_space i80321_bs_tag;

/*
 * There can be only one i80321, so we keep a global pointer to
 * the softc, so board-specific code can use features of the
 * i80321 without having to have a handle on the softc itself.
 */
struct i80321_softc *i80321_softc;

static int i80321_iopxs_print(void *, const char *);

/* Built-in devices. */
static const struct iopxs_device {
	const char *id_name;
	bus_addr_t id_offset;
	bus_size_t id_size;
} iopxs_devices[] = {
	{ "iopaau",	VERDE_AAU_BASE,		VERDE_AAU_SIZE },
/*	{ "iopdma",	VERDE_DMA_BASE0,	VERDE_DMA_CHSIZE },	*/
/*	{ "iopdma",	VERDE_DMA_BASE1,	VERDE_DMA_CHSIZE },	*/
	{ "iopiic",	VERDE_I2C_BASE0,	VERDE_I2C_CHSIZE },
	{ "iopiic",	VERDE_I2C_BASE1,	VERDE_I2C_CHSIZE },
/*	{ "iopssp",	VERDE_SSP_BASE,		VERDE_SSP_SIZE },	*/
	{ "iopmu",	VERDE_MU_BASE,		VERDE_MU_SIZE },
	{ "iopwdog",	0,			0 },
	{ NULL,		0,			0 }
};

static void i80321_pci_dma_init(struct i80321_softc *);

/* XXX - debug */
/*
 * i80321_attach:
 *
 *	Board-independent attach routine for the i80321.
 */
void
i80321_attach(struct i80321_softc *sc)
{
	struct pcibus_attach_args pba;
	const struct iopxs_device *id;
	struct iopxs_attach_args ia;
	pcireg_t preg;

	i80321_softc = sc;

	/*
	 * Program the Inbound windows.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0,
	    (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0,
	    sc->sc_iwin[0].iwin_xlate);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START, sc->sc_iwin[0].iwin_base_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START + 0x04, sc->sc_iwin[0].iwin_base_hi);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1,
	    (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0);
	/* no xlate for window 1 */

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START + 0x08, sc->sc_iwin[1].iwin_base_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START + 0x0c, sc->sc_iwin[1].iwin_base_hi);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2,
	    (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2,
	    sc->sc_iwin[2].iwin_xlate);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START + 0x10, sc->sc_iwin[2].iwin_base_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_MAPREG_START + 0x14, sc->sc_iwin[2].iwin_base_hi);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3,
	    (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3,
	    sc->sc_iwin[3].iwin_xlate);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi);

	/*
	 * Mask (disable) the ATU interrupt sources.
	 * XXX May want to revisit this if we encounter
	 * XXX an application that wants it.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_ATUIMR,
	    ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST|
	    ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM|
	    ATUIMR_PTAT|ATUIMR_PMPE);

	/*
	 * Program the outbound windows.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_OIOWTVR, sc->sc_ioout_xlate);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi);

	/*
	 * Set up the ATU configuration register.  All we do
	 * right now is enable Outbound Windows.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR,
	    ATUCR_OUT_EN);

	/*
	 * Enable bus mastering, memory access, SERR, and parity
	 * checking on the ATU.
	 */
	preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_COMMAND_STATUS_REG);
	preg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE |
	    PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE;
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
	    PCI_COMMAND_STATUS_REG, preg);

	/* Initialize the bus space tags. */
	i80321_io_bs_init(&sc->sc_pci_iot, sc);
	i80321_mem_bs_init(&sc->sc_pci_memt, sc);

	/* Initialize the DMA tags. */
	i80321_pci_dma_init(sc);
	i80321_local_dma_init(sc);

	/*
	 * Attach all the IOP built-ins.
	 */
	for (id = iopxs_devices; id->id_name != NULL; id++) {
		ia.ia_name = id->id_name;
		ia.ia_st = sc->sc_st;
		ia.ia_sh = sc->sc_sh;
		ia.ia_dmat = &sc->sc_local_dmat;
		ia.ia_offset = id->id_offset;
		ia.ia_size = id->id_size;

		config_found(&sc->sc_dev, &ia, i80321_iopxs_print);
	}

	/*
	 * Attach the PCI bus.
	 */
	preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
	preg = PCIXSR_BUSNO(preg);
	if (preg == 0xff)
		preg = 0;
	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = &sc->sc_pci_iot;
	pba.pba_memt = &sc->sc_pci_memt;
	pba.pba_dmat = &sc->sc_pci_dmat;
	pba.pba_pc = &sc->sc_pci_chipset;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = preg;

	config_found((struct device *)sc, &pba, i80321_iopxs_print);
}

/*
 * i80321_iopxs_print:
 *
 *	Autoconfiguration cfprint routine when attaching
 *	to the "iopxs" device.
 */
static int
i80321_iopxs_print(void *aux, const char *pnp)
{

	return (QUIET);
}

/*
 * i80321_pci_dma_init:
 *
 *	Initialize the PCI DMA tag.
 */
static void
i80321_pci_dma_init(struct i80321_softc *sc)
{
	bus_dma_tag_t dmat = &sc->sc_pci_dmat;
	struct arm32_dma_range *dr = &sc->sc_pci_dma_range;

	dr->dr_sysbase = sc->sc_iwin[2].iwin_xlate;
	dr->dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
	dr->dr_len = sc->sc_iwin[2].iwin_size;

	dmat->_ranges = dr;
	dmat->_nranges = 1;

	dmat->_dmamap_create = _bus_dmamap_create;
	dmat->_dmamap_destroy = _bus_dmamap_destroy;
	dmat->_dmamap_load = _bus_dmamap_load;
	dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf;
	dmat->_dmamap_load_uio = _bus_dmamap_load_uio;
	dmat->_dmamap_load_raw = _bus_dmamap_load_raw;
	dmat->_dmamap_unload = _bus_dmamap_unload;
	dmat->_dmamap_sync = _bus_dmamap_sync;

	dmat->_dmamem_alloc = _bus_dmamem_alloc;
	dmat->_dmamem_free = _bus_dmamem_free;
	dmat->_dmamem_map = _bus_dmamem_map;
	dmat->_dmamem_unmap = _bus_dmamem_unmap;
	dmat->_dmamem_mmap = _bus_dmamem_mmap;
}

/*
 * i80321_local_dma_init:
 *
 *	Initialize the local DMA tag.
 */
void
i80321_local_dma_init(struct i80321_softc *sc)
{
	bus_dma_tag_t dmat = &sc->sc_local_dmat;

	dmat->_ranges = NULL;
	dmat->_nranges = 0;

	dmat->_dmamap_create = _bus_dmamap_create;
	dmat->_dmamap_destroy = _bus_dmamap_destroy;
	dmat->_dmamap_load = _bus_dmamap_load;
	dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf;
	dmat->_dmamap_load_uio = _bus_dmamap_load_uio;
	dmat->_dmamap_load_raw = _bus_dmamap_load_raw;
	dmat->_dmamap_unload = _bus_dmamap_unload;
	dmat->_dmamap_sync = _bus_dmamap_sync;

	dmat->_dmamem_alloc = _bus_dmamem_alloc;
	dmat->_dmamem_free = _bus_dmamem_free;
	dmat->_dmamem_map = _bus_dmamem_map;
	dmat->_dmamem_unmap = _bus_dmamem_unmap;
	dmat->_dmamem_mmap = _bus_dmamem_mmap;
}


code:
/*	$OpenBSD: i80321_clock.c,v 1.10 2015/06/13 07:16:36 jsg Exp $ */

/*
 * Copyright (c) 2006 Dale Rahn <drahn@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/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/time.h>
#include <sys/device.h>
#include <sys/timetc.h>
#include <dev/clock_subr.h>

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

#include <arm/cpufunc.h>

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

#define TIMER_FREQUENCY	200000000	/* 200MHz */

static struct evcount clk_count;
static struct evcount stat_count;
static int clk_irq = 129; /* XXX */
static int stat_irq = 130; /* XXX */

uint32_t nextstatevent;
uint32_t nexttickevent;
uint32_t ticks_per_intr;
uint32_t ticks_per_second;
uint32_t lastnow;
uint32_t statvar, statmin;
int i80321_timer_inited;
static inline u_int32_t tmr0_read(void);
static inline void tmr0_write(u_int32_t val);
static inline u_int32_t tcr0_read(void);
static inline void tcr0_write(u_int32_t val);
static inline u_int32_t trr0_read(void);
static inline void trr0_write(u_int32_t val);
static inline u_int32_t tmr1_read(void);
static inline void tmr1_write(u_int32_t val);
static inline u_int32_t tcr1_read(void);
static inline void tcr1_write(u_int32_t val);
static inline u_int32_t trr1_read(void);
static inline void trr1_write(u_int32_t val);
static inline u_int32_t tisr_read(void);
static inline void tisr_write(u_int32_t val);
int i80321_intr(void *frame);

u_int tcr1_get_timecount(struct timecounter *tc);

static struct timecounter tcr1_timecounter = {
	tcr1_get_timecount, NULL, 0xffffffff, 0, "tcr1", 0, NULL
};

todr_chip_handle_t todr_handle;

/*
 * TMR0 is used in non-reload mode as it is used for both the clock
 * timer and sched timer.
 *
 * The counters on 80321 are count down interrupt on 0, not match
 * register based, so it is not possible to find out how much
 * many interrupts passed while irqs were blocked.
 * also it is not possible to atomically add to the register
 * get get it to precisely fire at a non-fixed interval.
 *
 * To work around this both timers are used, TMR1 is used as a reference
 * clock set to  auto reload with 0xffffffff, however we just ignore the
 * interrupt it would generate. NOTE: does this drop one tick
 * ever wrap? Could the reference timer be used in non-reload mode,
 * where it would just keep counting, and not stop at 0 ?
 *
 * Internally this keeps track of when the next timer should fire
 * and based on that time and the current value of the reference
 * clock a number is written into the timer count register to schedule
 * the next event.
 */

static inline u_int32_t
tmr0_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c0, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
tmr0_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c0, c1, 0" :: "r" (val));
}

static inline u_int32_t
tcr0_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c2, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
tcr0_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c2, c1, 0" :: "r" (val));
}

static inline u_int32_t
trr0_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c4, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
trr0_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c4, c1, 0" :: "r" (val));
}

static inline u_int32_t
tmr1_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c1, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
tmr1_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c1, c1, 0" :: "r" (val));
}

inline u_int32_t
tcr1_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c3, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
tcr1_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c3, c1, 0" :: "r" (val));
}

static inline u_int32_t
trr1_read(void)
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c5, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
trr1_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c5, c1, 0" :: "r" (val));
}

static inline u_int32_t
tisr_read()
{
	u_int32_t ret;
	__asm volatile ("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
	return ret;
}

static inline void
tisr_write(u_int32_t val)
{
	__asm volatile ("mcr p6, 0, %0, c6, c1, 0" :: "r" (val));
}

/* counter counts down not up, so reverse the results by subtracting. */
u_int
tcr1_get_timecount(struct timecounter *tc)
{
	return UINT_MAX - tcr1_read();
}

/*
 * timer 1 is running a timebase counter,
 * ie reload 0xffffffff, reload, interrupt ignored
 * timer 0 will be programmed with the delay until the next
 * event. this is not set for reload
 */
int
i80321_intr(void *frame)
{
	uint32_t now, r;
	uint32_t nextevent;

	tisr_write(TISR_TMR0);
	now = tcr1_read();

#if 0
	if (lastnow < now) {
		/* rollover, remove the missing 'tick'; 1-0xffffffff, not 0- */
		nextstatevent -=1;
		nexttickevent -=1;
	}
#endif
	while ((int32_t) (now - nexttickevent) < 0) {
		nexttickevent -= ticks_per_intr;
		/* XXX - correct nexttickevent? */
		clk_count.ec_count++;
		hardclock(frame);
	}
	while ((int32_t) (now - nextstatevent) < 0) {
		do {
			r = random() & (statvar -1);
		} while (r == 0); /* random == 0 not allowed */
		nextstatevent -= statmin + r;
		/* XXX - correct nextstatevent? */
		stat_count.ec_count++;
		statclock(frame);
	}
	if ((now - nexttickevent) < (now - nextstatevent))
		nextevent = now - nexttickevent;
	else
		nextevent = now - nextstatevent;
	if (nextevent < 10 /* XXX */)
		nextevent = 10;
	if (nextevent > ticks_per_intr) {
		/*
		 * If interrupts are blocked too long, like during
		 * the root prompt or ddb, the timer can roll over,
		 * this will allow the system to continue to run
		 * even if time is lost.
		 */
		nextevent = ticks_per_intr;
		nexttickevent = now;
		nextstatevent = now;
	}

	tcr0_write(nextevent);
	tmr0_write(TMRx_ENABLE|TMRx_PRIV|TMRx_CSEL_CORE);

	lastnow = now;

	return 1;
}

void
cpu_initclocks()
{
	uint32_t now;
	struct timeval rtctime;
	time_t	first_sec, sec;
	u_int32_t first_tb, second_tb;

	/* would it make sense to have this be 100/1000 to round nicely? */
	/* 100/1000 or 128/1024 ? */
	stathz = 100;
	profhz = 1000;

	ticks_per_second = 200 * 1000000; /* 200 MHz */

	if (todr_handle != NULL && todr_gettime(todr_handle, &rtctime) == 0) {
		int psw;
		int new_tps;
		int tps_diff;

		psw = disable_interrupts(I32_bit);

		first_sec =  rtctime.tv_sec;
		do {
			first_tb = tcr1_read();
			todr_gettime(todr_handle, &rtctime);
			sec = rtctime.tv_sec;
		} while (sec == first_sec);
		first_sec = sec;
		do {
			second_tb = tcr1_read();
			todr_gettime(todr_handle, &rtctime);
			sec = rtctime.tv_sec;
		} while (sec == first_sec);

		new_tps = first_tb - second_tb;
		tps_diff = ticks_per_second - new_tps;
		if (tps_diff < 0)
			tps_diff = -tps_diff;

		/*
		 * only if the calculated time is more than 0.1% use the
		 * new calculate time. Otherwise system with accurate clocks
		 * can be penalized. (error in measurement)
		 */
		if (tps_diff > ticks_per_second/1000)
			ticks_per_second = new_tps;

		restore_interrupts(psw);
	}

	setstatclockrate(stathz);

	ticks_per_intr = ticks_per_second / hz;

	evcount_attach(&clk_count, "clock", &clk_irq);
	evcount_attach(&stat_count, "stat", &stat_irq);

	(void) i80321_intr_establish(ICU_INT_TMR0, IPL_CLOCK, i80321_intr,
	    NULL, NULL);

	now = 0xffffffff;
	nextstatevent = now - ticks_per_intr;
	nexttickevent = now - ticks_per_intr;

	tcr1_write(now);
	trr1_write(now);
	tmr1_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_PRIV|TMRx_CSEL_CORE);

	tcr0_write(now); /* known big value */
	tmr0_write(TMRx_ENABLE|TMRx_PRIV|TMRx_CSEL_CORE);
	tcr0_write(ticks_per_intr);

	tcr1_timecounter.tc_frequency = ticks_per_second;
	tc_init(&tcr1_timecounter);

	i80321_timer_inited = 1;
}

void
delay(u_int usecs)
{
	u_int32_t clock, oclock, delta, delaycnt;
	volatile int j;
	int csec, usec;

		csec = usecs / 10000;
		usec = usecs % 10000;

		delaycnt = (TIMER_FREQUENCY / 100) * csec +
		    (TIMER_FREQUENCY / 100) * usec / 10000;

	if (delaycnt <= 1) /* delay too short spin for a bit */
		for (j = 100; j > 0; j--)
			;

	if (i80321_timer_inited == 0) {
		/* clock isn't initialized yet */
		for (; usecs > 0; usecs--)
			for (j = 100; j > 0; j--)
				;
		return;
	}

	oclock = tcr1_read();

	while(1) {
		clock = tcr1_read();
		/* timer counts down, not up so old - new */
		delta = oclock - clock;
		if (delta > delaycnt)
			break;
	}
}

void
setstatclockrate(int newhz)
{
	int minint, statint;
	int s;

	s = splclock();

	statint = ticks_per_second / newhz;
	/* calculate largest 2^n which is smaller that just over half statint */
	statvar = 0x40000000; /* really big power of two */
	minint = statint / 2 + 100;
	while (statvar > minint)
		statvar >>= 1;

	statmin = statint - (statvar >> 1);

	splx(s);

	/*
	 * XXX this allows the next stat timer to occur then it switches
	 * to the new frequency. Rather than switching instantly.
	 */
}

void
i80321_calibrate_delay(void)
{

	tmr1_write(0);			/* stop timer */
	tisr_write(TISR_TMR1);		/* clear interrupt */
	trr1_write(0xffffffff);	/* reload value */
	tcr1_write(0xffffffff);	/* current value */

	tmr1_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_PRIV|TMRx_CSEL_CORE);
}

/*
 * inittodr:
 *
 *	Initialize time from the time-of-day register.
 */
#define	MINYEAR		2003	/* minimum plausible year */
void
inittodr(time_t base)
{
	time_t deltat;
	struct timeval rtctime;
	struct timespec ts;
	int badbase;

	if (base < (MINYEAR - 1970) * SECYR) {
		printf("WARNING: preposterous time in file system\n");
		/* read the system clock anyway */
		base = (MINYEAR - 1970) * SECYR;
		badbase = 1;
	} else
		badbase = 0;

	if (todr_handle == NULL ||
	    todr_gettime(todr_handle, &rtctime) != 0 ||
	    rtctime.tv_sec == 0) {
		/*
		 * Believe the time in the file system for lack of
		 * anything better, resetting the TODR.
		 */
		rtctime.tv_sec = base;
		rtctime.tv_usec = 0;
		if (todr_handle != NULL && !badbase) {
			printf("WARNING: preposterous clock chip time\n");
			resettodr();
		}
		goto bad;
	}

	ts.tv_sec = rtctime.tv_sec;
	ts.tv_nsec = rtctime.tv_usec * 1000;
	tc_setclock(&ts);

	if (!badbase) {
		/*
		 * See if we gained/lost two or more days; if
		 * so, assume something is amiss.
		 */
		deltat = rtctime.tv_sec - base;
		if (deltat < 0)
			deltat = -deltat;
		if (deltat < 2 * SECDAY)
			return;		/* all is well */

		printf("WARNING: clock %s %ld days\n",
		    rtctime.tv_sec < base ? "lost" : "gained",
		    (long)deltat / SECDAY);
	}
 bad:
	printf("WARNING: CHECK AND RESET THE DATE!\n");
}

/*
 * resettodr:
 *
 *	Reset the time-of-day register with the current time.
 */
void
resettodr(void)
{
	struct timeval rtctime;

	if (time_second == 1)
		return;

	microtime(&rtctime);

	if (todr_handle != NULL &&
	   todr_settime(todr_handle, &rtctime) != 0)
		printf("resettodr: failed to set time\n");
}


code:
/*	$OpenBSD: i80321_i2c.c,v 1.3 2009/03/27 16:02:41 oga Exp $	*/
/*	$NetBSD: i80321_i2c.c,v 1.2 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Intel i80321 I/O Processor I2C Controller Unit support.
 */

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

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

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

#include <dev/i2c/i2cvar.h>

#include <arm/xscale/iopi2creg.h>
#include <arm/xscale/iopi2cvar.h>

int i80321_i2c_match(struct device *parent, void *v, void *aux);
void i80321_i2c_attach(struct device *parent, struct device *self, void *aux);

struct cfattach i80321_i2c_ca = {
	sizeof(struct iopiic_softc), i80321_i2c_match, i80321_i2c_attach
};

int
i80321_i2c_match(struct device *parent, void *v, void *aux)
{
	struct cfdata *cf = v;
	struct iopxs_attach_args *ia = aux;

	/* XXX thecus will reboot if iopiic1 attaches */
	if (ia->ia_offset == VERDE_I2C_BASE1)
		return 0;

	if (strcmp(cf->cf_driver->cd_name, ia->ia_name) == 0)
		return (1);

	return (0);
}

void
i80321_i2c_attach(struct device *parent, struct device *self, void *aux)
{
	struct iopiic_softc *sc = (void *) self;
	struct iopxs_attach_args *ia = aux;
	int error;
#ifdef LATER
	uint8_t gpio_bits;
#endif

	printf(": I2C controller\n");

	sc->sc_st = ia->ia_st;
	if ((error = bus_space_subregion(sc->sc_st, ia->ia_sh,
					 ia->ia_offset, ia->ia_size,
					 &sc->sc_sh)) != 0) {
		printf("%s: unable to subregion registers, error = %d\n",
		    sc->sc_dev.dv_xname, error);
		return;
	}

#ifdef LATER
	gpio_bits = (ia->ia_offset == VERDE_I2C_BASE0) ?
	    (1U << 7) | (1U << 6) : (1U << 5) | (1U << 4);
	i80321_gpio_set_val(gpio_bits, 0);
	i80321_gpio_set_direction(gpio_bits, 0);
#endif

	/* XXX Reset the I2C unit? */

	rw_init(&sc->sc_buslock, "iopiiclk");

	/* XXX We don't currently use interrupts.  Fix this some day. */
#if 0
	sc->sc_ih = i80321_intr_establish((ia->ia_offset == VERDE_I2C_BASE0) ?
	    ICU_INT_I2C0 : ICU_INT_I2C1, IPL_BIO, iopiic_intr, sc);
	if (sc->sc_ih == NULL) {
		aprint_error("%s: unable to establish interrupt handler\n",
		    sc->sc_dev.dv_xname);
		return;
	}
#endif

	/*
	 * Enable the I2C unit as a master.
	 * No, we do not support slave mode.
	 */
	sc->sc_icr = IIC_ICR_GCD | IIC_ICR_UE | IIC_ICR_SCLE;
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR, 0);
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ISAR, 0);
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR, sc->sc_icr);

	iopiic_attach(sc);
}


code:
/* $OpenBSD: i80321_intr.c,v 1.16 2014/04/03 10:17:34 mpi Exp $ */

/*
 * Copyright (c) 2006 Dale Rahn <drahn@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/malloc.h>
#include <sys/evcount.h>

#include <uvm/uvm_extern.h>

#include <machine/intr.h>

#include <arm/cpufunc.h>
#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

/*
 * autoconf glue
 */
int		i80321intc_match(struct device *, void *, void *);
void		i80321intc_attach(struct device *, struct device *, void *);

/* internal functions */
static void	i80321intc_write_intctl(uint32_t mask);
void		i80321intc_write_steer(uint32_t mask);
uint32_t	i80321intc_read_intsrc(void);
void		i80321intc_calc_mask(void);
void		i80321intc_init(void);
void		i80321intc_intr_init(void);
static void	i80321intc_setipl(int new);
void		i80321intc_do_pending(void);

uint32_t	i80321intc_imask[NIPL];
uint32_t	i80321intc_smask[NIPL];

#define SI_TO_IRQBIT(x)	(1 << (x))

volatile int current_ipl_level;
volatile int softint_pending;

struct cfattach i80321intc_ca = {
	sizeof(struct device), i80321intc_match, i80321intc_attach
};

struct cfdriver i80321intc_cd = {
	NULL, "i80321intc", DV_DULL
};

int i80321intc_attached = 0;

int
i80321intc_match(struct device *parent, void *v, void *aux)
{
	if (i80321intc_attached == 0)
		return 1;

	i80321intc_attached = 1;
	return 0;
}

void
i80321intc_attach(struct device *parent, struct device *self, void *args)
{
	i80321intc_init();
}

static inline void
i80321intc_write_intctl(uint32_t mask)
{
	__asm__ volatile ("mcr p6, 0, %0, c0, c0, 0" : : "r" (mask));
}

void
i80321intc_write_steer(uint32_t mask)
{
	__asm__ volatile ("mcr p6, 0, %0, c4, c0, 0" : : "r" (mask));
}

uint32_t
i80321intc_read_intsrc(void)
{
	uint32_t mask;
	__asm__ volatile ("mrc p6, 0, %0, c8, c0, 0" : "=r" (mask));
	return mask;
}

static inline void
i80321intc_setipl(int new)
{
	int psw;

	psw = disable_interrupts(I32_bit);
	current_ipl_level = new;
	i80321intc_write_intctl(i80321intc_imask[new]);
	restore_interrupts(psw);
}

struct intrq i80321_handler[NIRQ];

/*
 * Recompute the irq mask bits.
 * Must be called with interrupts disabled.
 */
void
i80321intc_calc_mask(void)
{
	int irq;
	struct intrhand *ih;
	int i;

	for (irq = 0; irq < NIRQ; irq++) {
		int i;
		int max = IPL_NONE;
		int min = IPL_HIGH;
		TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
			if (ih->ih_ipl > max)
				max = ih->ih_ipl;

			if (ih->ih_ipl < min)
				min = ih->ih_ipl;
		}

		i80321_handler[irq].iq_irq = max;

		if (max == IPL_NONE)
			min = IPL_NONE; /* interrupt not enabled */
#if 0
		printf("irq %d: min %x max %x\n", irq, min, max);
#endif

		/* Enable interrupts at lower levels */
		for (i = 0; i < min; i++)
			i80321intc_imask[i] |= (1 << irq);
		/* Disable interrupts at upper levels */
		for (;i <= IPL_HIGH; i++)
			i80321intc_imask[i] &= ~(1 << irq);
	}
	/* initialize soft interrupt mask */
	for (i = IPL_NONE; i <= IPL_HIGH; i++)  {
		i80321intc_smask[i] = 0;
		if (i < IPL_SOFT)
			i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
		if (i < IPL_SOFTCLOCK)
			i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
		if (i < IPL_SOFTNET)
			i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
		if (i < IPL_SOFTTTY)
			i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTTTY);
#if 0
		printf("mask[%d]: %x %x\n", i, i80321intc_smask[i],
		    i80321intc_imask[i]);
#endif
	}

	i80321intc_setipl(current_ipl_level);
}

void
i80321intc_do_pending(void)
{
	static int processing = 0;
	int oldirqstate, spl_save;

	oldirqstate = disable_interrupts(I32_bit);

	spl_save = current_ipl_level;

	if (processing == 1) {
		restore_interrupts(oldirqstate);
		return;
	}

#define DO_SOFTINT(si, ipl) \
	if ((softint_pending & i80321intc_smask[current_ipl_level]) &	\
	    SI_TO_IRQBIT(si)) {						\
		softint_pending &= ~SI_TO_IRQBIT(si);			\
		if (current_ipl_level < ipl)				\
			i80321intc_setipl(ipl);				\
		restore_interrupts(oldirqstate);			\
		softintr_dispatch(si);					\
		oldirqstate = disable_interrupts(I32_bit);		\
		i80321intc_setipl(spl_save);				\
	}

	do {
		DO_SOFTINT(SI_SOFTTTY, IPL_SOFTTTY);
		DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
		DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
		DO_SOFTINT(SI_SOFT, IPL_SOFT);
	} while (softint_pending & i80321intc_smask[current_ipl_level]);

	processing = 0;
	restore_interrupts(oldirqstate);
}

void
splx(int new)
{
	i80321intc_setipl(new);

	if (softint_pending & i80321intc_smask[current_ipl_level])
		i80321intc_do_pending();
}

int
_spllower(int new)
{
	int old = current_ipl_level;
	splx(new);
	return (old);
}

int
_splraise(int new)
{
	int old;
	old = current_ipl_level;

	/*
	 * setipl must always be called because there is a race window
	 * where the variable is updated before the mask is set
	 * an interrupt occurs in that window without the mask always
	 * being set, the hardware might not get updated on the next
	 * splraise completely messing up spl protection.
	 */
	if (old > new)
		new = old;

	i80321intc_setipl(new);

	return (old);
}

void
_setsoftintr(int si)
{
	int oldirqstate;

        oldirqstate = disable_interrupts(I32_bit);
	softint_pending |= SI_TO_IRQBIT(si);
	restore_interrupts(oldirqstate);

	/* Process unmasked pending soft interrupts. */
	if (softint_pending & i80321intc_smask[current_ipl_level])
		i80321intc_do_pending();
}

/*
 * i80321_icu_init:
 *
 *	Initialize the i80321 ICU.  Called early in bootstrap
 *	to make sure the ICU is in a pristine state.
 */
void
i80321intc_intr_init(void)
{
	i80321intc_write_intctl(0);

	i80321intc_write_steer(0);
}

/*
 * i80321_intr_init:
 *
 *      Initialize the rest of the interrupt subsystem, making it
 *      ready to handle interrupts from devices.
 */
void
i80321intc_init(void)
{
	struct intrq *iq;
	int i;

	for (i = 0; i < NIRQ; i++) {
		iq = &i80321_handler[i];
		TAILQ_INIT(&iq->iq_list);
	}

	i80321intc_calc_mask();

	/* Enable IRQs (don't yet use FIQs). */
	enable_interrupts(I32_bit);
}

void *
i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
    const char *name)
{
	struct intrq *iq;
	struct intrhand *ih;
	uint32_t oldirqstate;

	if (irq < 0 || irq > NIRQ)
		panic("i80321_intr_establish: IRQ %d out of range", irq);

	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
	if (ih == NULL)
		return (NULL);

	ih->ih_func = func;
	ih->ih_arg = arg;
	ih->ih_ipl = ipl;
	ih->ih_name = name;
	ih->ih_irq = irq;

	iq = &i80321_handler[irq];

	if (name != NULL)
		evcount_attach(&ih->ih_count, name, &ih->ih_irq);

	/* All IOP321 interrupts are level-triggered. */
	iq->iq_ist = IST_LEVEL;

	oldirqstate = disable_interrupts(I32_bit);

	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);

	i80321intc_calc_mask();

	restore_interrupts(oldirqstate);

	return (ih);
}

void
i80321_intr_disestablish(void *cookie)
{
	struct intrhand *ih = cookie;
	struct intrq *iq = &i80321_handler[ih->ih_irq];
	int oldirqstate;

	oldirqstate = disable_interrupts(I32_bit);

	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
	if (ih->ih_name != NULL)
		evcount_detach(&ih->ih_count);

	i80321intc_calc_mask();

	restore_interrupts(oldirqstate);
}

void
i80321_irq_handler(void *arg)
{
	struct clockframe *frame = arg;
	uint32_t hwpend;
	int irq;
	int saved_spl_level;
	struct intrhand *ih;

	saved_spl_level = current_ipl_level;

	/* get pending IRQs */
	hwpend = i80321intc_read_intsrc();

	while ((irq = find_first_bit(hwpend)) >= 0) {
		/* XXX: Should we handle IRQs in priority order? */

		/* raise spl to stop interrupts of lower priorities */
		if (saved_spl_level < i80321_handler[irq].iq_irq)
			i80321intc_setipl(i80321_handler[irq].iq_irq);

		/* Enable interrupt */
		enable_interrupts(I32_bit);
		TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
			if ((ih->ih_func)( ih->ih_arg == 0
			    ? frame : ih->ih_arg))
				ih->ih_count.ec_count++;
		}
		/* Disable interrupt */
		disable_interrupts(I32_bit);
		hwpend &= ~(1<<irq);
	}
	uvmexp.intrs++;

	/* restore spl to that was when this interrupt happen */
	i80321intc_setipl(saved_spl_level);

	if(softint_pending & i80321intc_smask[current_ipl_level])
		i80321intc_do_pending();
}

#ifdef DIAGNOSTIC
void
i80321_splassert_check(int wantipl, const char *func)
{
	int oldipl = current_ipl_level;

	if (oldipl < wantipl) {
		splassert_fail(wantipl, oldipl, func);
		/*
		 * If the splassert_ctl is set to not panic, raise the ipl
		 * in a feeble attempt to reduce damage.
		 */
		i80321intc_setipl(wantipl);
	}
}
#endif


code:
/*	$OpenBSD: i80321_mcu.c,v 1.2 2006/05/29 17:27:31 drahn Exp $	*/
/*	$NetBSD: i80321_mcu.c,v 1.3 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Intel i80321 I/O Processor memory controller support.
 */

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

#include <machine/bus.h>

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

/*
 * i80321_sdram_bounds:
 *
 *	Retrieve the start and size of SDRAM.
 */
void
i80321_sdram_bounds(bus_space_tag_t st, bus_space_handle_t sh,
    paddr_t *start, psize_t *size)
{
	uint32_t sdbr, sbr0, sbr1;
	uint32_t bank0, bank1;

	sdbr = bus_space_read_4(st, sh, MCU_SDBR);
	sbr0 = bus_space_read_4(st, sh, MCU_SBR0);
	sbr1 = bus_space_read_4(st, sh, MCU_SBR1);

#ifdef VERBOSE_INIT_ARM
	printf("i80321: SBDR = 0x%08x SBR0 = 0x%08x SBR1 = 0x%08x\n",
	    sdbr, sbr0, sbr1);
#endif

	*start = sdbr;

	sdbr = (sdbr >> 25) & 0x1f;

	sbr0 &= 0x3f;
	sbr1 &= 0x3f;

	bank0 = (sbr0 - sdbr) << 25;
	bank1 = (sbr1 - sbr0) << 25;

#ifdef VERBOSE_INIT_ARM
	printf("i80321: BANK0 = 0x%08x BANK1 = 0x%08x\n", bank0, bank1);
#endif

	*size = bank0 + bank1;
}


code:
/*	$OpenBSD: i80321_mutex.c,v 1.3 2009/08/13 19:39:46 deraadt Exp $	*/

/*
 * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``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/mutex.h>
#include <sys/systm.h>

#include <machine/intr.h>

#ifdef MULTIPROCESSOR
#error This code needs work
#endif

/*
 * Single processor systems don't need any mutexes, but they need the spl
 * raising semantics of the mutexes.
 */
void
mtx_init(struct mutex *mtx, int wantipl)
{
	mtx->mtx_oldipl = 0;
	mtx->mtx_wantipl = wantipl;
	mtx->mtx_lock = 0;
}

void
mtx_enter(struct mutex *mtx)
{
	if (mtx->mtx_wantipl != IPL_NONE)
		mtx->mtx_oldipl = _splraise(mtx->mtx_wantipl);

	MUTEX_ASSERT_UNLOCKED(mtx);
	mtx->mtx_lock = 1;
}

int
mtx_enter_try(struct mutex *mtx)
{
	if (mtx->mtx_wantipl != IPL_NONE)
		mtx->mtx_oldipl = _splraise(mtx->mtx_wantipl);

	MUTEX_ASSERT_UNLOCKED(mtx);
	mtx->mtx_lock = 1;

	return 1;
}

void
mtx_leave(struct mutex *mtx)
{
	MUTEX_ASSERT_LOCKED(mtx);
	mtx->mtx_lock = 0;
	if (mtx->mtx_wantipl != IPL_NONE)
		splx(mtx->mtx_oldipl);
}


code:
/*	$OpenBSD: i80321_pci.c,v 1.4 2010/12/04 17:06:31 miod Exp $	*/
/*	$NetBSD: i80321_pci.c,v 1.7 2005/12/15 01:44:00 briggs Exp $	*/

/*
 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * PCI configuration support for i80321 I/O Processor chip.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

#include <dev/pci/ppbreg.h>

#include "pci.h"

void		i80321_pci_attach_hook(struct device *, struct device *,
		    struct pcibus_attach_args *);
int		i80321_pci_bus_maxdevs(void *, int);
pcitag_t	i80321_pci_make_tag(void *, int, int, int);
void		i80321_pci_decompose_tag(void *, pcitag_t, int *, int *,
		    int *);
int		i80321_pci_conf_size(void *, pcitag_t);
pcireg_t	i80321_pci_conf_read(void *, pcitag_t, int);
void		i80321_pci_conf_write(void *, pcitag_t, int, pcireg_t);

#define	PCI_CONF_LOCK(s)	(s) = disable_interrupts(I32_bit)
#define	PCI_CONF_UNLOCK(s)	restore_interrupts((s))

void
i80321_pci_init(pci_chipset_tag_t pc, void *cookie)
{
#if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
	struct i80321_softc *sc = cookie;
	struct extent *ioext, *memext;
	uint32_t busno;
#endif

	pc->pc_conf_v = cookie;
	pc->pc_attach_hook = i80321_pci_attach_hook;
	pc->pc_bus_maxdevs = i80321_pci_bus_maxdevs;
	pc->pc_make_tag = i80321_pci_make_tag;
	pc->pc_decompose_tag = i80321_pci_decompose_tag;
	pc->pc_conf_size = i80321_pci_conf_size;
	pc->pc_conf_read = i80321_pci_conf_read;
	pc->pc_conf_write = i80321_pci_conf_write;

#if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
	/*
	 * Configure the PCI bus.
	 *
	 * XXX We need to revisit this.  We only configure the Secondary
	 * bus (and its children).  The bus configure code needs changes
	 * to support how the busses are arranged on this chip.  We also
	 * need to only configure devices in the private device space on
	 * the Secondary bus.
	 */

	busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
	busno = PCIXSR_BUSNO(busno);
	if (busno == 0xff)
		busno = 0;

	ioext  = extent_create("pciio",
	    sc->sc_ioout_xlate + sc->sc_ioout_xlate_offset,
	    sc->sc_ioout_xlate + VERDE_OUT_XLATE_IO_WIN_SIZE - 1,
	    M_DEVBUF, NULL, 0, EX_NOWAIT);
	memext = extent_create("pcimem", sc->sc_owin[0].owin_xlate_lo,
	    sc->sc_owin[0].owin_xlate_lo + VERDE_OUT_XLATE_MEM_WIN_SIZE - 1,
	    M_DEVBUF, NULL, 0, EX_NOWAIT);

	aprint_normal("%s: configuring PCI bus\n", sc->sc_dev.dv_xname);
	pci_configure_bus(pc, ioext, memext, NULL, busno, arm_dcache_align);

	extent_destroy(ioext);
	extent_destroy(memext);
#endif
}

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

	/* Nothing to do. */
}

int
i80321_pci_bus_maxdevs(void *v, int busno)
{

	return (32);
}

pcitag_t
i80321_pci_make_tag(void *v, int b, int d, int f)
{

	return ((b << 16) | (d << 11) | (f << 8));
}

void
i80321_pci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
{

	if (bp != NULL)
		*bp = (tag >> 16) & 0xff;
	if (dp != NULL)
		*dp = (tag >> 11) & 0x1f;
	if (fp != NULL)
		*fp = (tag >> 8) & 0x7;
}

struct pciconf_state {
	uint32_t ps_addr_val;

	int ps_b, ps_d, ps_f;
};

static int
i80321_pci_conf_setup(struct i80321_softc *sc, pcitag_t tag, int offset,
    struct pciconf_state *ps)
{
	uint32_t busno;

	i80321_pci_decompose_tag(sc, tag, &ps->ps_b, &ps->ps_d, &ps->ps_f);

	busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
	busno = PCIXSR_BUSNO(busno);
	if (busno == 0xff)
		busno = 0;

	/*
	 * If the bus # is the same as our own, then use Type 0 cycles,
	 * else use Type 1.
	 *
	 * XXX We should filter out all non-private devices here!
	 * XXX How does private space interact with PCI-PCI bridges?
	 */
	if (ps->ps_b == busno) {
		if (ps->ps_d > (31 - 16))
			return (1);
		/*
		 * NOTE: PCI-X requires that devices update their
		 * PCIXSR on every config write with the device number
		 * specified in AD[15:11].  If we don't set this field,
		 * each device could end of thinking it is at device 0,
		 * which can cause a number of problems.  Doing this
		 * unconditionally should be OK when only PCI devices
		 * are present.
		 */
		ps->ps_addr_val = (1U << (ps->ps_d + 16)) |
		    (ps->ps_d << 11) | (ps->ps_f << 8) | offset;
	} else {
		/* The tag is already in the correct format. */
		ps->ps_addr_val = tag | offset | 1;
	}

	return (0);
}

int
i80321_pci_conf_size(void *v, pcitag_t tag)
{
	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
i80321_pci_conf_read(void *v, pcitag_t tag, int offset)
{
	struct i80321_softc *sc = v;
	struct pciconf_state ps;
	vaddr_t va;
	uint32_t isr;
	pcireg_t rv;
	u_int s;

	if (i80321_pci_conf_setup(sc, tag, offset, &ps))
		return ((pcireg_t) -1);

	PCI_CONF_LOCK(s);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCAR,
	    ps.ps_addr_val);

	va = (vaddr_t) bus_space_vaddr(sc->sc_st, sc->sc_atu_sh);
	if (badaddr_read((void *) (va + ATU_OCCDR), sizeof(rv), &rv)) {
		isr = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUISR);
		bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUISR,
		    isr & (ATUISR_P_SERR_DET|ATUISR_PMA|ATUISR_PTAM|
			   ATUISR_PTAT|ATUISR_PMPE));
#if 0
		printf("conf_read: %d/%d/%d bad address\n",
		    ps.ps_b, ps.ps_d, ps.ps_f);
#endif
		rv = (pcireg_t) -1;
	}

	PCI_CONF_UNLOCK(s);

#if 0
	if (rv != 0xffffffff)
		printf("conf read %x %x %x %x: %x\n",
		    ps.ps_b, ps.ps_d, ps.ps_f, offset, rv);
#endif

	return (rv);
}

void
i80321_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
{
	struct i80321_softc *sc = v;
	struct pciconf_state ps;
	u_int s;

	if (i80321_pci_conf_setup(sc, tag, offset, &ps))
		return;

	PCI_CONF_LOCK(s);

	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCAR,
	    ps.ps_addr_val);
	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCDR, val);

	PCI_CONF_UNLOCK(s);
}


code:
/*	$OpenBSD: i80321_space.c,v 1.5 2014/11/16 12:30:56 deraadt Exp $	*/
/*	$NetBSD: i80321_space.c,v 1.9 2005/11/24 13:08:32 yamt Exp $	*/

/*
 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * bus_space functions for i80321 I/O Processor.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/bus.h>

#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>

/* Prototypes for all the bus_space structure functions */
bs_protos(i80321);
bs_protos(i80321_io);
bs_protos(i80321_mem);
bs_protos(generic);
bs_protos(generic_armv4);
bs_protos(bs_notimpl);

/*
 * Template bus_space -- copied, and the bits that are NULL are
 * filled in.
 */
const struct bus_space i80321_bs_tag_template = {
	/* cookie */
	(void *) 0,

	/* mapping/unmapping */
	i80321_bs_map,
	i80321_bs_unmap,
	i80321_bs_subregion,

	/* allocation/deallocation */
	NULL,
	NULL,

	/* get kernel virtual address */
	i80321_bs_vaddr,

	/* mmap */
	i80321_bs_mmap,

	/* barrier */
	i80321_bs_barrier,

	/* read (single) */
	generic_bs_r_1,
	generic_armv4_bs_r_2,
	generic_bs_r_4,
	bs_notimpl_bs_r_8,

	/* read multiple */
	generic_bs_rm_1,
	generic_armv4_bs_rm_2,
	generic_bs_rm_4,
	bs_notimpl_bs_rm_8,

	/* read region */
	generic_bs_rr_1,
	generic_armv4_bs_rr_2,
	generic_bs_rr_4,
	bs_notimpl_bs_rr_8,

	/* write (single) */
	generic_bs_w_1,
	generic_armv4_bs_w_2,
	generic_bs_w_4,
	bs_notimpl_bs_w_8,

	/* write multiple */
	generic_bs_wm_1,
	generic_armv4_bs_wm_2,
	generic_bs_wm_4,
	bs_notimpl_bs_wm_8,

	/* write region */
	generic_bs_wr_1,
	generic_armv4_bs_wr_2,
	generic_bs_wr_4,
	bs_notimpl_bs_wr_8,

	/* set multiple */
	bs_notimpl_bs_sm_1,
	bs_notimpl_bs_sm_2,
	bs_notimpl_bs_sm_4,
	bs_notimpl_bs_sm_8,

	/* set region */
	bs_notimpl_bs_sr_1,
	generic_armv4_bs_sr_2,
	generic_bs_sr_4,
	bs_notimpl_bs_sr_8,

	/* copy */
	bs_notimpl_bs_c_1,
	generic_armv4_bs_c_2,
	bs_notimpl_bs_c_4,
	bs_notimpl_bs_c_8,
};

void
i80321_bs_init(bus_space_tag_t bs, void *cookie)
{

	*bs = i80321_bs_tag_template;
	bs->bs_cookie = cookie;
}

void
i80321_io_bs_init(bus_space_tag_t bs, void *cookie)
{

	*bs = i80321_bs_tag_template;
	bs->bs_cookie = cookie;

	bs->bs_map = i80321_io_bs_map;
	bs->bs_unmap = i80321_io_bs_unmap;
	bs->bs_alloc = i80321_io_bs_alloc;
	bs->bs_free = i80321_io_bs_free;

	bs->bs_vaddr = i80321_io_bs_vaddr;
}

void
i80321_mem_bs_init(bus_space_tag_t bs, void *cookie)
{

	*bs = i80321_bs_tag_template;
	bs->bs_cookie = cookie;

	bs->bs_map = i80321_mem_bs_map;
	bs->bs_unmap = i80321_mem_bs_unmap;
	bs->bs_alloc = i80321_mem_bs_alloc;
	bs->bs_free = i80321_mem_bs_free;

	bs->bs_mmap = i80321_mem_bs_mmap;
}

int
i80321_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
    bus_space_handle_t *bshp)
{
	const struct pmap_devmap *pd;
	paddr_t startpa, endpa, pa, pagecnt;
	vaddr_t va;
	pt_entry_t *pte;

	if ((pd = pmap_devmap_find_pa(bpa, size)) != NULL) {
		/* Device was statically mapped. */
		*bshp = pd->pd_va + (bpa - pd->pd_pa);
		return (0);
	}

#if 0
printf("i80321_bs_map bpa %x, size %x flag %x\n", bpa, size, flag);
#endif
	endpa = round_page(bpa + size);
	startpa = trunc_page(bpa);
	pagecnt = endpa - startpa;

	va = uvm_km_valloc(kernel_map, endpa - startpa);
	if (va == 0)
		return(ENOMEM);
#if 0
printf("i80321_bs_map va %x pa %x, endpa %x, sz %x\n", va, startpa,
    endpa, endpa-startpa);
#endif

	*bshp = (bus_space_handle_t)(va + (bpa - startpa));

	for (pa = startpa; pagecnt > 0;
	    pa += PAGE_SIZE, va += PAGE_SIZE, pagecnt -= PAGE_SIZE) {
		pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE);
		if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0) {
			pte = vtopte(va);
			*pte &= ~L2_S_CACHE_MASK;
			PTE_SYNC(pte);
		}
	}
	pmap_update(pmap_kernel());

	return (0);
}

void
i80321_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
{
	vaddr_t va, endva;

	if (pmap_devmap_find_va(bsh, size) != NULL) {
		/* Device was statically mapped; nothing to do. */
		return;
	}

	endva = round_page(bsh + size);
	va = trunc_page(bsh);

	pmap_kremove(va, endva - va);
	uvm_km_free(kernel_map, va, endva - va);
}

/* *** Routines shared by i80321, PCI IO, and PCI MEM. *** */

int
i80321_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
    bus_size_t size, bus_space_handle_t *nbshp)
{
	*nbshp = bsh + offset;
	return (0);
}

void
i80321_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
    bus_size_t len, int flags)
{

	/* Nothing to do. */
}

void *
i80321_bs_vaddr(void *t, bus_space_handle_t bsh)
{

	return ((void *)bsh);
}

paddr_t
i80321_bs_mmap(void *t, bus_addr_t addr, off_t off, int prot, int flags)
{

	/* Not supported. */
	return (-1);
}

/* *** Routines for PCI IO. *** */

int
i80321_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags,
    bus_space_handle_t *bshp)
{
	struct i80321_softc *sc = t;
	uint32_t busbase;

	if (bpa >= sc->sc_ioout_xlate &&
	    bpa < (sc->sc_ioout_xlate + VERDE_OUT_XLATE_IO_WIN_SIZE)) {
		busbase = sc->sc_ioout_xlate;
	} else
		return (EINVAL);

	if ((bpa + size) >= (busbase + VERDE_OUT_XLATE_IO_WIN_SIZE))
		return (EINVAL);

	/*
	 * Found the window -- PCI I/O space is mapped at a fixed
	 * virtual address by board-specific code.  Translate the
	 * bus address to the virtual address.
	 */
	bus_space_subregion(sc->sc_st, sc->sc_io_sh, (bpa - busbase), size,
	    bshp);
	return (0);
}

void
i80321_io_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
{

	/* Nothing to do. */
}

int
i80321_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
    bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags,
    bus_addr_t *bpap, bus_space_handle_t *bshp)
{

	panic("i80321_io_bs_alloc(): not implemented");
}

void
i80321_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
{

	panic("i80321_io_bs_free(): not implemented");
}

void *
i80321_io_bs_vaddr(void *t, bus_space_handle_t bsh)
{

	/* Not supported. */
	return (NULL);
}

/* *** Routines for PCI MEM. *** */

int
i80321_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
    bus_space_handle_t *bshp)
{

	struct i80321_softc *sc = t;
	vaddr_t va;
	uint32_t busbase;
	paddr_t pa, endpa, physbase;
	pt_entry_t *pte;

#if 0
printf("i80321_bs_map bpa %x, size %x flag %x : %x %x \n", bpa, size, flag,
   sc->sc_owin[0].owin_xlate_lo,
   sc->sc_owin[0].owin_xlate_lo+ VERDE_OUT_XLATE_MEM_WIN_SIZE);
#endif

	if (bpa >= sc->sc_owin[0].owin_xlate_lo &&
	    bpa < (sc->sc_owin[0].owin_xlate_lo +
		   VERDE_OUT_XLATE_MEM_WIN_SIZE)) {
		busbase = sc->sc_iwin[1].iwin_xlate;
		physbase = sc->sc_owin[0].owin_xlate_lo;
	} else
		return (EINVAL);

	if ((bpa + size) >= ( sc->sc_owin[0].owin_xlate_lo +
	    VERDE_OUT_XLATE_MEM_WIN_SIZE))
		return (EINVAL);

	/*
	 * Found the window -- PCI MEM space is now mapped by allocating
	 * some kernel VA space and mapping the pages with pmap_enter().
	 * pmap_enter() will map unmanaged pages as non-cacheable.
	 */
	pa = trunc_page((bpa - busbase) + physbase);
	endpa = round_page(((bpa - busbase) + physbase) + size);

	va = uvm_km_valloc(kernel_map, endpa - pa);
	if (va == 0)
		return (ENOMEM);
//printf("i80321_mem_bs_map bpa %x pa %x va %x sz %x\n", bpa, pa, va, endpa-pa);

#if 0
printf("i80321_bs_map va %x pa %x, endpa %x, sz %x\n", va, pa,
    endpa, endpa-pa);
#endif

	*bshp = va + (bpa & PAGE_MASK);

	for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
		pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE);
		if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0) {
			pte = vtopte(va);
			*pte &= ~L2_S_CACHE_MASK;
			PTE_SYNC(pte);
		}
	}
	pmap_update(pmap_kernel());

	return (0);
}

void
i80321_mem_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
{
	vaddr_t va, endva;

	va = trunc_page(bsh);
	endva = round_page(bsh + size);

	pmap_kremove(va, endva - va);
	pmap_update(pmap_kernel());

	/* Free the kernel virtual mapping. */
	uvm_km_free(kernel_map, va, endva - va);
}

int
i80321_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
    bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags,
    bus_addr_t *bpap, bus_space_handle_t *bshp)
{

	panic("i80321_mem_bs_alloc(): not implemented");
}

void
i80321_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
{

	panic("i80321_mem_bs_free(): not implemented");
}

paddr_t
i80321_mem_bs_mmap(void *t, bus_addr_t addr, off_t off, int prot, int flags)
{

	/* XXX */
	return (-1);
}


code:
/*	$OpenBSD: i80321reg.h,v 1.3 2006/06/27 05:18:25 drahn Exp $	*/
/*	$NetBSD: i80321reg.h,v 1.15 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

#ifndef _ARM_XSCALE_I80321REG_H_
#define _ARM_XSCALE_I80321REG_H_

/*
 * Register definitions for the Intel 80321 (``Verde'') I/O processor,
 * based on the XScale core.
 */

/*
 * Base i80321 memory map:
 *
 *	0x0000.0000 - 0x7fff.ffff	ATU Outbound Direct Addressing Window
 *	0x8000.0000 - 0x9001.ffff	ATU Outbound Translation Windows
 *	0x9002.0000 - 0xffff.dfff	External Memory
 *	0xffff.e000 - 0xffff.e8ff	Peripheral Memory Mapped Registers
 *	0xffff.e900 - 0xffff.ffff	Reserved
 */

#define	VERDE_OUT_DIRECT_WIN_BASE	0x00000000UL
#define	VERDE_OUT_DIRECT_WIN_SIZE	0x80000000UL

#define	VERDE_OUT_XLATE_MEM_WIN_SIZE	0x04000000UL
#define	VERDE_OUT_XLATE_IO_WIN_SIZE	0x00010000UL

#define	VERDE_OUT_XLATE_MEM_WIN0_BASE	0x80000000UL
#define	VERDE_OUT_XLATE_MEM_WIN1_BASE	0x84000000UL

#define	VERDE_OUT_XLATE_IO_WIN0_BASE	0x90000000UL

#define	VERDE_EXTMEM_BASE		0x90020000UL

#define	VERDE_PMMR_BASE			0xffffe000UL
#define	VERDE_PMMR_SIZE			0x00001700UL

/*
 * Peripheral Memory Mapped Registers.  Defined as offsets
 * from the VERDE_PMMR_BASE.
 */
#define	VERDE_ATU_BASE			0x0100
#define	VERDE_ATU_SIZE			0x0100

#define	VERDE_MU_BASE			0x0300
#define	VERDE_MU_SIZE			0x0100

#define	VERDE_DMA_BASE			0x0400
#define	VERDE_DMA_BASE0			(VERDE_DMA_BASE + 0x00)
#define	VERDE_DMA_BASE1			(VERDE_DMA_BASE + 0x40)
#define	VERDE_DMA_SIZE			0x0100
#define	VERDE_DMA_CHSIZE		0x0040

#define	VERDE_MCU_BASE			0x0500
#define	VERDE_MCU_SIZE			0x0100

#define	VERDE_SSP_BASE			0x0600
#define	VERDE_SSP_SIZE			0x0080

#define	VERDE_PBIU_BASE			0x0680
#define	VERDE_PBIU_SIZE			0x0080

#define	VERDE_AAU_BASE			0x0800
#define	VERDE_AAU_SIZE			0x0100

#define	VERDE_I2C_BASE			0x1680
#define	VERDE_I2C_BASE0			(VERDE_I2C_BASE + 0x00)
#define	VERDE_I2C_BASE1			(VERDE_I2C_BASE + 0x20)
#define	VERDE_I2C_SIZE			0x0080
#define	VERDE_I2C_CHSIZE		0x0020

/*
 * Address Translation Unit
 */
	/* 0x00 - 0x38 -- PCI configuration space header */
#define	ATU_IALR0	0x40	/* Inbound ATU Limit 0 */
#define	ATU_IATVR0	0x44	/* Inbound ATU Xlate Value 0 */
#define	ATU_ERLR	0x48	/* Expansion ROM Limit */
#define	ATU_ERTVR	0x4c	/* Expansion ROM Xlate Value */
#define	ATU_IALR1	0x50	/* Inbound ATU Limit 1 */
#define	ATU_IALR2	0x54	/* Inbound ATU Limit 2 */
#define	ATU_IATVR2	0x58	/* Inbound ATU Xlate Value 2 */
#define	ATU_OIOWTVR	0x5c	/* Outbound I/O Window Xlate Value */
#define	ATU_OMWTVR0	0x60	/* Outbound Mem Window Xlate Value 0 */
#define	ATU_OUMWTVR0	0x64	/* Outbound Mem Window Xlate Value 0 Upper */
#define	ATU_OMWTVR1	0x68	/* Outbound Mem Window Xlate Value 1 */
#define	ATU_OUMWTVR1	0x6c	/* Outbound Mem Window Xlate Value 1 Upper */
#define	ATU_OUDWTVR	0x78	/* Outbound Mem Direct Xlate Value Upper */
#define	ATU_ATUCR	0x80	/* ATU Configuration */
#define	ATU_PCSR	0x84	/* PCI Configuration and Status */
#define	ATU_ATUISR	0x88	/* ATU Interrupt Status */
#define	ATU_ATUIMR	0x8c	/* ATU Interrupt Mask */
#define	ATU_IABAR3	0x90	/* Inbound ATU Base Address 3 */
#define	ATU_IAUBAR3	0x94	/* Inbound ATU Base Address 3 Upper */
#define	ATU_IALR3	0x98	/* Inbound ATU Limit 3 */
#define	ATU_IATVR3	0x9c	/* Inbound ATU Xlate Value 3 */
#define	ATU_OCCAR	0xa4	/* Outbound Configuration Cycle Address */
#define	ATU_OCCDR	0xac	/* Outbound Configuration Cycle Data */
#define	ATU_MSI_PORT	0xb4	/* MSI port */
#define	ATU_PDSCR	0xbc	/* PCI Bus Drive Strength Control */
#define	ATU_PCI_X_CAP_ID 0xe0	/* (1) */
#define	ATU_PCI_X_NEXT	0xe1	/* (1) */
#define	ATU_PCIXCMD	0xe2	/* PCI-X Command Register (2) */
#define	ATU_PCIXSR	0xe4	/* PCI-X Status Register */

#define	ATUCR_DRC_ALIAS		(1U << 19)
#define	ATUCR_DAU2GXEN		(1U << 18)
#define	ATUCR_P_SERR_MA		(1U << 16)
#define	ATUCR_DTS		(1U << 15)
#define	ATUCR_P_SERR_DIE	(1U << 9)
#define	ATUCR_DAE		(1U << 8)
#define	ATUCR_BIST_IE		(1U << 3)
#define	ATUCR_OUT_EN		(1U << 1)

#define	PCSR_DAAAPE		(1U << 18)
#define	PCSR_PCI_X_CAP		(3U << 16)
#define	PCSR_PCI_X_CAP_BORING	(0 << 16)
#define	PCSR_PCI_X_CAP_66	(1U << 16)
#define	PCSR_PCI_X_CAP_100	(2U << 16)
#define	PCSR_PCI_X_CAP_133	(3U << 16)
#define	PCSR_OTQB		(1U << 15)
#define	PCSR_IRTQB		(1U << 14)
#define	PCSR_DTV		(1U << 12)
#define	PCSR_BUS66		(1U << 10)
#define	PCSR_BUS64		(1U << 8)
#define	PCSR_RIB		(1U << 5)
#define	PCSR_RPB		(1U << 4)
#define	PCSR_CCR		(1U << 2)
#define	PCSR_CPR		(1U << 1)

#define	ATUISR_IMW1BU		(1U << 14)
#define	ATUISR_ISCEM		(1U << 13)
#define	ATUISR_RSCEM		(1U << 12)
#define	ATUISR_PST		(1U << 11)
#define	ATUISR_P_SERR_ASRT	(1U << 10)
#define	ATUISR_DPE		(1U << 9)
#define	ATUISR_BIST		(1U << 8)
#define	ATUISR_IBMA		(1U << 7)
#define	ATUISR_P_SERR_DET	(1U << 4)
#define	ATUISR_PMA		(1U << 3)
#define	ATUISR_PTAM		(1U << 2)
#define	ATUISR_PTAT		(1U << 1)
#define	ATUISR_PMPE		(1U << 0)

#define	ATUIMR_IMW1BU		(1U << 11)
#define	ATUIMR_ISCEM		(1U << 10)
#define	ATUIMR_RSCEM		(1U << 9)
#define	ATUIMR_PST		(1U << 8)
#define	ATUIMR_DPE		(1U << 7)
#define	ATUIMR_P_SERR_ASRT	(1U << 6)
#define	ATUIMR_PMA		(1U << 5)
#define	ATUIMR_PTAM		(1U << 4)
#define	ATUIMR_PTAT		(1U << 3)
#define	ATUIMR_PMPE		(1U << 2)
#define	ATUIMR_IE_SERR_EN	(1U << 1)
#define	ATUIMR_ECC_TAE		(1U << 0)

#define	PCIXCMD_MOST_1		(0 << 4)
#define	PCIXCMD_MOST_2		(1 << 4)
#define	PCIXCMD_MOST_3		(2 << 4)
#define	PCIXCMD_MOST_4		(3 << 4)
#define	PCIXCMD_MOST_8		(4 << 4)
#define	PCIXCMD_MOST_12		(5 << 4)
#define	PCIXCMD_MOST_16		(6 << 4)
#define	PCIXCMD_MOST_32		(7 << 4)
#define	PCIXCMD_MOST_MASK	(7 << 4)
#define	PCIXCMD_MMRBC_512	(0 << 2)
#define	PCIXCMD_MMRBC_1024	(1 << 2)
#define	PCIXCMD_MMRBC_2048	(2 << 2)
#define	PCIXCMD_MMRBC_4096	(3 << 2)
#define	PCIXCMD_MMRBC_MASK	(3 << 2)
#define	PCIXCMD_ERO		(1U << 1)
#define	PCIXCMD_DPERE		(1U << 0)

#define	PCIXSR_RSCEM		(1U << 29)
#define	PCIXSR_DMCRS_MASK	(7 << 26)
#define	PCIXSR_DMOST_MASK	(7 << 23)
#define	PCIXSR_COMPLEX		(1U << 20)
#define	PCIXSR_USC		(1U << 19)
#define	PCIXSR_SCD		(1U << 18)
#define	PCIXSR_133_CAP		(1U << 17)
#define	PCIXSR_32PCI		(1U << 16)	/* 0 = 32, 1 = 64 */
#define	PCIXSR_BUSNO(x)		(((x) & 0xff00) >> 8)
#define	PCIXSR_DEVNO(x)		(((x) & 0xf8) >> 3)
#define	PCIXSR_FUNCNO(x)	((x) & 0x7)

/*
 * Memory Controller Unit
 */
#define	MCU_SDIR		0x00	/* DDR SDRAM Init. Register */
#define	MCU_SDCR		0x04	/* DDR SDRAM Control Register */
#define	MCU_SDBR		0x08	/* SDRAM Base Register */
#define	MCU_SBR0		0x0c	/* SDRAM Boundary 0 */
#define	MCU_SBR1		0x10	/* SDRAM Boundary 1 */
#define	MCU_ECCR		0x34	/* ECC Control Register */
#define	MCU_ELOG0		0x38	/* ECC Log 0 */
#define	MCU_ELOG1		0x3c	/* ECC Log 1 */
#define	MCU_ECAR0		0x40	/* ECC address 0 */
#define	MCU_ECAR1		0x44	/* ECC address 1 */
#define	MCU_ECTST		0x48	/* ECC test register */
#define	MCU_MCISR		0x4c	/* MCU Interrupt Status Register */
#define	MCU_RFR			0x50	/* Refresh Frequency Register */
#define	MCU_DBUDSR		0x54	/* Data Bus Pull-up Drive Strength */
#define	MCU_DBDDSR		0x58	/* Data Bus Pull-down Drive Strength */
#define	MCU_CUDSR		0x5c	/* Clock Pull-up Drive Strength */
#define	MCU_CDDSR		0x60	/* Clock Pull-down Drive Strength */
#define	MCU_CEUDSR		0x64	/* Clock En Pull-up Drive Strength */
#define	MCU_CEDDSR		0x68	/* Clock En Pull-down Drive Strength */
#define	MCU_CSUDSR		0x6c	/* Chip Sel Pull-up Drive Strength */
#define	MCU_CSDDSR		0x70	/* Chip Sel Pull-down Drive Strength */
#define	MCU_REUDSR		0x74	/* Rx En Pull-up Drive Strength */
#define	MCU_REDDSR		0x78	/* Rx En Pull-down Drive Strength */
#define	MCU_ABUDSR		0x7c	/* Addr Bus Pull-up Drive Strength */
#define	MCU_ABDDSR		0x80	/* Addr Bus Pull-down Drive Strength */
#define	MCU_DSDR		0x84	/* Data Strobe Delay Register */
#define	MCU_REDR		0x88	/* Rx Enable Delay Register */

#define	SDCR_DIMMTYPE		(1U << 1)	/* 0 = unbuf, 1 = reg */
#define	SDCR_BUSWIDTH		(1U << 2)	/* 0 = 64, 1 = 32 */

#define	SBRx_TECH		(1U << 31)
#define	SBRx_BOUND		0x0000003f

#define	ECCR_SBERE		(1U << 0)
#define	ECCR_MBERE		(1U << 1)
#define	ECCR_SBECE		(1U << 2)
#define	ECCR_ECCEN		(1U << 3)

#define	ELOGx_SYNDROME		0x000000ff
#define	ELOGx_ERRTYPE		(1U << 8)	/* 1 = multi-bit */
#define	ELOGx_RW		(1U << 12)	/* 1 = write error */
	/*
	 * Dev ID	Func		Requester
	 * 2		0		XScale core
	 * 2		1		ATU
	 * 13		0		DMA channel 0
	 * 13		1		DMA channel 1
	 * 26		0		ATU
	 */
#define	ELOGx_REQ_DEV(x)	(((x) >> 19) & 0x1f)
#define	ELOGx_REQ_FUNC(x)	(((x) >> 16) & 0x3)

#define	MCISR_ECC_ERR0		(1U << 0)
#define	MCISR_ECC_ERR1		(1U << 1)
#define	MCISR_ECC_ERRN		(1U << 2)

/*
 * Timers
 *
 * The i80321 timer registers are available in both memory-mapped
 * and coprocessor spaces.  Most of the registers are read-only
 * if memory-mapped, so we access them via coprocessor space.
 *
 *	TMR0	cp6 c0,1	0xffffe7e0
 *	TMR1	cp6 c1,1	0xffffe7e4
 *	TCR0	cp6 c2,1	0xffffe7e8
 *	TCR1	cp6 c3,1	0xffffe7ec
 *	TRR0	cp6 c4,1	0xffffe7f0
 *	TRR1	cp6 c5,1	0xffffe7f4
 *	TISR	cp6 c6,1	0xffffe7f8
 *	WDTCR	cp6 c7,1	0xffffe7fc
 */

#define	TMRx_TC			(1U << 0)
#define	TMRx_ENABLE		(1U << 1)
#define	TMRx_RELOAD		(1U << 2)
#define	TMRx_PRIV		(1U << 3)
#define	TMRx_CSEL_CORE		(0 << 4)
#define	TMRx_CSEL_CORE_div4	(1 << 4)
#define	TMRx_CSEL_CORE_div8	(2 << 4)
#define	TMRx_CSEL_CORE_div16	(3 << 4)

#define	TISR_TMR0		(1U << 0)
#define	TISR_TMR1		(1U << 1)

#define	WDTCR_ENABLE1		0x1e1e1e1e
#define	WDTCR_ENABLE2		0xe1e1e1e1

/*
 * Interrupt Controller Unit.
 *
 *	INTCTL	cp6 c0,0	0xffffe7d0
 *	INTSTR	cp6 c4,0	0xffffe7d4
 *	IINTSRC	cp6 c8,0	0xffffe7d8
 *	FINTSRC	cp6 c9,0	0xffffe7dc
 *	PIRSR			0xffffe1ec
 */

#define	ICU_PIRSR		0x01ec
#define	ICU_GPOE		0x07c4
#define	ICU_GPID		0x07c8
#define	ICU_GPOD		0x07cc

/*
 * NOTE: WE USE THE `bitXX' BITS TO INDICATE PENDING SOFTWARE
 * INTERRUPTS.  See i80321_icu.c
 */
#define	ICU_INT_HPI		31	/* high priority interrupt */
#define	ICU_INT_XINT0		27	/* external interrupts */
#define	ICU_INT_XINT(x)		((x) + ICU_INT_XINT0)
#define	ICU_INT_bit26		26
#define	ICU_INT_SSP		25	/* SSP serial port */
#define	ICU_INT_MUE		24	/* msg unit error */
#define	ICU_INT_AAUE		23	/* AAU error */
#define	ICU_INT_bit23		23
#define	ICU_INT_bit22		22
#define	ICU_INT_DMA1E		21	/* DMA Ch 1 error */
#define	ICU_INT_DMA0E		20	/* DMA Ch 0 error */
#define	ICU_INT_MCUE		19	/* memory controller error */
#define	ICU_INT_ATUE		18	/* ATU error */
#define	ICU_INT_BIUE		17	/* bus interface unit error */
#define	ICU_INT_PMU		16	/* XScale PMU */
#define	ICU_INT_PPM		15	/* peripheral PMU */
#define	ICU_INT_BIST		14	/* ATU Start BIST */
#define	ICU_INT_MU		13	/* messaging unit */
#define	ICU_INT_I2C1		12	/* i2c unit 1 */
#define	ICU_INT_I2C0		11	/* i2c unit 0 */
#define	ICU_INT_TMR1		10	/* timer 1 */
#define	ICU_INT_TMR0		9	/* timer 0 */
#define	ICU_INT_CPPM		8	/* core processor PMU */
#define	ICU_INT_AAU_EOC		7	/* AAU end-of-chain */
#define	ICU_INT_AAU_EOT		6	/* AAU end-of-transfer */
#define	ICU_INT_bit5		5
#define	ICU_INT_bit4		4
#define	ICU_INT_DMA1_EOC	3	/* DMA1 end-of-chain */
#define	ICU_INT_DMA1_EOT	2	/* DMA1 end-of-transfer */
#define	ICU_INT_DMA0_EOC	1	/* DMA0 end-of-chain */
#define	ICU_INT_DMA0_EOT	0	/* DMA0 end-of-transfer */

#define	ICU_INT_HWMASK		(0xffffffff & \
					~((1 << ICU_INT_bit26) | \
					  (1 << ICU_INT_bit22) | \
					  (1 << ICU_INT_bit5)  | \
					  (1 << ICU_INT_bit4)))

/*
 * SSP Serial Port
 */

#define	SSP_SSCR0	0x00		/* SSC control 0 */
#define	SSP_SSCR1	0x04		/* SSC control 1 */
#define	SSP_SSSR	0x08		/* SSP status */
#define	SSP_SSITR	0x0c		/* SSP interrupt test */
#define	SSP_SSDR	0x10		/* SSP data */

#define	SSP_SSCR0_DSIZE(x)	((x) - 1)/* data size: 4..16 */
#define	SSP_SSCR0_FRF_SPI	(0 << 4) /* Motorola Serial Periph Iface */
#define	SSP_SSCR0_FRF_SSP	(1U << 4)/* TI Sync. Serial Protocol */
#define	SSP_SSCR0_FRF_UWIRE	(2U << 4)/* NatSemi Microwire */
#define	SSP_SSCR0_FRF_rsvd	(3U << 4)/* reserved */
#define	SSP_SSCR0_ECS		(1U << 6)/* external clock select */
#define	SSP_SSCR0_SSE		(1U << 7)/* sync. serial port enable */
#define	SSP_SSCR0_SCR(x)	((x) << 8)/* serial clock rate */
					  /* bit rate = 3.6864 * 10e6 /
					        (2 * (SCR + 1)) */

#define	SSP_SSCR1_RIE		(1U << 0)/* Rx FIFO interrupt enable */
#define	SSP_SSCR1_TIE		(1U << 1)/* Tx FIFO interrupt enable */
#define	SSP_SSCR1_LBM		(1U << 2)/* loopback mode enable */
#define	SSP_SSCR1_SPO		(1U << 3)/* Moto SPI SSCLK pol. (1 = high) */
#define	SSP_SSCR1_SPH		(1U << 4)/* Moto SPI SSCLK phase:
					    0 = inactive full at start,
						1/2 at end of frame
					    1 = inactive 1/2 at start,
						full at end of frame */
#define	SSP_SSCR1_MWDS		(1U << 5)/* Microwire data size:
					    0 = 8 bit
					    1 = 16 bit */
#define	SSP_SSCR1_TFT		(((x) - 1) << 6) /* Tx FIFO threshold */
#define	SSP_SSCR1_RFT		(((x) - 1) << 10)/* Rx FIFO threshold */
#define	SSP_SSCR1_EFWR		(1U << 14)/* enab. FIFO write/read */
#define	SSP_SSCR1_STRF		(1U << 15)/* FIFO write/read FIFO select:
					     0 = Tx FIFO
					     1 = Rx FIFO */

#define	SSP_SSSR_TNF		(1U << 2)/* Tx FIFO not full */
#define	SSP_SSSR_RNE		(1U << 3)/* Rx FIFO not empty */
#define	SSP_SSSR_BSY		(1U << 4)/* SSP is busy */
#define	SSP_SSSR_TFS		(1U << 5)/* Tx FIFO service request */
#define	SSP_SSSR_RFS		(1U << 6)/* Rx FIFO service request */
#define	SSP_SSSR_ROR		(1U << 7)/* Rx FIFO overrun */
#define	SSP_SSSR_TFL(x)		(((x) >> 8) & 0xf) /* Tx FIFO level */
#define	SSP_SSSR_RFL(x)		(((x) >> 12) & 0xf)/* Rx FIFO level */

#define	SSP_SSITR_TTFS		(1U << 5)/* Test Tx FIFO service */
#define	SSP_SSITR_TRFS		(1U << 6)/* Test Rx FIFO service */
#define	SSP_SSITR_TROR		(1U << 7)/* Test Rx overrun */

/*
 * Peripheral Bus Interface Unit
 */

#define PBIU_PBCR		0x00	/* PBIU Control Register */
#define PBIU_PBBAR0		0x08	/* PBIU Base Address Register 0 */
#define PBIU_PBLR0		0x0c	/* PBIU Limit Register 0 */
#define PBIU_PBBAR1		0x10	/* PBIU Base Address Register 1 */
#define PBIU_PBLR1		0x14	/* PBIU Limit Register 1 */
#define PBIU_PBBAR2		0x18	/* PBIU Base Address Register 2 */
#define PBIU_PBLR2		0x1c	/* PBIU Limit Register 2 */
#define PBIU_PBBAR3		0x20	/* PBIU Base Address Register 3 */
#define PBIU_PBLR3		0x24	/* PBIU Limit Register 3 */
#define PBIU_PBBAR4		0x28	/* PBIU Base Address Register 4 */
#define PBIU_PBLR4		0x2c	/* PBIU Limit Register 4 */
#define PBIU_PBBAR5		0x30	/* PBIU Base Address Register 5 */
#define PBIU_PBLR5		0x34	/* PBIU Limit Register 5 */
#define PBIU_DSCR		0x38	/* PBIU Drive Strength Control Reg. */
#define PBIU_MBR0		0x40	/* PBIU Memory-less Boot Reg. 0 */
#define PBIU_MBR1		0x60	/* PBIU Memory-less Boot Reg. 1 */
#define PBIU_MBR2		0x64	/* PBIU Memory-less Boot Reg. 2 */

#define	PBIU_PBCR_PBIEN		(1 << 0)
#define	PBIU_PBCR_PBI100	(1 << 1)
#define	PBIU_PBCR_PBI66		(2 << 1)
#define	PBIU_PBCR_PBI33		(3 << 1)
#define	PBIU_PBCR_PBBEN		(1 << 3)

#define	PBIU_PBARx_WIDTH8	(0 << 0)
#define	PBIU_PBARx_WIDTH16	(1 << 0)
#define	PBIU_PBARx_WIDTH32	(2 << 0)
#define	PBIU_PBARx_ADWAIT4	(0 << 2)
#define	PBIU_PBARx_ADWAIT8	(1 << 2)
#define	PBIU_PBARx_ADWAIT12	(2 << 2)
#define	PBIU_PBARx_ADWAIT16	(3 << 2)
#define	PBIU_PBARx_ADWAIT20	(4 << 2)
#define	PBIU_PBARx_RCWAIT1	(0 << 6)
#define	PBIU_PBARx_RCWAIT4	(1 << 6)
#define	PBIU_PBARx_RCWAIT8	(2 << 6)
#define	PBIU_PBARx_RCWAIT12	(3 << 6)
#define	PBIU_PBARx_RCWAIT16	(4 << 6)
#define	PBIU_PBARx_RCWAIT20	(5 << 6)
#define	PBIU_PBARx_FWE		(1 << 9)
#define	PBIU_BASE_MASK		0xfffff000U

#define	PBIU_PBLRx_SIZE(x)	(~((x) - 1))

/*
 * Messaging Unit
 */
#define MU_IMR0			0x0010	/* MU Inbound Message Register 0 */
#define MU_IMR1			0x0014	/* MU Inbound Message Register 1 */
#define MU_OMR0			0x0018	/* MU Outbound Message Register 0 */
#define MU_OMR1			0x001c	/* MU Outbound Message Register 1 */
#define MU_IDR			0x0020	/* MU Inbound Doorbell Register */
#define MU_IISR			0x0024	/* MU Inbound Interrupt Status Reg */
#define MU_IIMR			0x0028	/* MU Inbound Interrupt Mask Reg */
#define MU_ODR			0x002c	/* MU Outbound Doorbell Register */
#define MU_OISR			0x0030	/* MU Outbound Interrupt Status Reg */
#define MU_OIMR			0x0034	/* MU Outbound Interrupt Mask Reg */
#define MU_MUCR			0x0050	/* MU Configuration Register */
#define MU_QBAR			0x0054	/* MU Queue Base Address Register */
#define MU_IFHPR		0x0060	/* MU Inbound Free Head Pointer Reg */
#define MU_IFTPR		0x0064	/* MU Inbound Free Tail Pointer Reg */
#define MU_IPHPR		0x0068	/* MU Inbound Post Head Pointer Reg */
#define MU_IPTPR		0x006c	/* MU Inbound Post Tail Pointer Reg */
#define MU_OFHPR		0x0070	/* MU Outbound Free Head Pointer Reg */
#define MU_OFTPR		0x0074	/* MU Outbound Free Tail Pointer Reg */
#define MU_OPHPR		0x0078	/* MU Outbound Post Head Pointer Reg */
#define MU_OPTPR		0x007c	/* MU Outbound Post Tail Pointer Reg */
#define MU_IAR			0x0080	/* MU Index Address Register */

#define MU_IIMR_IRI	(1 << 6)	/* Index Register Interrupt */
#define MU_IIMR_OFQFI	(1 << 5)	/* Outbound Free Queue Full Int. */
#define MU_IIMR_IPQI	(1 << 4)	/* Inbound Post Queue Interrupt */
#define MU_IIMR_EDI	(1 << 3)	/* Error Doorbell Interrupt */
#define MU_IIMR_IDI	(1 << 2)	/* Inbound Doorbell Interrupt */
#define MU_IIMR_IM1I	(1 << 1)	/* Inbound Message 1 Interrupt */
#define MU_IIMR_IM0I	(1 << 0)	/* Inbound Message 0 Interrupt */

#endif /* _ARM_XSCALE_I80321REG_H_ */


code:
/*	$OpenBSD: i80321var.h,v 1.4 2009/08/22 02:54:50 mk Exp $	*/
/*	$NetBSD: i80321var.h,v 1.10 2005/12/15 01:44:00 briggs Exp $	*/

/*
 * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

#ifndef _ARM_XSCALE_I80321VAR_H_
#define	_ARM_XSCALE_I80321VAR_H_

#include <sys/queue.h>
#include <sys/gpio.h>
#include <sys/evcount.h>
#include <dev/pci/pcivar.h>
#include <dev/gpio/gpiovar.h>

/*
 * There are roughly 32 interrupt sources.
 */
#define	NIRQ		32

struct intrhand {
	TAILQ_ENTRY(intrhand) ih_list;	/* link on intrq list */
	int (*ih_func)(void *);		/* handler */
	void *ih_arg;			/* arg for handler */
	int ih_ipl;			/* IPL_* */
	int ih_irq;			/* IRQ number */
	struct evcount  	ih_count;
	const char *ih_name;
};

struct intrq {
	TAILQ_HEAD(, intrhand) iq_list;	/* handler list */
	int iq_irq;			/* IRQ to mask while handling */
	int iq_levels;			/* IPL_*'s this IRQ has */
	int iq_ist;			/* share type */
};

struct config_bus_space {
	u_int32_t bus_base;
	u_int32_t bus_size;
	int bus_io;
};

struct i80321_softc {
	struct device sc_dev;		/* generic device glue */

	int sc_is_host;			/* indicates if we're a host or
					   plugged into another host */

	/*
	 * This is the bus_space and handle used to access the
	 * i80321 itself.  This is filled in by the board-specific
	 * front-end.
	 */
	bus_space_tag_t sc_st;
	bus_space_handle_t sc_sh;

	/* Handles for the various subregions. */
	bus_space_handle_t sc_atu_sh;
	bus_space_handle_t sc_mcu_sh;

#ifdef BULLSHIT
	/*
	 * We expect the board-specific front-end to have already mapped
	 * the PCI I/O space .. it is only 64K, and I/O mappings tend to
	 * be smaller than a page size, so it's generally more efficient
	 * to map them all into virtual space in one fell swoop.
	 */
	vaddr_t	sc_iow_vaddr;		/* I/O window vaddr */
#else
	bus_space_handle_t sc_io_sh;
#endif

	/*
	 * Variables that define the Inbound windows.  The base address of
	 * 0-2 are configured by a host via BARs.  The xlate variable
	 * defines the start of the local address space that it maps to.
	 * The size variable defines the byte size.
	 *
	 * The first 3 windows are for incoming PCI memory read/write
	 * cycles from a host.  The 4th window, not configured by the
	 * host (as it outside the normal BAR range) is the inbound
	 * window for PCI devices controlled by the i80321.
	 */
	struct {
		uint32_t iwin_base_hi;
		uint32_t iwin_base_lo;
		uint32_t iwin_xlate;
		uint32_t iwin_size;
	} sc_iwin[4];

	/*
	 * Variables that define the Outbound windows.
	 */
	struct {
		uint32_t owin_xlate_lo;
		uint32_t owin_xlate_hi;
	} sc_owin[2];

	/*
	 * This is the PCI address that the Outbound I/O window maps to.
         * The offset is to keep the actual used I/O address away from 0,
	 * which can be bad if, say, an i8254x gig-e chip gets mapped there.
	 * The 0 value apparently looks like "unconfigured" to the controller
	 * and it ignores writes to that region (it doesn't cause a bus fault,
	 * it just ignores them--leading to a non-functional controller).  The
	 * wm(4) driver usually uses memory-mapped regions, but does use the
	 * I/O-mapped region for reset operations in order to work around a
	 * bug in the chip.
	 * Iyonix, while using sc_ioout_xlate 0 needs an offset of 0, too, in
	 * order to function properly.  These values are both set in the
	 * port-specific i80321_mainbus_attach() routine.
	 */
	uint32_t sc_ioout_xlate;
	uint32_t sc_ioout_xlate_offset;

	/* Bus space, DMA, and PCI tags for the PCI bus (private devices). */
	struct bus_space sc_pci_iot;
	struct bus_space sc_pci_memt;
	struct arm32_bus_dma_tag sc_pci_dmat;
	struct arm32_pci_chipset sc_pci_chipset;

	/* DMA window info for PCI DMA. */
	struct arm32_dma_range sc_pci_dma_range;

	/* GPIO state */
	uint8_t sc_gpio_dir;	/* GPIO pin direction (1 == output) */
	uint8_t sc_gpio_val;	/* GPIO output pin value */

#define I80219_GPIO_NPINS 8
	/* GPIO for 80219 -XXX */
	struct gpio_chipset_tag sc_gpio_gc;
        struct gpio_pin sc_gpio_pins[I80219_GPIO_NPINS];

	/* DMA tag for local devices. */
	struct arm32_bus_dma_tag sc_local_dmat;

	/* Structures to do bus fixup */
	int nbogus;
	struct extent *extent_mem;
	struct extent *extent_port;
	struct config_bus_space sc_membus_space;
	struct config_bus_space sc_iobus_space;

};

/*
 * Arguments used to attach IOP built-ins.
 */
struct iopxs_attach_args {
	const char *ia_name;	/* name of device */
	bus_space_tag_t ia_st;	/* space tag */
	bus_space_handle_t ia_sh;/* handle of IOP base */
	bus_dma_tag_t ia_dmat;	/* DMA tag */
	bus_addr_t ia_offset;	/* offset of device from IOP base */
	bus_size_t ia_size;	/* size of sub-device */
};

extern struct bus_space i80321_bs_tag;
extern struct i80321_softc *i80321_softc;

extern void (*i80321_hardclock_hook)(void);

void	i80321_sdram_bounds(bus_space_tag_t, bus_space_handle_t,
	    paddr_t *, psize_t *);

void	i80321_calibrate_delay(void);

void	i80321intc_init(void);
void	i80321intc_intr_init(void);
void	*i80321intc_establish(int, int, int (*)(void *), void *, char *);
void	i80321intc_disestablish(void *);

void	i80321_gpio_set_direction(uint8_t, uint8_t);
void	i80321_gpio_set_val(uint8_t, uint8_t);
uint8_t	i80321_gpio_get_val(void);

void	i80321_bs_init(bus_space_tag_t, void *);
void	i80321_io_bs_init(bus_space_tag_t, void *);
void	i80321_mem_bs_init(bus_space_tag_t, void *);

void	i80321_local_dma_init(struct i80321_softc *sc);

void	i80321_pci_init(pci_chipset_tag_t, void *);

void	i80321_attach(struct i80321_softc *);
#endif /* _ARM_XSCALE_I80321VAR_H_ */


code:
/*	$OpenBSD: iopi2c.c,v 1.3 2009/03/27 16:02:41 oga Exp $	*/
/*	$NetBSD: iopi2c.c,v 1.3 2005/12/11 12:16:51 christos Exp $	*/

/*
 * Copyright (c) 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Intel i80321 I/O Processor I2C Controller Unit support.
 */
#include <sys/param.h>
#include <sys/rwlock.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>

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

#include <dev/i2c/i2cvar.h>

#include <arm/xscale/iopi2creg.h>
#include <arm/xscale/iopi2cvar.h>

static int iopiic_acquire_bus(void *, int);
static void iopiic_release_bus(void *, int);

static int iopiic_send_start(void *, int);
static int iopiic_send_stop(void *, int);
static int iopiic_initiate_xfer(void *, uint16_t, int);
static int iopiic_read_byte(void *, uint8_t *, int);
static int iopiic_write_byte(void *, uint8_t, int);

struct cfdriver iopiic_cd = {
	NULL, "iopiic", DV_DULL
};

void
iopiic_attach(struct iopiic_softc *sc)
{
	struct i2cbus_attach_args iba;

	sc->sc_i2c.ic_exec = NULL;
	sc->sc_i2c.ic_cookie = sc;
	sc->sc_i2c.ic_acquire_bus = iopiic_acquire_bus;
	sc->sc_i2c.ic_release_bus = iopiic_release_bus;
	sc->sc_i2c.ic_send_start = iopiic_send_start;
	sc->sc_i2c.ic_send_stop = iopiic_send_stop;
	sc->sc_i2c.ic_initiate_xfer = iopiic_initiate_xfer;
	sc->sc_i2c.ic_read_byte = iopiic_read_byte;
	sc->sc_i2c.ic_write_byte = iopiic_write_byte;

	bzero(&iba, sizeof iba);
	iba.iba_name = "iic";
	iba.iba_tag = &sc->sc_i2c;
	(void) config_found(&sc->sc_dev, &iba, iicbus_print);
}

static int
iopiic_acquire_bus(void *cookie, int flags)
{
	struct iopiic_softc *sc = cookie;

	/* XXX What should we do for the polling case? */
	if (flags & I2C_F_POLL)
		return (0);

	return (rw_enter(&sc->sc_buslock, RW_WRITE | RW_INTR));
}

static void
iopiic_release_bus(void *cookie, int flags)
{
	struct iopiic_softc *sc = cookie;

	/* XXX See above. */
	if (flags & I2C_F_POLL)
		return;

	rw_exit(&sc->sc_buslock);
}

#define	IOPIIC_TIMEOUT		100	/* protocol timeout, in uSecs */

static int
iopiic_wait(struct iopiic_softc *sc, int bit, int flags)
{
	uint32_t isr;
	int timeout, error=0;

	/* XXX We never sleep, we always poll.  Fix me. */

	/*
	 * For some reason, we seem to run into problems if we poll
	 * the ISR while the transfer is in progress--at least on the
	 * i80312.  The condition that we're looking for never seems
	 * to appear on a read, and it's not clear why; perhaps reads
	 * of the I2C register file interfere with its proper operation?
	 * For now, just delay for a while up front.
	 *
	 * We _really_ need this to be interrupt-driven, but a problem
	 * with that is that the i80312 has no way to mask interrupts...
	 * So we need to deal with that.  For DMA and AAU, too, for that
	 * matter.
	 * Note that delay(100) doesn't quite work on the npwr w/ m41t00.
	 */
	delay(200);
	for (timeout = IOPIIC_TIMEOUT; timeout != 0; timeout--) {
		isr = bus_space_read_4(sc->sc_st, sc->sc_sh, IIC_ISR);
		if (isr & (bit | IIC_ISR_BED))
			break;
		delay(1);
	}

	if (isr & (IIC_ISR_BED | (bit & IIC_ISR_ALD)))
		error = EIO;
	else if (isr & (bit & ~IIC_ISR_ALD))
		error = 0;
	else
		error = ETIMEDOUT;

#if 0
	if (error)
		printf("%s: iopiic_wait, (%08x) error %d: ISR = 0x%08x\n",
		    sc->sc_dev.dv_xname, bit, error, isr);
#endif

	/*
	 * The IIC_ISR is Read/Clear apart from the bottom 4 bits, which are
	 * read-only. So simply write back our copy of the ISR to clear any
	 * latched status.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ISR, isr);

	return (error);
}

static int
iopiic_send_start(void *cookie, int flags)
{
	struct iopiic_softc *sc = cookie;

	/*
	 * This may only work in conjunction with a data transfer;
	 * we might need to un-export the "start" primitive.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR,
	    sc->sc_icr | IIC_ICR_START);
	delay(IOPIIC_TIMEOUT);

	return (0);
}

static int
iopiic_send_stop(void *cookie, int flags)
{
	struct iopiic_softc *sc = cookie;

	/*
	 * The STOP bit is only used in conjunction with
	 * a data transfer, so we need to use MA in this
	 * case.
	 *
	 * Consider adding an I2C_F_STOP so we can
	 * do a read-with-STOP and write-with-STOP.
	 */
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR,
	    sc->sc_icr | IIC_ICR_MA);
	delay(IOPIIC_TIMEOUT);

	return (0);
}

static int
iopiic_initiate_xfer(void *cookie, uint16_t addr, int flags)
{
	struct iopiic_softc *sc = cookie;
	int error, rd_req = (flags & I2C_F_READ) != 0;
	uint32_t idbr;

	/* We only support 7-bit addressing. */
	if ((addr & 0x78) == 0x78)
		return (EINVAL);

	idbr = (addr << 1) | (rd_req ? 1 : 0);
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_IDBR, idbr);
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR,
	    sc->sc_icr | IIC_ICR_START | IIC_ICR_TB);

	error = iopiic_wait(sc, IIC_ISR_ITE, flags);
#if 0
	if (error)
		printf("%s: failed to initiate %s xfer\n", sc->sc_dev.dv_xname,
		    rd_req ? "read" : "write");
#endif
	return (error);
}

static int
iopiic_read_byte(void *cookie, uint8_t *bytep, int flags)
{
	struct iopiic_softc *sc = cookie;
	int error, last_byte = (flags & I2C_F_LAST) != 0,
	    send_stop = (flags & I2C_F_STOP) != 0;

	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR,
	    sc->sc_icr | IIC_ICR_TB | (last_byte ? IIC_ICR_NACK : 0) |
	    (send_stop ? IIC_ICR_STOP : 0));
	if ((error = iopiic_wait(sc, IIC_ISR_IRF | IIC_ISR_ALD, flags)) == 0)
		*bytep = bus_space_read_4(sc->sc_st, sc->sc_sh, IIC_IDBR);
#if 0
	if (error)
		printf("%s: read byte failed\n", sc->sc_dev.dv_xname);
#endif

	return (error);
}

static int
iopiic_write_byte(void *cookie, uint8_t byte, int flags)
{
	struct iopiic_softc *sc = cookie;
	int error, send_stop = (flags & I2C_F_STOP) != 0;

	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_IDBR, byte);
	bus_space_write_4(sc->sc_st, sc->sc_sh, IIC_ICR,
	    sc->sc_icr | IIC_ICR_TB | (send_stop ? IIC_ICR_STOP : 0));
	error = iopiic_wait(sc, IIC_ISR_ITE | IIC_ISR_ALD, flags);

#if 0
	if (error)
		printf("%s: write byte failed\n", sc->sc_dev.dv_xname);
#endif

	return (error);
}