code:
/*	$OpenBSD: sxitimer.c,v 1.4 2015/05/19 06:04:26 jsg Exp $	*/
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
 * Copyright (c) 2013 Artturi Alm
 *
 * 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/evcount.h>
#include <sys/device.h>
#include <sys/timetc.h>
#include <dev/clock_subr.h>

#include <arm/cpufunc.h>

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

#include <armv7/armv7/armv7var.h>
#include <armv7/sunxi/sunxireg.h>
/* #include <armv7/sunxi/sxipiovar.h> */

#define	TIMER_IER 		0x00
#define	TIMER_ISR 		0x04
#define	TIMER_IRQ(x)		(1 << (x))

#define	TIMER_CTRL(x)		(0x10 + (0x10 * (x)))
#define	TIMER_INTV(x)		(0x14 + (0x10 * (x)))
#define	TIMER_CURR(x)		(0x18 + (0x10 * (x)))

/* A20 counter, relative to CPUCNTRS_ADDR */
#define	OSC24M_CNT64_CTRL	0x80
#define	OSC24M_CNT64_LOW	0x84
#define	OSC24M_CNT64_HIGH	0x88

/* A1X counter */
#define	CNT64_CTRL		0xa0
#define	CNT64_LOW		0xa4
#define	CNT64_HIGH		0xa8

#define	CNT64_CLR_EN		(1 << 0) /* clear enable */
#define	CNT64_RL_EN		(1 << 1) /* read latch enable */
#define	CNT64_SYNCH		(1 << 4) /* sync to OSC24M counter */

#define	LOSC_CTRL		0x100
#define	OSC32K_SRC_SEL		(1 << 0)

#define	TIMER_ENABLE		(1 << 0)
#define	TIMER_RELOAD		(1 << 1)
#define	TIMER_CLK_SRC_MASK	(3 << 2)
#define	TIMER_LSOSC		(0 << 2)
#define	TIMER_OSC24M		(1 << 2)
#define	TIMER_PLL6_6		(2 << 2)
#define	TIMER_PRESC_1		(0 << 4)
#define	TIMER_PRESC_2		(1 << 4)
#define	TIMER_PRESC_4		(2 << 4)
#define	TIMER_PRESC_8		(3 << 4)
#define	TIMER_PRESC_16		(4 << 4)
#define	TIMER_PRESC_32		(5 << 4)
#define	TIMER_PRESC_64		(6 << 4)
#define	TIMER_PRESC_128		(7 << 4)
#define	TIMER_CONTINOUS		(0 << 7)
#define	TIMER_SINGLESHOT	(1 << 7)

#define	TICKTIMER		0
#define	STATTIMER		1
#define	CNTRTIMER		2

void	sxitimer_attach(struct device *, struct device *, void *);
int	sxitimer_tickintr(void *);
int	sxitimer_statintr(void *);
void	sxitimer_cpu_initclocks(void);
void	sxitimer_setstatclockrate(int);
uint64_t	sxitimer_readcnt64(void);
uint32_t	sxitimer_readcnt32(void);
void	sxitimer_delay(u_int);

u_int sxitimer_get_timecount(struct timecounter *);

static struct timecounter sxitimer_timecounter = {
	sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
};

bus_space_tag_t		sxitimer_iot;
bus_space_handle_t	sxitimer_ioh;
bus_space_handle_t	sxitimer_cntr_ioh;

uint32_t sxitimer_freq[] = {
	TIMER0_FREQUENCY,
	TIMER1_FREQUENCY,
	TIMER2_FREQUENCY,
	0
};

uint32_t sxitimer_irq[] = {
	TIMER0_IRQ,
	TIMER1_IRQ,
	TIMER2_IRQ,
	0
};

uint32_t sxitimer_stat_tpi, sxitimer_tick_tpi;
uint32_t sxitimer_statvar, sxitimer_statmin;
uint32_t sxitimer_tick_nextevt, sxitimer_stat_nextevt;
uint32_t sxitimer_ticks_err_cnt, sxitimer_ticks_err_sum;

bus_addr_t cntr64_ctrl = CNT64_CTRL;
bus_addr_t cntr64_low = CNT64_LOW;
bus_addr_t cntr64_high = CNT64_HIGH;

struct sxitimer_softc {
	struct device		sc_dev;
};

struct cfattach	sxitimer_ca = {
	sizeof (struct sxitimer_softc), NULL, sxitimer_attach
};

struct cfdriver sxitimer_cd = {
	NULL, "sxitimer", DV_DULL
};

void
sxitimer_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	uint32_t freq, ival, now, cr, v;
	int unit = self->dv_unit;

	if (unit != 0)
		goto skip_init;

	sxitimer_iot = aa->aa_iot;

	if (bus_space_map(sxitimer_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sxitimer_ioh))
		panic("sxitimer_attach: bus_space_map failed!");

	if (board_id == BOARD_ID_SUN7I_A20) {
		if (bus_space_map(sxitimer_iot, CPUCNTRS_ADDR, CPUCNTRS_SIZE,
		    0, &sxitimer_cntr_ioh))
			panic("sxitimer_attach: bus_space_map failed!");

		cntr64_ctrl = OSC24M_CNT64_CTRL;
		cntr64_low = OSC24M_CNT64_LOW;
		cntr64_high = OSC24M_CNT64_HIGH;

		v = bus_space_read_4(sxitimer_iot, sxitimer_cntr_ioh,
		    cntr64_ctrl);
		bus_space_write_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_ctrl,
		    v | CNT64_SYNCH);
		bus_space_write_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_ctrl,
		    v & ~CNT64_SYNCH);
	} else
		sxitimer_cntr_ioh = sxitimer_ioh;

	/* clear counter, loop until ready */
	bus_space_write_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_ctrl,
	    CNT64_CLR_EN); /* XXX as a side-effect counter clk src=OSC24M */
	while (bus_space_read_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_ctrl)
	    & CNT64_CLR_EN)
		continue;

	/* setup timers */
	cr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL);
	cr |= OSC32K_SRC_SEL; /* ext 32.768KHz OSC src */
	bus_space_write_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL, cr);

skip_init:
	/* timers are down-counters, from interval to 0 */
	now = 0xffffffff; /* known big value */
	freq = sxitimer_freq[unit];

	/* stop timer, and set clk src */
	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(unit),
	    freq == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);

	switch (unit) { /* XXX more XXXXTIMER magic for less lines? */
	case TICKTIMER:
		ival = sxitimer_tick_tpi = freq / hz;
		sxitimer_tick_nextevt = now - ival;

		sxitimer_ticks_err_cnt = freq % hz;
		sxitimer_ticks_err_sum = 0;

		printf(": ticktimer %dhz @ %dKHz", hz, freq / 1000);
		break;
	case STATTIMER:
		/* 100/1000 or 128/1024 ? */
		stathz = 128;
		profhz = 1024;
		sxitimer_setstatclockrate(stathz);

		ival = sxitimer_stat_tpi = freq / stathz;
		sxitimer_stat_nextevt = now - ival;

		printf(": stattimer %dhz @ %dKHz", stathz, freq / 1000);
		break;
	case CNTRTIMER:
		ival = now;

		sxitimer_timecounter.tc_frequency = freq;
		tc_init(&sxitimer_timecounter);
		arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
		    sxitimer_setstatclockrate, NULL);

		printf(": cntrtimer @ %dKHz", freq / 1000);
		break;
	default:
		panic("sxitimer_attach: unit = %d", unit);
		break;
	}

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_INTV(unit), ival);

	printf("\n");
}

/*
 * would be interesting to play with trigger mode while having one timer
 * in 32KHz mode, and the other timer running in sysclk mode and use
 * the high resolution speeds (matters more for delay than tick timer)
 */

void
sxitimer_cpu_initclocks(void)
{
	uint32_t isr, ier;

	/* establish interrupts */
	arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
	    sxitimer_tickintr, NULL, "tick");
	arm_intr_establish(sxitimer_irq[STATTIMER], IPL_STATCLOCK,
	    sxitimer_statintr, NULL, "stattick");

	/* clear timer interrupt pending bits */
	isr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR);
	isr |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, isr);

	/* enable timer IRQs */
	ier = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_IER);
	ier |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_IER, ier);

	/* enable timers */
	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(CNTRTIMER),
	    TIMER_ENABLE | TIMER_RELOAD | TIMER_CONTINOUS);

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(STATTIMER),
	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(TICKTIMER),
	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
}

/*
 * See comment in arm/xscale/i80321_clock.c
 *
 * Counter is count up, but with autoreload timers it is not possible
 * to detect how many interrupts passed while interrupts were blocked.
 * Also it is not possible to atomically add to the register.
 *
 * To work around this two timers are used, one is used as a reference
 * clock without reload, however we just disable the interrupt it
 * could generate.
 *
 * 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.
 */
/* XXX update above comment */
int
sxitimer_tickintr(void *frame)
{
	uint32_t now, nextevent;
	int rc = 0;

	splassert(IPL_CLOCK);

	/* clear timer pending interrupt bit */
	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_ISR, TIMER_IRQ(TICKTIMER));

	now = sxitimer_readcnt32();

	while ((int32_t)(now - sxitimer_tick_nextevt) < 0) {
		sxitimer_tick_nextevt -= sxitimer_tick_tpi;
		sxitimer_ticks_err_sum += sxitimer_ticks_err_cnt;

		while (sxitimer_ticks_err_sum  > hz) {
			sxitimer_tick_nextevt += 1;
			sxitimer_ticks_err_sum -= hz;
		}

		rc = 1;
		hardclock(frame);
	}
	nextevent = now - sxitimer_tick_nextevt;
	if (nextevent < 10 /* XXX */)
		nextevent = 10;

	if (nextevent > sxitimer_tick_tpi) {
		/*
		 * 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 = sxitimer_tick_tpi;
		sxitimer_tick_nextevt = now;
	}

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_INTV(TICKTIMER), nextevent);

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(TICKTIMER),
	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);

	return rc;
}

int
sxitimer_statintr(void *frame)
{
	uint32_t now, nextevent, r;
	int rc = 0;

	splassert(IPL_STATCLOCK);

	/* clear timer pending interrupt bit */
	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_ISR, TIMER_IRQ(STATTIMER));

	now = sxitimer_readcnt32();
	while ((int32_t)(now - sxitimer_stat_nextevt) < 0) {
		do {
			r = random() & (sxitimer_statvar -1);
		} while (r == 0); /* random == 0 not allowed */
		sxitimer_stat_nextevt -= sxitimer_statmin + r;
		rc = 1;
		statclock(frame);
	}

	nextevent = now - sxitimer_stat_nextevt;

	if (nextevent < 10 /* XXX */)
		nextevent = 10;

	if (nextevent > sxitimer_stat_tpi) {
		/*
		 * 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 = sxitimer_stat_tpi;
		sxitimer_stat_nextevt = now;
	}

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_INTV(STATTIMER), nextevent);

	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CTRL(STATTIMER),
	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);

	return rc;
}

uint64_t
sxitimer_readcnt64(void)
{
	uint32_t low, high;

	/* latch counter, loop until ready */
	bus_space_write_4(sxitimer_iot, sxitimer_cntr_ioh,
	    cntr64_ctrl, CNT64_RL_EN);
	while (bus_space_read_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_ctrl)
	    & CNT64_RL_EN)
		continue;

	/*
	 * A10 usermanual doesn't mention anything about order, but fwiw
	 * iirc. A20 manual mentions that low should be read first.
	 */
	/* XXX check above */
	low = bus_space_read_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_low);
	high = bus_space_read_4(sxitimer_iot, sxitimer_cntr_ioh, cntr64_high);
	return (uint64_t)high << 32 | low;
}

uint32_t
sxitimer_readcnt32(void)
{
	return bus_space_read_4(sxitimer_iot, sxitimer_ioh,
	    TIMER_CURR(CNTRTIMER));
}

void
sxitimer_delay(u_int usecs)
{
	uint64_t oclock, timeout;

	oclock = sxitimer_readcnt64();
	timeout = oclock + (COUNTER_FREQUENCY / 1000000) * usecs;

	while (oclock < timeout)
		oclock = sxitimer_readcnt64();
}

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

	s = splstatclock();

	statint = sxitimer_freq[STATTIMER] / newhz;
	/* calculate largest 2^n which is smaller than just over half statint */
	sxitimer_statvar = 0x40000000; /* really big power of two */
	minint = statint / 2 + 100;
	while (sxitimer_statvar > minint)
		sxitimer_statvar >>= 1;

	sxitimer_statmin = statint - (sxitimer_statvar >> 1);

	splx(s);

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

u_int
sxitimer_get_timecount(struct timecounter *tc)
{
	return (u_int)UINT_MAX - sxitimer_readcnt32();
}


code:
/*	$OpenBSD: sxiuart.c,v 1.4 2015/04/22 11:39:04 jsg Exp $	*/
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
 * Copyright (c) 2013 Artturi Alm
 *
 * 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/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/uio.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/select.h>
#include <sys/kernel.h>

#include <dev/cons.h>

#ifdef DDB
#include <ddb/db_var.h>
#endif

#include <machine/bus.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/sunxi/sxiuartreg.h>
#include <armv7/sunxi/sunxireg.h>

#define DEVUNIT(x)      (minor(x) & 0x7f)
#define DEVCUA(x)       (minor(x) & 0x80)

struct sxiuart_softc {
	struct device	sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
	struct soft_intrhand *sc_si;
	void		*sc_irq;
	struct tty	*sc_tty;
	struct timeout	sc_diag_tmo;
	struct timeout	sc_dtr_tmo;
	int		sc_overflows;
	int		sc_floods;
	int		sc_errors;
	int		sc_halt;
	uint8_t		sc_ier;
	uint8_t		sc_mcr;
	uint8_t		sc_msr;
	uint8_t		sc_dtr;
	uint8_t		sc_lcr;
	int		sc_frequency;
	uint8_t		sc_hwflags;
#define COM_HW_NOIEN    0x01
#define COM_HW_FIFO     0x02
#define COM_HW_SIR      0x20
#define COM_HW_CONSOLE  0x40
#define COM_HW_KGDB     0x80
	uint8_t		sc_swflags;
#define COM_SW_SOFTCAR  0x01
#define COM_SW_CLOCAL   0x02
#define COM_SW_CRTSCTS  0x04
#define COM_SW_MDMBUF   0x08
#define COM_SW_PPS      0x10

	uint8_t		sc_initialize;
	uint8_t		sc_cua;
	uint8_t		*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
#define SXIUART_IBUFSIZE 128
#define SXIUART_IHIGHWATER 100
	uint8_t		sc_ibufs[2][SXIUART_IBUFSIZE];
};

int	sxiuartprobe(struct device *, void *, void *);
void	sxiuartattach(struct device *, struct device *, void *);

void sxiuartcnprobe(struct consdev *);
void sxiuartcninit(struct consdev *);
int sxiuartcnattach(bus_space_tag_t, bus_addr_t, int, long, tcflag_t);
int sxiuartcngetc(dev_t);
void sxiuartcnputc(dev_t, int);
void sxiuartcnpollc(dev_t, int);
int sxiuart_param(struct tty *, struct termios *);
void sxiuart_start(struct tty *);
void sxiuart_pwroff(struct sxiuart_softc *);
void sxiuart_diag(void *);
void sxiuart_raisedtr(void *);
void sxiuart_softint(void *);
int sxiuart_intr(void *);

struct sxiuart_softc *sxiuart_sc(dev_t);

/* XXX - we imitate 'com' serial ports and take over their entry points */
/* XXX: These belong elsewhere */
cdev_decl(sxiuart);

struct cfattach sxiuart_ca = {
	sizeof(struct sxiuart_softc), NULL, sxiuartattach
};

struct cfdriver sxiuart_cd = {
	NULL, "sxiuart", DV_TTY
};

struct consdev sxiuartcons = {
	sxiuartcnprobe, sxiuartcninit,
	sxiuartcngetc, sxiuartcnputc,
	sxiuartcnpollc, NULL,
	NODEV, CN_HIGHPRI
};

bus_space_tag_t	sxiuartconsiot;
bus_space_handle_t sxiuartconsioh;
bus_addr_t	sxiuartconsaddr;
tcflag_t	sxiuartconscflag = TTYDEF_CFLAG;
int		sxiuartdefaultrate = B115200;

struct cdevsw sxiuartdev =
	cdev_tty_init(1/*XXX NIMXUART */ , sxiuart); /* 12: serial port */

void
sxiuartattach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct sxiuart_softc *sc = (struct sxiuart_softc *) self;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	int s;

	sc->sc_iot = iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
		panic("sxiuartattach: bus_space_map failed!");
	ioh = sc->sc_ioh;

	if (aa->aa_dev->mem[0].addr == sxiuartconsaddr) {
		cn_tab->cn_dev = makedev(12 /* XXX */, 0);
		cdevsw[12] = sxiuartdev;		/* KLUDGE */

		printf(": console");
		/* XXX compare uses of COM_HW_CONSOLE against com.c */
		SET(sc->sc_hwflags, COM_HW_CONSOLE);
		SET(sc->sc_swflags, COM_SW_SOFTCAR);
		sxiuartconsiot = iot;
		sxiuartconsioh = ioh;
	}

	timeout_set(&sc->sc_diag_tmo, sxiuart_diag, sc);
	timeout_set(&sc->sc_dtr_tmo, sxiuart_raisedtr, sc);
	sc->sc_si = softintr_establish(IPL_TTY, sxiuart_softint, sc);
	if(sc->sc_si == NULL)
		panic("%s: can't establish soft interrupt.",
		    sc->sc_dev.dv_xname);

	sc->sc_frequency = 24000000; /* XXX */

	if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, SXIUART_IIR) &
	  IIR_BUSY) == IIR_BUSY)
		(void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, SXIUART_USR);
	sc->sc_ier = 0;
	/* disable interrupts */
	bus_space_write_1(iot, ioh, SXIUART_IER, sc->sc_ier);

	/* clear and disable fifo */
	bus_space_write_1(iot, ioh, SXIUART_FCR, 0 | RFIFOR | XFIFOR);

	s = splhigh();
	SET(sc->sc_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
	bus_space_write_1(sc->sc_iot, sc->sc_ioh, SXIUART_MCR, sc->sc_mcr);
	splx(s);

	arm_intr_establish(aa->aa_dev->irq[0], IPL_TTY,
	    sxiuart_intr, sc, sc->sc_dev.dv_xname);

	printf("\n");
}

int
sxiuart_intr(void *arg)
{
	struct sxiuart_softc *sc = arg;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp;
	uint32_t cnt;
	uint8_t c, iir, lsr, msr, delta;
	uint8_t *p;

	iir = bus_space_read_1(iot, ioh, SXIUART_IIR);

	if ((iir & IIR_IMASK) == IIR_BUSY) {
		(void)bus_space_read_1(iot, ioh, SXIUART_USR);
		return (0);
	}
	if (ISSET(iir, IIR_NOPEND))
		return (0);

	if (sc->sc_tty == NULL)
		return (0);

	tp = sc->sc_tty;
	cnt = 0;
loop:
	lsr = bus_space_read_1(iot, ioh, SXIUART_LSR);
	if (ISSET(lsr, LSR_RXRDY)) {
		if (cnt == 0) {
			p = sc->sc_ibufp;
			softintr_schedule(sc->sc_si);
		}
		cnt++;

		c = bus_space_read_1(iot, ioh, SXIUART_RBR);
		if (ISSET(lsr, LSR_BI)) {
#if defined(DDB)
			if (ISSET(sc->sc_hwflags,
			    COM_HW_CONSOLE)) {
				if (db_console)
					Debugger();
				goto loop;
			}
#endif
			c = 0;
		}
		if (p >= sc->sc_ibufend) {
			sc->sc_floods++;
			if (sc->sc_errors++ == 0)
				timeout_add_sec(&sc->sc_diag_tmo, 60);
		} else {
			*p++ = c;
			*p++ = lsr;
			if (p == sc->sc_ibufhigh &&
			    ISSET(tp->t_cflag, CRTSCTS)) {
				/* XXX */
				CLR(sc->sc_mcr, MCR_RTS);
				bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
			}
		}
		goto loop;
	} else if (cnt > 0)
		sc->sc_ibufp = p;

	msr = bus_space_read_1(iot, ioh, SXIUART_MSR);
	if (msr != sc->sc_msr) {
		delta = msr ^ sc->sc_msr;

		ttytstamp(tp, sc->sc_msr & MSR_CTS,
		    msr & MSR_CTS, sc->sc_msr & MSR_DCD,
		    msr & MSR_DCD);

		sc->sc_msr = msr;
		if (ISSET(delta, MSR_DCD)) {
			if (!ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
			    (*linesw[tp->t_line].l_modem)(tp,
			    ISSET(msr, MSR_DCD)) == 0) {
				CLR(sc->sc_mcr, sc->sc_dtr);
				bus_space_write_1(iot, ioh, SXIUART_MCR,
				    sc->sc_mcr);
			}
		}
		if (ISSET(delta & msr, MSR_CTS) &&
		    ISSET(tp->t_cflag, CRTSCTS))
			(*linesw[tp->t_line].l_start)(tp);
	}

	if (ISSET(tp->t_state, TS_BUSY) && ISSET(lsr, LSR_TXRDY)) {
		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
		if (sc->sc_halt > 0)
			wakeup(&tp->t_outq);
		(*linesw[tp->t_line].l_start)(tp);
	}

	iir = bus_space_read_1(iot, ioh, SXIUART_IIR);

	if (ISSET(iir, IIR_NOPEND))
		goto done;

	cnt = 0;
	goto loop;
done:
	return (1);
}

int
sxiuart_param(struct tty *tp, struct termios *t)
{
	struct sxiuart_softc *sc = sxiuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	int ospeed = t->c_ospeed;
	int error;
	tcflag_t oldcflag;
	uint16_t ratediv;
	uint8_t lcr = 0;

	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
		return (EINVAL);

	/* XXX get prev state of SXIUART_LCR_SBREAK bit */

	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		SET(lcr, LCR_5BITS);
		break;
	case CS6:
		SET(lcr, LCR_6BITS);
		break;
	case CS7:
		SET(lcr, LCR_7BITS);
		break;
	case CS8:
		SET(lcr, LCR_8BITS);
		break;
	}
	if (ISSET(t->c_cflag, PARENB)) {
		SET(lcr, LCR_PENAB);
		if (!ISSET(t->c_cflag, PARODD))
			SET(lcr, LCR_PEVEN);
	}
	if (ISSET(t->c_cflag, CSTOPB))
		SET(lcr, LCR_STOPB);

	sc->sc_lcr = lcr;

	if (ospeed == 0) {
		CLR(sc->sc_mcr, MCR_DTR);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
	}

	if (ospeed != 0) { /* XXX sc_initialize? */
		while (ISSET(tp->t_state, TS_BUSY)) {
			++sc->sc_halt;
			error = ttysleep(tp, &tp->t_outq,
			    TTOPRI | PCATCH, "sxiuartprm", 0);
			--sc->sc_halt;
			if (error) {
				sxiuart_start(tp);
				return (error);
			}
		}
		bus_space_write_1(iot, ioh, SXIUART_LCR, lcr | LCR_DLAB);
		ratediv = 13;
		bus_space_write_1(iot, ioh, SXIUART_DLL, ratediv);
		bus_space_write_1(iot, ioh, SXIUART_DLH, ratediv >> 8);
		bus_space_write_1(iot, ioh, SXIUART_LCR, lcr);
		SET(sc->sc_mcr, MCR_DTR);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
	} else
		bus_space_write_1(iot, ioh, SXIUART_LCR, lcr);

	/* setup fifo */
	bus_space_write_1(iot, ioh, SXIUART_FCR, FIFOE | FIFO_RXT0);

	/* When not using CRTSCTS, RTS follows DTR. */
	if (!ISSET(t->c_cflag, CRTSCTS)) {
		if (ISSET(sc->sc_mcr, MCR_DTR)) {
			if (!ISSET(sc->sc_mcr, MCR_RTS)) {
				SET(sc->sc_mcr, MCR_RTS);
				bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
			}
		} else {
			if (ISSET(sc->sc_mcr, MCR_RTS)) {
				CLR(sc->sc_mcr, MCR_RTS);
				bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
			}
		}
		sc->sc_dtr = MCR_DTR | MCR_RTS;
	} else
		sc->sc_dtr = MCR_DTR;

	/* and copy to tty */
	tp->t_ispeed = t->c_ispeed;
	tp->t_ospeed = t->c_ospeed;
	oldcflag = tp->t_cflag;
	tp->t_cflag = t->c_cflag;

        /*
	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
	 * stop the device.
	 */
	if (!ISSET(sc->sc_msr, MSR_DCD) &&
	    !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
	    ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) &&
	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
		CLR(sc->sc_mcr, sc->sc_dtr);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
	}

	sxiuart_start(tp);

	return (0);
}

void
sxiuart_start(struct tty *tp)
{
        struct sxiuart_softc *sc = sxiuart_sc(tp->t_dev);
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	int i, n, s;
	uint8_t buf[64];

	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY)) {
		splx(s);
		return;
	}
	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
		goto stopped;
	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS))
		goto stopped;
#if 0
	if (tp->t_outq.c_cc <= tp->t_lowat) {
		if (ISSET(tp->t_state, TS_ASLEEP)) {
			CLR(tp->t_state, TS_ASLEEP);
			wakeup(&tp->t_outq);
		}
		if (tp->t_outq.c_cc == 0)
			goto stopped;
		selwakeup(&tp->t_wsel);
	}
#else
	ttwakeupwr(tp);
	if (tp->t_outq.c_cc == 0)
		goto stopped;
#endif
	SET(tp->t_state, TS_BUSY);

	if (!ISSET(sc->sc_ier, IER_ETXRDY)) {
		SET(sc->sc_ier, IER_ETXRDY);
		bus_space_write_1(iot, ioh, SXIUART_IER, sc->sc_ier);
	}

	n = q_to_b(&tp->t_outq, buf, sizeof(buf));
	for (i = 0; i < n; i++)
		bus_space_write_1(iot, ioh, SXIUART_THR, buf[i]);
	bzero(buf, n);
	splx(s);
	return;
stopped:
	if (ISSET(sc->sc_ier, IER_ETXRDY)) {
		CLR(sc->sc_ier, IER_ETXRDY);
		bus_space_write_1(iot, ioh, SXIUART_IER, sc->sc_ier);
	}
	splx(s);
}

void
sxiuart_pwroff(struct sxiuart_softc *sc)
{
}

void
sxiuart_diag(void *arg)
{
	struct sxiuart_softc *sc = arg;
	int overflows, floods;
	int s = spltty();
	sc->sc_errors = 0;
	overflows = sc->sc_overflows;
	sc->sc_overflows = 0;
	floods = sc->sc_floods;
	sc->sc_floods = 0;
	splx(s);
	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
	    sc->sc_dev.dv_xname,
	    overflows, overflows == 1 ? "" : "s",
	    floods, floods == 1 ? "" : "s");
}

void
sxiuart_raisedtr(void *arg)
{
	struct sxiuart_softc *sc = arg;

	SET(sc->sc_mcr, MCR_DTR | MCR_RTS);
	bus_space_write_1(sc->sc_iot, sc->sc_ioh, SXIUART_MCR, sc->sc_mcr);
}

void
sxiuart_softint(void *arg)
{
	struct sxiuart_softc *sc = arg;
	struct tty *tp;
	uint8_t *ibufp;
	uint8_t *ibufend;
	int c, s;
	static int lsrmap[8] = {
		0,	TTY_PE,
		TTY_FE,	TTY_PE|TTY_FE,
		TTY_FE,	TTY_PE|TTY_FE,
		TTY_FE,	TTY_PE|TTY_FE
	};

	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
		return;
	tp = sc->sc_tty;

	s = spltty();

	ibufp = sc->sc_ibuf;
	ibufend = sc->sc_ibufp;

	if (ibufp == ibufend) {
		splx(s);
		return;
	}

	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
				     sc->sc_ibufs[1] : sc->sc_ibufs[0];
	sc->sc_ibufhigh = sc->sc_ibuf + SXIUART_IHIGHWATER;
	sc->sc_ibufend = sc->sc_ibuf + SXIUART_IBUFSIZE;

	if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
		splx(s);
		return;
	}

	if (ISSET(tp->t_cflag, CRTSCTS) &&
	    !ISSET(sc->sc_mcr, MCR_RTS)) {
		/* XXX */
		SET(sc->sc_mcr, MCR_RTS);
		bus_space_write_1(sc->sc_iot, sc->sc_ioh, SXIUART_MCR,
		    sc->sc_mcr);
	}

	splx(s);

	while (ibufp < ibufend) {
		c = *ibufp++;
		if (ISSET(*ibufp, LSR_OE)) {
			sc->sc_overflows++;
			if (sc->sc_errors++ == 0)
				timeout_add_sec(&sc->sc_diag_tmo, 60);
		}
		/* This is ugly, but fast. */
#define ASD (LSR_BI | LSR_FE | LSR_PE)
		c |= lsrmap[(*ibufp++ & ASD) >> 2];
#undef ASD
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
}

int
sxiuartopen(dev_t dev, int flag, int mode, struct proc *p)
{
	struct sxiuart_softc *sc;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	struct tty *tp;
	int s;
	int error = 0;

	sc = sxiuart_sc(dev);
	if (sc == NULL)
		return (ENXIO);

	s = spltty();
	if (sc->sc_tty == NULL)
		tp = sc->sc_tty = ttymalloc(1000000);
	else
		tp = sc->sc_tty;
	splx(s);

	tp->t_oproc = sxiuart_start;
	tp->t_param = sxiuart_param;
	tp->t_dev = dev;

	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		SET(tp->t_state, TS_WOPEN);
		ttychars(tp);
		tp->t_iflag = TTYDEF_IFLAG;
		tp->t_oflag = TTYDEF_OFLAG;

		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
			tp->t_cflag = sxiuartconscflag;
		else
			tp->t_cflag = TTYDEF_CFLAG;
		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
			SET(tp->t_cflag, CLOCAL);
		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
			SET(tp->t_cflag, CRTSCTS);
		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
			SET(tp->t_cflag, MDMBUF);
		tp->t_lflag = TTYDEF_LFLAG;
		tp->t_ispeed = tp->t_ospeed = sxiuartdefaultrate;

		s = spltty();

		sc->sc_initialize = 1;
		sxiuart_param(tp, &tp->t_termios);
		ttsetwater(tp);

		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
		sc->sc_ibufhigh = sc->sc_ibuf + SXIUART_IHIGHWATER;
		sc->sc_ibufend = sc->sc_ibuf + SXIUART_IBUFSIZE;

		iot = sc->sc_iot;
		ioh = sc->sc_ioh;

		bus_space_write_1(iot, ioh, SXIUART_FCR, FIFOE | FIFO_RXT2);
		delay(100);
		while (ISSET(bus_space_read_1(iot, ioh, SXIUART_LSR),
		    LSR_RXRDY))
			(void)bus_space_read_1(iot, ioh, SXIUART_RBR);

		sc->sc_mcr = MCR_DTR | MCR_RTS | MCR_IENABLE;
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);

		sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC;
		bus_space_write_1(iot, ioh, SXIUART_IER, sc->sc_ier);

		sc->sc_msr = bus_space_read_1(iot, ioh, SXIUART_MSR);
		if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) || DEVCUA(dev) ||
		    ISSET(sc->sc_msr, MSR_DCD) ||
		    ISSET(tp->t_cflag, MDMBUF))
			SET(tp->t_state, TS_CARR_ON);
		else
			CLR(tp->t_state, TS_CARR_ON);

	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p, 0) != 0)
		return (EBUSY);
	else
		s = spltty();

	if (DEVCUA(dev)) {
		if (ISSET(tp->t_state, TS_ISOPEN)) {
			splx(s);
			return (EBUSY);
		}
		sc->sc_cua = 1;
	} else {
		/* tty (not cua) device; wait for carrier if necessary */
		if (ISSET(flag, O_NONBLOCK)) {
			if (sc->sc_cua) {
				/* Opening TTY non-blocking... but the CUA is busy */
				splx(s);
				return (EBUSY);
			}
		} else {
			while (sc->sc_cua ||
			    (!ISSET(tp->t_cflag, CLOCAL) &&
				!ISSET(tp->t_state, TS_CARR_ON))) {
				SET(tp->t_state, TS_WOPEN);
				error = ttysleep(tp, &tp->t_rawq,
				    TTIPRI | PCATCH, ttopen, 0);
				/*
				 * If TS_WOPEN has been reset, that means the
				 * cua device has been closed.  We don't want
				 * to fail in that case,
				 * so just go around again.
				 */
				if (error && ISSET(tp->t_state, TS_WOPEN)) {
					CLR(tp->t_state, TS_WOPEN);
					if (!sc->sc_cua && !ISSET(tp->t_state,
					    TS_ISOPEN))
						sxiuart_pwroff(sc);
					splx(s);
					return (error);
				}
			}
		}
	}
	splx(s);

	return (*linesw[tp->t_line].l_open)(dev, tp, p);
}

int
sxiuartclose(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct sxiuart_softc *sc = sxiuart_cd.cd_devs[unit];
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp = sc->sc_tty;
	int s;

	/* XXX This is for cons.c. */
	if (!ISSET(tp->t_state, TS_ISOPEN))
		return (0);

	(*linesw[tp->t_line].l_close)(tp, flag, p);
	s = spltty();
	if (ISSET(tp->t_state, TS_WOPEN)) {
		/* tty device is waiting for carrier; drop dtr then re-raise */
		CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
		timeout_add(&sc->sc_dtr_tmo, hz * 2);
	} else {
		/* no one else waiting; turn off the uart */
		sxiuart_pwroff(sc);
	}
	CLR(tp->t_state, TS_BUSY | TS_FLUSH);

	sc->sc_cua = 0;
	splx(s);
	ttyclose(tp);

	return (0);
}

int
sxiuartread(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = sxiuarttty(dev);
	if (tty == NULL)
		return (ENODEV);

	return ((*linesw[tty->t_line].l_read)(tty, uio, flag));
}

int
sxiuartwrite(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = sxiuarttty(dev);
	if (tty == NULL)
		return (ENODEV);

	return ((*linesw[tty->t_line].l_write)(tty, uio, flag));
}

static u_char tiocm_xxx2mcr(int);

static u_char
tiocm_xxx2mcr(int data)
{
	u_char m = 0;

	if (ISSET(data, TIOCM_DTR))
		SET(m, MCR_DTR);
	if (ISSET(data, TIOCM_RTS))
		SET(m, MCR_RTS);
	return m;
}

int
sxiuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct sxiuart_softc *sc;
	struct tty *tp;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	int error;

	sc = sxiuart_sc(dev);
	if (sc == NULL)
		return (ENODEV);

	tp = sc->sc_tty;
	if (tp == NULL)
		return (ENXIO);

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	iot = sc->sc_iot;
	ioh = sc->sc_ioh;

	switch (cmd) {
	case TIOCSBRK:
		SET(sc->sc_lcr, LCR_SBREAK);
		bus_space_write_1(iot, ioh, SXIUART_LCR, sc->sc_lcr);
		break;
	case TIOCCBRK:
		CLR(sc->sc_lcr, LCR_SBREAK);
		bus_space_write_1(iot, ioh, SXIUART_LCR, sc->sc_lcr);
		break;
	case TIOCSDTR:
		SET(sc->sc_mcr, sc->sc_dtr);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
		break;
	case TIOCCDTR:
		CLR(sc->sc_mcr, sc->sc_dtr);
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
		break;
	case TIOCMSET:
		CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
	case TIOCMBIS:
		SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
		break;
	case TIOCMBIC:
		CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
		bus_space_write_1(iot, ioh, SXIUART_MCR, sc->sc_mcr);
		break;
	case TIOCMGET: {
		u_char m;
		int bits = 0;

		m = sc->sc_mcr;
		if (ISSET(m, MCR_DTR))
			SET(bits, TIOCM_DTR);
		if (ISSET(m, MCR_RTS))
			SET(bits, TIOCM_RTS);
		m = sc->sc_msr;
		if (ISSET(m, MSR_DCD))
			SET(bits, TIOCM_CD);
		if (ISSET(m, MSR_CTS))
			SET(bits, TIOCM_CTS);
		if (ISSET(m, MSR_DSR))
			SET(bits, TIOCM_DSR);
		if (ISSET(m, MSR_RI | MSR_TERI))
			SET(bits, TIOCM_RI);
		if (bus_space_read_1(iot, ioh, SXIUART_IER))
			SET(bits, TIOCM_LE);
		*(int *)data = bits;
		break;
	}
	case TIOCGFLAGS: {
		int driverbits, userbits = 0;

		driverbits = sc->sc_swflags;
		if (ISSET(driverbits, COM_SW_SOFTCAR))
			SET(userbits, TIOCFLAG_SOFTCAR);
		if (ISSET(driverbits, COM_SW_CLOCAL))
			SET(userbits, TIOCFLAG_CLOCAL);
		if (ISSET(driverbits, COM_SW_CRTSCTS))
			SET(userbits, TIOCFLAG_CRTSCTS);
		if (ISSET(driverbits, COM_SW_MDMBUF))
			SET(userbits, TIOCFLAG_MDMBUF);
		if (ISSET(driverbits, COM_SW_PPS))
			SET(userbits, TIOCFLAG_PPS);

		*(int *)data = userbits;
		break;
	}
	case TIOCSFLAGS: {
		int userbits, driverbits = 0;

		error = suser(p, 0);
		if (error != 0)
			return(EPERM);

		userbits = *(int *)data;
		if (ISSET(userbits, TIOCFLAG_SOFTCAR) ||
		    ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
			SET(driverbits, COM_SW_SOFTCAR);
		if (ISSET(userbits, TIOCFLAG_CLOCAL))
			SET(driverbits, COM_SW_CLOCAL);
		if (ISSET(userbits, TIOCFLAG_CRTSCTS))
			SET(driverbits, COM_SW_CRTSCTS);
		if (ISSET(userbits, TIOCFLAG_MDMBUF))
			SET(driverbits, COM_SW_MDMBUF);
		if (ISSET(userbits, TIOCFLAG_PPS))
			SET(driverbits, COM_SW_PPS);

		sc->sc_swflags = driverbits;
		break;
	}
	default:
		return (ENOTTY);
	}

	return (0);
}

int
sxiuartstop(struct tty *tp, int flag)
{
	return (0);
}

struct tty *
sxiuarttty(dev_t dev)
{
	int unit;
	struct sxiuart_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= sxiuart_cd.cd_ndevs)
		return (NULL);
	sc = (struct sxiuart_softc *)sxiuart_cd.cd_devs[unit];
	if (sc == NULL)
		return (NULL);
	return (sc->sc_tty);
}

struct sxiuart_softc *
sxiuart_sc(dev_t dev)
{
	int unit;
	struct sxiuart_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= sxiuart_cd.cd_ndevs)
		return (NULL);
	sc = (struct sxiuart_softc *)sxiuart_cd.cd_devs[unit];
	return (sc);
}

/* serial console */
void
sxiuartcnprobe(struct consdev *cp)
{
	cp->cn_dev = makedev(12 /* XXX */, 0);
	cp->cn_pri = CN_HIGHPRI;
}

void
sxiuartcninit(struct consdev *cp)
{
}

int
sxiuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, long freq,
	tcflag_t cflag)
{
	int s;
	uint16_t ratediv;

	if (bus_space_map(iot, iobase, UARTx_SIZE, 0, &sxiuartconsioh))
		return (ENOMEM);

	sxiuartconsiot = iot;
	sxiuartconsaddr = iobase;
	sxiuartconscflag = cflag;

	s = splhigh();
	bus_space_write_1(iot, sxiuartconsioh, SXIUART_LCR, LCR_DLAB);

	ratediv = 13; /* for 115200baud with 24000000hz freq */
	bus_space_write_1(iot, sxiuartconsioh, SXIUART_DLL, ratediv);
	bus_space_write_1(iot, sxiuartconsioh, SXIUART_DLH, ratediv >> 8);
	bus_space_write_1(iot, sxiuartconsioh, SXIUART_LCR, LCR_8BITS);

	bus_space_write_1(iot, sxiuartconsioh, SXIUART_MCR, MCR_DTR | MCR_RTS);
	bus_space_write_1(iot, sxiuartconsioh, SXIUART_IER, 0);

	bus_space_write_1(iot, sxiuartconsioh, SXIUART_FCR, FIFOE | FIFO_RXT0);

	(void)bus_space_read_1(iot, sxiuartconsioh, SXIUART_IIR);
	splx(s);

	cn_tab = &sxiuartcons;

	return (0);
}

int
sxiuartcngetc(dev_t dev)
{
	int s;
	uint8_t c;

	s = splhigh();

	while (!ISSET(bus_space_read_1(sxiuartconsiot, sxiuartconsioh,
	    SXIUART_LSR), LSR_RXRDY))
		continue;
	c = bus_space_read_1(sxiuartconsiot, sxiuartconsioh, SXIUART_RBR);

	/* clear any pending interrupts */
	(void)bus_space_read_1(sxiuartconsiot, sxiuartconsioh, SXIUART_IIR);

	splx(s);
	return (c);
}

void
sxiuartcnputc(dev_t dev, int c)
{
	int s = spltty();
	int timo = 500;

	while (!ISSET(bus_space_read_1(sxiuartconsiot, sxiuartconsioh,
	    SXIUART_LSR), LSR_THRE) && --timo)
		continue;

	bus_space_write_1(sxiuartconsiot, sxiuartconsioh, SXIUART_THR,
	    (uint8_t)c);
	bus_space_barrier(sxiuartconsiot, sxiuartconsioh, 0, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);

	splx(s);
}

void
sxiuartcnpollc(dev_t dev, int on)
{
}

license: unknown


code:
#define	SXIUART_RBR	0x00
#define	SXIUART_THR	0x00
#define SXIUART_DLL	0x00
#define SXIUART_DLH	0x04
#define SXIUART_IER	0x04
#define SXIUART_IIR	0x08
#define SXIUART_FCR	0x08
#define SXIUART_LCR	0x0c
#define SXIUART_MCR	0x10
#define SXIUART_LSR	0x14
#define SXIUART_MSR	0x18
#define SXIUART_SCH	0x1c
#define SXIUART_USR	0x7c
#define SXIUART_TFL	0x80
#define SXIUART_RFL	0x84
#define SXIUART_HALT	0xa4

/* interrupt enable register */
#define IER_PTIME	0x80
#define	IER_EDSSI	0x08
#define IER_EMSC	IER_EDSSI
#define	IER_ELSI	0x04
#define IER_ERLS	IER_ELSI
#define	IER_ETBEI	0x02
#define IER_ETXRDY	IER_ETBEI
#define	IER_ERBFI	0x01
#define IER_ERXRDY	IER_ERBFI

/* interrupt identification register */
#define	IIR_IMASK	0x0f
#define	IIR_RXTOUT	0x0c
#define	IIR_BUSY	0x07
#define	IIR_RLS		0x06
#define	IIR_RXRDY	0x04
#define	IIR_TXRDY	0x02
#define	IIR_MLSC	0x00
#define	IIR_NOPEND	0x01
#define	IIR_FIFO_MASK	0xc0

/* fifo control register */
#define	FIFO_RXT3	0xc0	/* FIFOSIZE-2 chars in rxfifo */
#define	FIFO_RXT2	0x80	/* rxfifo 1/2 full */
#define	FIFO_RXT1	0x40	/* rxfifo 1/4 full */
#define	FIFO_RXT0	0x00	/* 1char in rxfifo */
#define FIFO_TXT3	0x30	/* txfifo 1/2 full */
#define FIFO_TXT2	0x20	/* txfifo 1/4 full */
#define FIFO_TXT1	0x10	/* 2chars in txfifo */
#define FIFO_TXT0	0x00	/* txfifo empty */
#define	DMAM		0x08
#define	XFIFOR		0x04	/* txfifo reset */
#define	RFIFOR		0x02	/* rxfifo reset */
#define	FIFOE		0x01	/* enable, resets fifos when changed */

/* line control register */
#define	LCR_DLAB	0x80
#define	LCR_SBREAK	0x40
#define	LCR_PZERO	0x38
#define	LCR_PONE	0x28
#define	LCR_PEVEN	0x18
#define	LCR_PODD	0x08
#define	LCR_PNONE	0x00
#define	LCR_PENAB	0x08
#define	LCR_STOPB	0x04
#define	LCR_8BITS	0x03
#define	LCR_7BITS	0x02
#define	LCR_6BITS	0x01
#define	LCR_5BITS	0x00

/* modem control register */
#define MCR_SIRE	0x40
#define	MCR_AFCE	0x20
#define	MCR_LOOPBACK	0x10
#define	MCR_IENABLE	0x08 /* XXX */
#define	MCR_DRS		0x04 /* XXX */
#define	MCR_RTS		0x02
#define	MCR_DTR		0x01

/* line status register */
#define	LSR_RCV_FIFO	0x80
#define	LSR_TSRE	0x40
#define	LSR_TEMT	LSR_TSRE
#define	LSR_TXRDY	0x20
#define	LSR_THRE	LSR_TXRDY
#define	LSR_BI		0x10
#define	LSR_FE		0x08
#define	LSR_PE		0x04
#define	LSR_OE		0x02
#define	LSR_RXRDY	0x01
#define	LSR_RCV_MASK	0x1f

/* modem status register */
/* All deltas are from the last read of the MSR. */
#define	MSR_DCD		0x80
#define	MSR_RI		0x40
#define	MSR_DSR		0x20
#define	MSR_CTS		0x10
#define	MSR_DDCD	0x08
#define	MSR_TERI	0x04
#define	MSR_DDSR	0x02
#define	MSR_DCTS	0x01

/* uart status register */
#define	USR_RFF		0x10
#define	USR_RFNE	0x08
#define	USR_TFE		0x04
#define	USR_TFNF	0x02
#define	USR_BUSY	0x01


code:
#	$OpenBSD: files.vexpress,v 1.2 2015/06/14 05:01:31 jsg Exp $

define vexpress {}
device vexpress: vexpress
attach vexpress at mainbus
file	arch/armv7/vexpress/vexpress_machdep.c	vexpress needs-flag
file	arch/armv7/vexpress/vexpress.c		vexpress
file	arch/armv7/vexpress/vexpress_a9.c	vexpress
file	arch/armv7/vexpress/vexpress_a15.c	vexpress

device pluart
attach pluart at vexpress
file	arch/armv7/vexpress/pl011.c	pluart

device plrtc
attach plrtc at vexpress
file	arch/armv7/vexpress/pl031.c	plrtc

attach	virtio at vexpress with virtio_mmio
file	arch/armv7/vexpress/virtio_mmio.c	virtio_mmio

device sysreg
attach sysreg at vexpress
file	arch/armv7/vexpress/sysreg.c	sysreg


code:
/*	$OpenBSD: pl011.c,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/

/*
 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
 * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/uio.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/select.h>
#include <sys/kernel.h>

#include <dev/cons.h>

#ifdef DDB
#include <ddb/db_var.h>
#endif

#include <machine/bus.h>
//#include <machine/clock.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/vexpress/pl011reg.h>
#include <armv7/vexpress/pl011var.h>
#include <armv7/armv7/armv7var.h>

#define DEVUNIT(x)      (minor(x) & 0x7f)
#define DEVCUA(x)       (minor(x) & 0x80)

struct pl011_softc {
	struct device	sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
	struct soft_intrhand *sc_si;
	void *sc_irq;
	struct tty	*sc_tty;
	struct timeout	sc_diag_tmo;
	struct timeout	sc_dtr_tmo;
	int		sc_overflows;
	int		sc_floods;
	int		sc_errors;
	int		sc_halt;
	u_int16_t	sc_ucr1;
	u_int16_t	sc_ucr2;
	u_int16_t	sc_ucr3;
	u_int16_t	sc_ucr4;
	u_int8_t	sc_hwflags;
#define COM_HW_NOIEN    0x01
#define COM_HW_FIFO     0x02
#define COM_HW_SIR      0x20
#define COM_HW_CONSOLE  0x40
#define COM_HW_KGDB     0x80
	u_int8_t	sc_swflags;
#define COM_SW_SOFTCAR  0x01
#define COM_SW_CLOCAL   0x02
#define COM_SW_CRTSCTS  0x04
#define COM_SW_MDMBUF   0x08
#define COM_SW_PPS      0x10
	int		sc_fifolen;

	u_int8_t	sc_initialize;
	u_int8_t	sc_cua;
	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
#define UART_IBUFSIZE 128
#define UART_IHIGHWATER 100
	u_int16_t		sc_ibufs[2][UART_IBUFSIZE];

	struct clk	*sc_clk;
};

int     pl011probe(struct device *parent, void *self, void *aux);
void    pl011attach(struct device *parent, struct device *self, void *aux);

void pl011cnprobe(struct consdev *cp);
void pl011cnprobe(struct consdev *cp);
void pl011cninit(struct consdev *cp);
int pl011cnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
    tcflag_t cflag);
int pl011cngetc(dev_t dev);
void pl011cnputc(dev_t dev, int c);
void pl011cnpollc(dev_t dev, int on);
int  pl011_param(struct tty *tp, struct termios *t);
void pl011_start(struct tty *);
void pl011_pwroff(struct pl011_softc *sc);
void pl011_diag(void *arg);
void pl011_raisedtr(void *arg);
void pl011_softint(void *arg);
struct pl011_softc *pl011_sc(dev_t dev);

int pl011_intr(void *);

/* XXX - we imitate 'com' serial ports and take over their entry points */
/* XXX: These belong elsewhere */
cdev_decl(pl011);

struct cfdriver pluart_cd = {
	NULL, "pluart", DV_TTY
};

struct cfattach pluart_ca = {
	sizeof(struct pl011_softc), pl011probe, pl011attach
};

bus_space_tag_t	pl011consiot;
bus_space_handle_t pl011consioh;
bus_addr_t	pl011consaddr;
tcflag_t	pl011conscflag = TTYDEF_CFLAG;
int		pl011defaultrate = B38400;

int
pl011probe(struct device *parent, void *self, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("arm,pl011", aa->aa_node))
		return 1;
#endif

	return 0;
}

struct cdevsw pl011dev =
	cdev_tty_init(3/*XXX NUART */ ,pl011);		/* 12: serial port */

void
pl011attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct pl011_softc *sc = (struct pl011_softc *) self;
	struct armv7mem mem;
	int irq;

#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;

		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			  __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;

		if (fdt_node_property_ints(aa->aa_node, "interrupts",
		    ints, 3) != 3)
			panic("%s: could not extract interrupt data from FDT",
			    __func__);
		irq = ints[1];
	} else
#endif
	{
		irq = aa->aa_dev->irq[0];
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}

	sc->sc_irq = arm_intr_establish(irq, IPL_TTY, pl011_intr,
	    sc, sc->sc_dev.dv_xname);

	sc->sc_iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("pl011attach: bus_space_map failed!");

	if (mem.addr == pl011consaddr)
		printf(" console");

	timeout_set(&sc->sc_diag_tmo, pl011_diag, sc);
	timeout_set(&sc->sc_dtr_tmo, pl011_raisedtr, sc);
	sc->sc_si = softintr_establish(IPL_TTY, pl011_softint, sc);

	if(sc->sc_si == NULL)
		panic("%s: can't establish soft interrupt.",
		    sc->sc_dev.dv_xname);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM));
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
	    ~UART_LCR_H_FEN);

	printf("\n");
}

int
pl011_intr(void *arg)
{
	struct pl011_softc *sc = arg;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp = sc->sc_tty;
	u_int16_t fr;
	u_int16_t *p;
	u_int16_t c;

	bus_space_write_4(iot, ioh, UART_ICR, -1);

	if (sc->sc_tty == NULL)
		return(0);

	fr = bus_space_read_4(iot, ioh, UART_FR);
	if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) {
		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
		if (sc->sc_halt > 0)
			wakeup(&tp->t_outq);
		(*linesw[tp->t_line].l_start)(tp);
	}

	if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF))
		return 0;

	p = sc->sc_ibufp;

	while(ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
		c = bus_space_read_1(iot, ioh, UART_DR);
		if (p >= sc->sc_ibufend) {
			sc->sc_floods++;
			if (sc->sc_errors++ == 0)
				timeout_add(&sc->sc_diag_tmo, 60 * hz);
		} else {
			*p++ = c;
			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
				/* XXX */
				//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
				//bus_space_write_4(iot, ioh, IMXUART_UCR3,
				//    sc->sc_ucr3);
			}
		}
		/* XXX - msr stuff ? */
	}
	sc->sc_ibufp = p;

	softintr_schedule(sc->sc_si);

	return 1;
}

int
pl011_param(struct tty *tp, struct termios *t)
{
	struct pl011_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
	//bus_space_tag_t iot = sc->sc_iot;
	//bus_space_handle_t ioh = sc->sc_ioh;
	int ospeed = t->c_ospeed;
	int error;
	tcflag_t oldcflag;

	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
		return EINVAL;

	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		return EINVAL;
	case CS6:
		return EINVAL;
	case CS7:
		//CLR(sc->sc_ucr2, IMXUART_CR2_WS);
		break;
	case CS8:
		//SET(sc->sc_ucr2, IMXUART_CR2_WS);
		break;
	}
//	bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);

	/*
	if (ISSET(t->c_cflag, PARENB)) {
		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
	}
	*/
	/* STOPB - XXX */
	if (ospeed == 0) {
		/* lower dtr */
	}

	if (ospeed != 0) {
		while (ISSET(tp->t_state, TS_BUSY)) {
			++sc->sc_halt;
			error = ttysleep(tp, &tp->t_outq,
			    TTOPRI | PCATCH, "pl011prm", 0);
			--sc->sc_halt;
			if (error) {
				pl011_start(tp);
				return (error);
			}
		}
		/* set speed */
	}

	/* setup fifo */

	/* When not using CRTSCTS, RTS follows DTR. */
	/* sc->sc_dtr = MCR_DTR; */

	/* and copy to tty */
	tp->t_ispeed = t->c_ispeed;
	tp->t_ospeed = t->c_ospeed;
	oldcflag = tp->t_cflag;
	tp->t_cflag = t->c_cflag;

        /*
	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
	 * stop the device.
	 */
	 /* XXX */

	pl011_start(tp);

	return 0;
}

void
pl011_start(struct tty *tp)
{
	struct pl011_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	int s;
	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
		goto out;
	if (tp->t_outq.c_cc <= tp->t_lowat) {
		if (ISSET(tp->t_state, TS_ASLEEP)) {
			CLR(tp->t_state, TS_ASLEEP);
			wakeup(&tp->t_outq);
		}
		if (tp->t_outq.c_cc == 0)
			goto out;
		selwakeup(&tp->t_wsel);
	}
	SET(tp->t_state, TS_BUSY);

	if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
		u_char buffer[64];	/* largest fifo */
		int i, n;

		n = q_to_b(&tp->t_outq, buffer,
		    min(sc->sc_fifolen, sizeof buffer));
		for (i = 0; i < n; i++) {
			bus_space_write_4(iot, ioh, UART_DR, buffer[i]);
		}
		bzero(buffer, n);
	} else if (tp->t_outq.c_cc != 0)
		bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));

out:
	splx(s);
}

void
pl011_pwroff(struct pl011_softc *sc)
{
}

void
pl011_diag(void *arg)
{
	struct pl011_softc *sc = arg;
	int overflows, floods;
	int s;

	s = spltty();
	sc->sc_errors = 0;
	overflows = sc->sc_overflows;
	sc->sc_overflows = 0;
	floods = sc->sc_floods;
	sc->sc_floods = 0;
	splx(s);
	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
	    sc->sc_dev.dv_xname,
	    overflows, overflows == 1 ? "" : "s",
	    floods, floods == 1 ? "" : "s");
}

void
pl011_raisedtr(void *arg)
{
	//struct pl011_softc *sc = arg;

	//SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
	//bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
}

void
pl011_softint(void *arg)
{
	struct pl011_softc *sc = arg;
	struct tty *tp;
	u_int16_t *ibufp;
	u_int16_t *ibufend;
	int c;
	int err;
	int s;

	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
		return;

	tp = sc->sc_tty;
	s = spltty();

	ibufp = sc->sc_ibuf;
	ibufend = sc->sc_ibufp;

	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
		splx(s);
		return;
	}

	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
	sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
	sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;

#if 0
	if (ISSET(tp->t_cflag, CRTSCTS) &&
	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
		/* XXX */
		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
		    sc->sc_ucr3);
	}
#endif

	splx(s);

	while (ibufp < ibufend) {
		c = *ibufp++;
		/*
		if (ISSET(c, IMXUART_RX_OVERRUN)) {
			sc->sc_overflows++;
			if (sc->sc_errors++ == 0)
				timeout_add(&sc->sc_diag_tmo, 60 * hz);
		}
		*/
		/* This is ugly, but fast. */

		err = 0;
		/*
		if (ISSET(c, IMXUART_RX_PRERR))
			err |= TTY_PE;
		if (ISSET(c, IMXUART_RX_FRMERR))
			err |= TTY_FE;
		*/
		c = (c & 0xff) | err;
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
}

int
pl011open(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct pl011_softc *sc;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	struct tty *tp;
	int s;
	int error = 0;

	if (unit >= pluart_cd.cd_ndevs)
		return ENXIO;
	sc = pluart_cd.cd_devs[unit];
	if (sc == NULL)
		return ENXIO;

	s = spltty();
	if (sc->sc_tty == NULL)
		tp = sc->sc_tty = ttymalloc(0);
	else
		tp = sc->sc_tty;

	splx(s);

	tp->t_oproc = pl011_start;
	tp->t_param = pl011_param;
	tp->t_dev = dev;

	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		SET(tp->t_state, TS_WOPEN);
		ttychars(tp);
		tp->t_iflag = TTYDEF_IFLAG;
		tp->t_oflag = TTYDEF_OFLAG;

		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
			tp->t_cflag = pl011conscflag;
		else
			tp->t_cflag = TTYDEF_CFLAG;
		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
			SET(tp->t_cflag, CLOCAL);
		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
			SET(tp->t_cflag, CRTSCTS);
		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
			SET(tp->t_cflag, MDMBUF);
		tp->t_lflag = TTYDEF_LFLAG;
		tp->t_ispeed = tp->t_ospeed = pl011defaultrate;

		s = spltty();

		sc->sc_initialize = 1;
		pl011_param(tp, &tp->t_termios);
		ttsetwater(tp);
		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
		sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
		sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;

		iot = sc->sc_iot;
		ioh = sc->sc_ioh;

#if 0
		sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
		sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
		sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
		sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);

		/* interrupt after one char on tx/rx */
		/* reference frequency divider: 1 */
		bus_space_write_4(iot, ioh, IMXUART_UFCR,
		    1 << IMXUART_FCR_TXTL_SH |
		    5 << IMXUART_FCR_RFDIV_SH |
		    1 << IMXUART_FCR_RXTL_SH);

		bus_space_write_4(iot, ioh, IMXUART_UBIR,
		    (pl011defaultrate / 100) - 1);

		/* formula: clk / (rfdiv * 1600) */
		bus_space_write_4(iot, ioh, IMXUART_UBMR,
		    (clk_get_rate(sc->sc_clk) * 1000) / 1600);

		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
		bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);

		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
		bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
#endif

		SET(tp->t_state, TS_CARR_ON); /* XXX */

	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
		return EBUSY;
	else
		s = spltty();

	if (DEVCUA(dev)) {
		if (ISSET(tp->t_state, TS_ISOPEN)) {
			splx(s);
			return EBUSY;
		}
		sc->sc_cua = 1;
	} else {
		/* tty (not cua) device; wait for carrier if necessary */
		if (ISSET(flag, O_NONBLOCK)) {
			if (sc->sc_cua) {
				/* Opening TTY non-blocking... but the CUA is busy */
				splx(s);
				return EBUSY;
			}
		} else {
			while (sc->sc_cua ||
			    (!ISSET(tp->t_cflag, CLOCAL) &&
				!ISSET(tp->t_state, TS_CARR_ON))) {
				SET(tp->t_state, TS_WOPEN);
				error = ttysleep(tp, &tp->t_rawq,
				    TTIPRI | PCATCH, ttopen, 0);
				/*
				 * If TS_WOPEN has been reset, that means the
				 * cua device has been closed.  We don't want
				 * to fail in that case,
				 * so just go around again.
				 */
				if (error && ISSET(tp->t_state, TS_WOPEN)) {
					CLR(tp->t_state, TS_WOPEN);
					if (!sc->sc_cua && !ISSET(tp->t_state,
					    TS_ISOPEN))
						pl011_pwroff(sc);
					splx(s);
					return error;
				}
			}
		}
	}
	splx(s);
	return (*linesw[tp->t_line].l_open)(dev,tp,p);
}

int
pl011close(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct pl011_softc *sc = pluart_cd.cd_devs[unit];
	//bus_space_tag_t iot = sc->sc_iot;
	//bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp = sc->sc_tty;
	int s;

	/* XXX This is for cons.c. */
	if (!ISSET(tp->t_state, TS_ISOPEN))
		return 0;

	(*linesw[tp->t_line].l_close)(tp, flag, p);
	s = spltty();
	if (ISSET(tp->t_state, TS_WOPEN)) {
		/* tty device is waiting for carrier; drop dtr then re-raise */
		//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
		//bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
		timeout_add(&sc->sc_dtr_tmo, hz * 2);
	} else {
		/* no one else waiting; turn off the uart */
		pl011_pwroff(sc);
	}
	CLR(tp->t_state, TS_BUSY | TS_FLUSH);

	sc->sc_cua = 0;
	splx(s);
	ttyclose(tp);

	return 0;
}

int
pl011read(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = pl011tty(dev);
	if (tty == NULL)
		return ENODEV;

	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
}

int
pl011write(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = pl011tty(dev);
	if (tty == NULL)
		return ENODEV;

	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
}

int
pl011ioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct pl011_softc *sc;
	struct tty *tp;
	int error;

	sc = pl011_sc(dev);
	if (sc == NULL)
		return (ENODEV);

	tp = sc->sc_tty;
	if (tp == NULL)
		return (ENXIO);

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	switch(cmd) {
	case TIOCSBRK:
		break;
	case TIOCCBRK:
		break;
	case TIOCSDTR:
		break;
	case TIOCCDTR:
		break;
	case TIOCMSET:
		break;
	case TIOCMBIS:
		break;
	case TIOCMBIC:
		break;
	case TIOCMGET:
		break;
	case TIOCGFLAGS:
		break;
	case TIOCSFLAGS:
		error = suser(p, 0);
		if (error != 0)
			return(EPERM);
		break;
	default:
		return (ENOTTY);
	}

	return 0;
}

int
pl011stop(struct tty *tp, int flag)
{
	return 0;
}

struct tty *
pl011tty(dev_t dev)
{
	int unit;
	struct pl011_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= pluart_cd.cd_ndevs)
		return NULL;
	sc = (struct pl011_softc *)pluart_cd.cd_devs[unit];
	if (sc == NULL)
		return NULL;
	return sc->sc_tty;
}

struct pl011_softc *
pl011_sc(dev_t dev)
{
	int unit;
	struct pl011_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= pluart_cd.cd_ndevs)
		return NULL;
	sc = (struct pl011_softc *)pluart_cd.cd_devs[unit];
	return sc;
}

/* serial console */
void
pl011cnprobe(struct consdev *cp)
{
	cp->cn_dev = makedev(12 /* XXX */, 0);
	cp->cn_pri = CN_MIDPRI;
}

void
pl011cninit(struct consdev *cp)
{
}

int
pl011cnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
{
	static struct consdev pl011cons = {
		NULL, NULL, pl011cngetc, pl011cnputc, pl011cnpollc, NULL,
		NODEV, CN_MIDPRI
	};

	if (bus_space_map(iot, iobase, UART_SPACE, 0, &pl011consioh))
			return ENOMEM;

	/* Disable FIFO. */
	bus_space_write_4(iot, pl011consioh, UART_LCR_H,
	    bus_space_read_4(iot, pl011consioh, UART_LCR_H) & ~UART_LCR_H_FEN);

	cn_tab = &pl011cons;
	cn_tab->cn_dev = makedev(12 /* XXX */, 0);
	cdevsw[12] = pl011dev; 	/* KLUDGE */

	pl011consiot = iot;
	pl011consaddr = iobase;
	pl011conscflag = cflag;

	return 0;
}

int
pl011cngetc(dev_t dev)
{
	int c;
	int s;
	s = splhigh();
	while((bus_space_read_4(pl011consiot, pl011consioh, UART_FR) &
	    UART_FR_RXFF) == 0)
		;
	c = bus_space_read_4(pl011consiot, pl011consioh, UART_DR);
	splx(s);
	return c;
}

void
pl011cnputc(dev_t dev, int c)
{
	int s;
	s = splhigh();
	while((bus_space_read_4(pl011consiot, pl011consioh, UART_FR) &
	    UART_FR_TXFE) == 0)
		;
	bus_space_write_4(pl011consiot, pl011consioh, UART_DR, (uint8_t)c);
	splx(s);
}

void
pl011cnpollc(dev_t dev, int on)
{
}


code:
/*	$OpenBSD: pl011reg.h,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/

/*
 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef	PL011REG_H
#define	PL011REG_H

#define		UART_DR				0x00 /* Data register */
#define		UART_DR_DATA(x)			((x) & 0xf)
#define		UART_DR_FE			(1 << 8) /* Framing error */
#define		UART_DR_PE			(1 << 9) /* Parity error */
#define		UART_DR_BE			(1 << 10) /* Break error */
#define		UART_DR_OE			(1 << 11) /* Overrun error */
#define		UART_RSR			0x04 /* Receive status register */
#define		UART_RSR_FE			(1 << 0) /* Framing error */
#define		UART_RSR_PE			(1 << 1) /* Parity error */
#define		UART_RSR_BE			(1 << 2) /* Break error */
#define		UART_RSR_OE			(1 << 3) /* Overrun error */
#define		UART_ECR			0x04 /* Error clear register */
#define		UART_ECR_FE			(1 << 0) /* Framing error */
#define		UART_ECR_PE			(1 << 1) /* Parity error */
#define		UART_ECR_BE			(1 << 2) /* Break error */
#define		UART_ECR_OE			(1 << 3) /* Overrun error */
#define		UART_FR				0x18 /* Flag register */
#define		UART_FR_CTS			(1 << 0) /* Clear to send */
#define		UART_FR_DSR			(1 << 1) /* Data set ready */
#define		UART_FR_DCD			(1 << 2) /* Data carrier detect */
#define		UART_FR_BUSY			(1 << 3) /* UART busy */
#define		UART_FR_RXFE			(1 << 4) /* Receive FIFO empty */
#define		UART_FR_TXFF			(1 << 5) /* Transmit FIFO full */
#define		UART_FR_RXFF			(1 << 6) /* Receive FIFO full */
#define		UART_FR_TXFE			(1 << 7) /* Transmit FIFO empty */
#define		UART_FR_RI			(1 << 8) /* Ring indicator */
#define		UART_ILPR			0x20 /* IrDA low-power counter register */
#define		UART_ILPR_ILPDVSR		((x) & 0xf) /* IrDA low-power divisor */
#define		UART_IBRD			0x24 /* Integer baud rate register */
#define		UART_IBRD_DIVINT		((x) & 0xff) /* Integer baud rate divisor */
#define		UART_FBRD			0x28 /* Fractional baud rate register */
#define		UART_FBRD_DIVFRAC		((x) & 0x3f) /* Fractional baud rate divisor */
#define		UART_LCR_H			0x2c /* Line control register */
#define		UART_LCR_H_BRK			(1 << 0) /* Send break */
#define		UART_LCR_H_PEN			(1 << 1) /* Parity enable */
#define		UART_LCR_H_EPS			(1 << 2) /* Even parity select */
#define		UART_LCR_H_STP2			(1 << 3) /* Two stop bits select */
#define		UART_LCR_H_FEN			(1 << 4) /* Enable FIFOs */
#define		UART_LCR_H_WLEN5		(0x0 << 5) /* Word length: 5 bits */
#define		UART_LCR_H_WLEN6		(0x1 << 5) /* Word length: 6 bits */
#define		UART_LCR_H_WLEN7		(0x2 << 5) /* Word length: 7 bits */
#define		UART_LCR_H_WLEN8		(0x3 << 5) /* Word length: 8 bits */
#define		UART_LCR_H_SPS			(1 << 7) /* Stick parity select */
#define		UART_CR				0x30 /* Control register */
#define		UART_CR_UARTEN			(1 << 0) /* UART enable */
#define		UART_CR_SIREN			(1 << 1) /* SIR enable */
#define		UART_CR_SIRLP			(1 << 2) /* IrDA SIR low power mode */
#define		UART_CR_LBE			(1 << 7) /* Loop back enable */
#define		UART_CR_TXE			(1 << 8) /* Transmit enable */
#define		UART_CR_RXE			(1 << 9) /* Receive enable */
#define		UART_CR_DTR			(1 << 10) /* Data transmit enable */
#define		UART_CR_RTS			(1 << 11) /* Request to send */
#define		UART_CR_OUT1			(1 << 12)
#define		UART_CR_OUT2			(1 << 13)
#define		UART_CR_CTSE			(1 << 14) /* CTS hardware flow control enable */
#define		UART_CR_RTSE			(1 << 15) /* RTS hardware flow control enable */
#define		UART_IFLS			0x34 /* Interrupt FIFO level select register */
#define		UART_IMSC			0x38 /* Interrupt mask set/clear register */
#define		UART_IMSC_RIMIM			(1 << 0)
#define		UART_IMSC_CTSMIM		(1 << 1)
#define		UART_IMSC_DCDMIM		(1 << 2)
#define		UART_IMSC_DSRMIM		(1 << 3)
#define		UART_IMSC_RXIM			(1 << 4)
#define		UART_IMSC_TXIM			(1 << 5)
#define		UART_IMSC_RTIM			(1 << 6)
#define		UART_IMSC_FEIM			(1 << 7)
#define		UART_IMSC_PEIM			(1 << 8)
#define		UART_IMSC_BEIM			(1 << 9)
#define		UART_IMSC_OEIM			(1 << 10)
#define		UART_RIS			0x3c /* Raw interrupt status register */
#define		UART_MIS			0x40 /* Masked interrupt status register */
#define		UART_ICR			0x44 /* Interrupt clear register */
#define		UART_DMACR			0x48 /* DMA control register */
#define		UART_SPACE			0x100

#endif /* !PL011REG_H */


code:
/*	$OpenBSD: pl011var.h,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/

/*
 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef	PL011VAR_H
#define	PL011VAR_H

int pl011cnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
    tcflag_t cflag);

#endif /* !PL011VAR_H */


code:
/*	$OpenBSD: pl031.c,v 1.1 2015/06/14 05:01:31 jsg Exp $	*/

/*
 * Copyright (c) 2015 Jonathan Gray <jsg@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/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>

#include <machine/bus.h>
#include <armv7/armv7/armv7var.h>
#include <dev/clock_subr.h>

#define RTCDR	0x00
#define RTCMR	0x04
#define RTCLR	0x08
#define RTCCR	0x0c
#define RTCIMSC	0x10
#define RTCRIS	0x14
#define RTCMIS	0x18
#define RTCICR	0x1c

#define RTCCR_START	(1 << 0)

extern todr_chip_handle_t todr_handle;

struct plrtc_softc {
	struct device		 sc_dev;
	bus_space_tag_t		 sc_iot;
	bus_space_handle_t	 sc_ioh;
};

void	plrtc_attach(struct device *, struct device *, void *);
int	plrtc_gettime(struct todr_chip_handle *, struct timeval *);
int	plrtc_settime(struct todr_chip_handle *, struct timeval *);

struct cfattach plrtc_ca = {
	sizeof(struct plrtc_softc), NULL , plrtc_attach
};

struct cfdriver plrtc_cd = {
	NULL, "plrtc", DV_DULL
};

int
plrtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
{
	struct plrtc_softc	*sc = handle->cookie;
	uint32_t		 tod;

	tod = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RTCDR);

	tv->tv_sec = tod;
	tv->tv_usec = 0;

	return (0);
}

int
plrtc_settime(todr_chip_handle_t handle, struct timeval *tv)
{
	struct plrtc_softc	*sc = handle->cookie;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RTCLR, tv->tv_sec);

	return (0);
}

void
plrtc_attach(struct device *parent, struct device *self, void *aux)
{
	struct armv7_attach_args	*aa = aux;
	struct plrtc_softc		*sc = (struct plrtc_softc *) self;
	todr_chip_handle_t		 handle;

	sc->sc_iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) {
		printf(": failed to map mem space\n");
		return;
	}

	handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF,
	    M_NOWAIT | M_ZERO);
	if (handle == NULL)
		panic("couldn't allocate todr_handle");

	handle->cookie = sc;
	handle->todr_gettime = plrtc_gettime;
	handle->todr_settime = plrtc_settime;
	todr_handle = handle;

	/* enable the rtc */
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, RTCCR, RTCCR_START);

	printf("\n");
}


code:
/*	$OpenBSD: sysreg.c,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <armv7/armv7/armv7var.h>

#define SYS_ID			0x00
#define SYS_PROCID0		0x84
#define SYS_PROCID1		0x88
#define SYS_CFGDATA		0xa0
#define SYS_CFGCTRL		0xa4
#define SYS_CFGSTAT		0xa8

#define SYS_CFG_WRITE		(1 << 30)
#define SYS_CFG_START		(1U << 31)

#define SYS_CFG_RESET		5
#define SYS_CFG_SHUTDOWN	8
#define SYS_CFG_REBOOT		9

#define SYS_CFGSTAT_COMPLETE	(1 << 0)
#define SYS_CFGSTAT_ERROR	(1 << 1)

struct sysreg_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

struct sysreg_softc *sysreg_sc;

void sysreg_attach(struct device *, struct device *, void *);
void sysreg_reset(void);

struct cfattach sysreg_ca = {
	sizeof (struct sysreg_softc), NULL, sysreg_attach
};

struct cfdriver sysreg_cd = {
	NULL, "sysreg", DV_DULL
};

void
sysreg_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct sysreg_softc *sc = (struct sysreg_softc *)self;
	uint32_t id;

	sc->sc_iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
		panic(": bus_space_map failed!");
	sysreg_sc = sc;

	id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SYS_ID);
	printf(": ID 0x%x", id);

	id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SYS_PROCID0);
	printf(" PROCID0 0x%x\n", id);
}

void
sysconf_function(struct sysreg_softc *sc, int function)
{
	int dcc, site, position, device;

	dcc = 0;
	site = 0;
	position = 0;
	device = 0;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SYS_CFGSTAT, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SYS_CFGCTRL,
	    SYS_CFG_START | SYS_CFG_WRITE |
	    (dcc << 26) | (function << 20) | (site << 16) |
	    (position << 12) | device);

	while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SYS_CFGSTAT) &
	    SYS_CFGSTAT_COMPLETE) == 0);

	if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SYS_CFGSTAT) &
	    SYS_CFGSTAT_ERROR)
		printf("SYS_CFGSTAT error\n");
}

void
sysconf_reboot(void)
{
	struct sysreg_softc *sc = sysreg_sc;

	if (sc == NULL)
		return;

	sysconf_function(sc, SYS_CFG_REBOOT);
}

void
sysconf_shutdown(void)
{
	struct sysreg_softc *sc = sysreg_sc;

	if (sc == NULL)
		return;

	sysconf_function(sc, SYS_CFG_SHUTDOWN);
}


code:
/*	$OpenBSD: vexpress.c,v 1.2 2015/06/14 05:01:31 jsg Exp $	*/

/*
 * Copyright (c) 2015 Jonathan Gray <jsg@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 <machine/bus.h>

#include <arm/cpufunc.h>
#include <armv7/armv7/armv7var.h>

int	vexpress_match(struct device *, void *, void *);
void	vexpress_a9_init();
void	vexpress_a15_init();

struct cfattach vexpress_ca = {
	sizeof(struct armv7_softc), vexpress_match, armv7_attach, NULL,
	config_activate_children
};

struct cfdriver vexpress_cd = {
	NULL, "vexpress", DV_DULL
};

struct board_dev vexpress_devs[] = {
	{ "sysreg",	0 },
	{ "pluart",	0 },
	{ "plrtc",	0 },
	{ "virtio",	0 },
	{ "virtio",	1 },
	{ "virtio",	2 },
	{ "virtio",	3 },
	{ NULL,		0 }
};

struct armv7_board vexpress_boards[] = {
	{
		BOARD_ID_VEXPRESS,
		"ARM Versatile Express",
		vexpress_devs,
		NULL,
	},
	{ 0, NULL, NULL, NULL },
};

struct board_dev *
vexpress_board_devs(void)
{
	int i;

	for (i = 0; vexpress_boards[i].name != NULL; i++) {
		if (vexpress_boards[i].board_id == board_id)
			return (vexpress_boards[i].devs);
	}
	return (NULL);
}

extern vaddr_t physical_start;

int
vexpress_legacy_map(void)
{
	return ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9);
}

void
vexpress_board_init(void)
{
	if (board_id != BOARD_ID_VEXPRESS)
		return;

	if (vexpress_legacy_map())
		vexpress_a9_init();
	else
		vexpress_a15_init();
}

const char *
vexpress_board_name(void)
{
	int i;

	for (i = 0; vexpress_boards[i].name != NULL; i++) {
		if (vexpress_boards[i].board_id == board_id) {
			return (vexpress_boards[i].name);
			break;
		}
	}
	return (NULL);
}

int
vexpress_match(struct device *parent, void *cfdata, void *aux)
{
	return (vexpress_board_devs() != NULL);
}


code:
/*	$OpenBSD: vexpress_a15.c,v 1.2 2015/06/14 05:01:31 jsg Exp $	*/

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <arch/arm/armv7/armv7var.h>

#include <armv7/armv7/armv7var.h>

#define SYSREG_ADDR	0x1c010000
#define SYSREG_SIZE	0x1000

#define UARTx_SIZE	0x1000
#define UART0_ADDR	0x1c090000
#define UART1_ADDR	0x1c0a0000
#define UART2_ADDR	0x1c0b0000
#define UART3_ADDR	0x1c0c0000

#define UART0_IRQ	5
#define UART1_IRQ	6
#define UART2_IRQ	7
#define UART3_IRQ	8

#define VIRTIO0_ADDR	0x1c130000
#define VIRTIO1_ADDR	0x1c130200
#define VIRTIO2_ADDR	0x1c130400
#define VIRTIO3_ADDR	0x1c130600
#define VIRTIO_SIZE	0x200

#define VIRTIO0_IRQ	40
#define VIRTIO1_IRQ	41
#define VIRTIO2_IRQ	42
#define VIRTIO3_IRQ	43

#define RTC_ADDR	0x1c170000
#define RTC_SIZE	0x1000
#define RTC_IRQ		4

struct armv7_dev vexpress_a15_devs[] = {
	{ .name = "sysreg",
	  .unit = 0,
	  .mem = { { SYSREG_ADDR, SYSREG_SIZE } },
	},
	{ .name = "pluart",
	  .unit = 0,
	  .mem = { { UART0_ADDR, UARTx_SIZE } },
	  .irq = { UART0_IRQ }
	},
	{ .name = "pluart",
	  .unit = 1,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART1_IRQ }
	},
	{ .name = "pluart",
	  .unit = 2,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART2_IRQ }
	},
	{ .name = "pluart",
	  .unit = 3,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART3_IRQ }
	},
	{ .name = "plrtc",
	  .unit = 0,
	  .mem = { { RTC_ADDR, RTC_SIZE } },
	  .irq = { RTC_IRQ }
	},
	{ .name = "virtio",
	  .unit = 0,
	  .mem = { { VIRTIO0_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO0_IRQ }
	},
	{ .name = "virtio",
	  .unit = 1,
	  .mem = { { VIRTIO1_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO1_IRQ }
	},
	{ .name = "virtio",
	  .unit = 2,
	  .mem = { { VIRTIO2_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO2_IRQ }
	},
	{ .name = "virtio",
	  .unit = 3,
	  .mem = { { VIRTIO3_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO3_IRQ }
	},
};

void
vexpress_a15_init(void)
{
	armv7_set_devs(vexpress_a15_devs);
}


code:
/*	$OpenBSD: vexpress_a9.c,v 1.2 2015/06/14 05:01:31 jsg Exp $	*/

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <arch/arm/armv7/armv7var.h>

#include <armv7/armv7/armv7var.h>

#define SYSREG_ADDR	0x10000000
#define SYSREG_SIZE	0x1000

#define UARTx_SIZE	0x1000
#define UART0_ADDR	0x10009000
#define UART1_ADDR	0x1000a000
#define UART2_ADDR	0x1000b000
#define UART3_ADDR	0x1000c000

#define UART0_IRQ	5
#define UART1_IRQ	6
#define UART2_IRQ	7
#define UART3_IRQ	8

#define VIRTIO0_ADDR	0x10013000
#define VIRTIO1_ADDR	0x10013200
#define VIRTIO2_ADDR	0x10013400
#define VIRTIO3_ADDR	0x10013600
#define VIRTIO_SIZE	0x200

#define VIRTIO0_IRQ	40
#define VIRTIO1_IRQ	41
#define VIRTIO2_IRQ	42
#define VIRTIO3_IRQ	43

#define RTC_ADDR	0x10017000
#define RTC_SIZE	0x1000
#define RTC_IRQ		4

struct armv7_dev vexpress_a9_devs[] = {
	{ .name = "sysreg",
	  .unit = 0,
	  .mem = { { SYSREG_ADDR, SYSREG_SIZE } },
	},
	{ .name = "pluart",
	  .unit = 0,
	  .mem = { { UART0_ADDR, UARTx_SIZE } },
	  .irq = { UART0_IRQ }
	},
	{ .name = "pluart",
	  .unit = 1,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART1_IRQ }
	},
	{ .name = "pluart",
	  .unit = 2,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART2_IRQ }
	},
	{ .name = "pluart",
	  .unit = 3,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART3_IRQ }
	},
	{ .name = "plrtc",
	  .unit = 0,
	  .mem = { { RTC_ADDR, RTC_SIZE } },
	  .irq = { RTC_IRQ }
	},
	{ .name = "virtio",
	  .unit = 0,
	  .mem = { { VIRTIO0_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO0_IRQ }
	},
	{ .name = "virtio",
	  .unit = 1,
	  .mem = { { VIRTIO1_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO1_IRQ }
	},
	{ .name = "virtio",
	  .unit = 2,
	  .mem = { { VIRTIO2_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO2_IRQ }
	},
	{ .name = "virtio",
	  .unit = 3,
	  .mem = { { VIRTIO3_ADDR, VIRTIO_SIZE } },
	  .irq = { VIRTIO3_IRQ }
	},
};

void
vexpress_a9_init(void)
{
	armv7_set_devs(vexpress_a9_devs);
}


code:
/*	$OpenBSD: vexpress_machdep.c,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/
/*
 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
 *
 * 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/types.h>
#include <sys/systm.h>
#include <sys/termios.h>

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

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <arm/cortex/smc.h>
#include <arm/armv7/armv7var.h>
#include <armv7/armv7/armv7var.h>
#include <armv7/vexpress/pl011var.h>
#include <armv7/armv7/armv7_machdep.h>

extern void sysconf_reboot(void);
extern void sysconf_shutdown(void);
extern char *vexpress_board_name(void);
extern struct board_dev *vexpress_board_devs(void);
extern void vexpress_board_init(void);
extern int vexpress_legacy_map(void);
extern int comcnspeed;
extern int comcnmode;

void
vexpress_platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
    uint32_t op, uint32_t val)
{
	bus_space_write_4(iot, ioh, off, val);
}

void
vexpress_platform_init_cons(void)
{
	paddr_t paddr;

	switch (board_id) {
	default:
	case BOARD_ID_VEXPRESS:
		if (vexpress_legacy_map())
			paddr = 0x10009000;
		else
			paddr = 0x1c090000;
		break;
	}
	pl011cnattach(&armv7_bs_tag, paddr, comcnspeed, comcnmode);
}

void
vexpress_platform_watchdog_reset(void)
{
	sysconf_reboot();
}

void
vexpress_platform_powerdown(void)
{
	sysconf_shutdown();
}

const char *
vexpress_platform_board_name(void)
{
	return (vexpress_board_name());
}

void
vexpress_platform_disable_l2_if_needed(void)
{

}

void
vexpress_platform_board_init(void)
{
	vexpress_board_init();
}

struct armv7_platform vexpress_platform = {
	.boot_name = "OpenBSD/vexpress",
	.board_name = vexpress_platform_board_name,
	.board_init = vexpress_platform_board_init,
	.smc_write = vexpress_platform_smc_write,
	.init_cons = vexpress_platform_init_cons,
	.watchdog_reset = vexpress_platform_watchdog_reset,
	.powerdown = vexpress_platform_powerdown,
	.disable_l2_if_needed = vexpress_platform_disable_l2_if_needed,
};

struct armv7_platform *
vexpress_platform_match(void)
{
	struct board_dev *devs;

	devs = vexpress_board_devs();
	if (devs == NULL)
		return (NULL);

	vexpress_platform.devs = devs;
	return (&vexpress_platform);
}


code:
/*	$OpenBSD: virtio_mmio.c,v 1.1 2015/06/08 06:33:16 jsg Exp $	*/
/*	$NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $	*/

/*
 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
 * Copyright (c) 2012 Stefan Fritsch.
 * Copyright (c) 2010 Minoura Makoto.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "fdt.h"

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

#include <dev/pci/virtioreg.h>
#include <dev/pci/virtiovar.h>

#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/armv7/armv7var.h>

#define VIRTIO_MMIO_MAGIC		('v' | 'i' << 8 | 'r' << 16 | 't' << 24)

#define VIRTIO_MMIO_MAGIC_VALUE		0x000
#define VIRTIO_MMIO_VERSION		0x004
#define VIRTIO_MMIO_DEVICE_ID		0x008
#define VIRTIO_MMIO_VENDOR_ID		0x00c
#define VIRTIO_MMIO_HOST_FEATURES	0x010
#define VIRTIO_MMIO_HOST_FEATURES_SEL	0x014
#define VIRTIO_MMIO_GUEST_FEATURES	0x020
#define VIRTIO_MMIO_GUEST_FEATURES_SEL	0x024
#define VIRTIO_MMIO_GUEST_PAGE_SIZE	0x028
#define VIRTIO_MMIO_QUEUE_SEL		0x030
#define VIRTIO_MMIO_QUEUE_NUM_MAX	0x034
#define VIRTIO_MMIO_QUEUE_NUM		0x038
#define VIRTIO_MMIO_QUEUE_ALIGN		0x03c
#define VIRTIO_MMIO_QUEUE_PFN		0x040
#define VIRTIO_MMIO_QUEUE_NOTIFY	0x050
#define VIRTIO_MMIO_INTERRUPT_STATUS	0x060
#define VIRTIO_MMIO_INTERRUPT_ACK	0x064
#define VIRTIO_MMIO_STATUS		0x070
#define VIRTIO_MMIO_CONFIG		0x100

#define VIRTIO_MMIO_INT_VRING		(1 << 0)
#define VIRTIO_MMIO_INT_CONFIG		(1 << 1)

#define DEVNAME(sc) (sc)->sc_dev.dv_xname

/*
 * XXX: Before being used on big endian arches, the access to config registers
 * XXX: needs to be reviewed/fixed. The non-device specific registers are
 * XXX: PCI-endian while the device specific registers are native endian.
 */

#define virtio_set_status(sc, s) virtio_mmio_set_status(sc, s)
#define virtio_device_reset(sc) virtio_set_status((sc), 0)

int		virtio_mmio_match(struct device *, void *, void *);
void		virtio_mmio_attach(struct device *, struct device *, void *);
int		virtio_mmio_detach(struct device *, int);

void		virtio_mmio_kick(struct virtio_softc *, uint16_t);
uint8_t		virtio_mmio_read_device_config_1(struct virtio_softc *, int);
uint16_t	virtio_mmio_read_device_config_2(struct virtio_softc *, int);
uint32_t	virtio_mmio_read_device_config_4(struct virtio_softc *, int);
uint64_t	virtio_mmio_read_device_config_8(struct virtio_softc *, int);
void		virtio_mmio_write_device_config_1(struct virtio_softc *, int, uint8_t);
void		virtio_mmio_write_device_config_2(struct virtio_softc *, int, uint16_t);
void		virtio_mmio_write_device_config_4(struct virtio_softc *, int, uint32_t);
void		virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t);
uint16_t	virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t);
void		virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint32_t);
void		virtio_mmio_set_status(struct virtio_softc *, int);
uint32_t	virtio_mmio_negotiate_features(struct virtio_softc *, uint32_t,
					      const struct virtio_feature_name *);
int		virtio_mmio_intr(void *);

struct virtio_mmio_softc {
	struct virtio_softc	sc_sc;

	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_size_t		sc_iosize;
	bus_dma_tag_t		sc_dmat;

	void			*sc_ih;

	int			sc_config_offset;
};

struct cfattach virtio_mmio_ca = {
	sizeof(struct virtio_mmio_softc),
	virtio_mmio_match,
	virtio_mmio_attach,
	virtio_mmio_detach,
	NULL
};

struct cfattach virtio_mmio_fdt_ca = {
	sizeof(struct virtio_mmio_softc),
	NULL,
	virtio_mmio_attach,
	virtio_mmio_detach,
	NULL
};

struct virtio_ops virtio_mmio_ops = {
	virtio_mmio_kick,
	virtio_mmio_read_device_config_1,
	virtio_mmio_read_device_config_2,
	virtio_mmio_read_device_config_4,
	virtio_mmio_read_device_config_8,
	virtio_mmio_write_device_config_1,
	virtio_mmio_write_device_config_2,
	virtio_mmio_write_device_config_4,
	virtio_mmio_write_device_config_8,
	virtio_mmio_read_queue_size,
	virtio_mmio_setup_queue,
	virtio_mmio_set_status,
	virtio_mmio_negotiate_features,
	virtio_mmio_intr,
};

uint16_t
virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx);
	return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    VIRTIO_MMIO_QUEUE_NUM_MAX);
}

void
virtio_mmio_setup_queue(struct virtio_softc *vsc, uint16_t idx, uint32_t addr)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM_MAX));
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_ALIGN,
	    PAGE_SIZE);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_PFN, addr);
}

void
virtio_mmio_set_status(struct virtio_softc *vsc, int status)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	int old = 0;

	if (status != 0)
		old = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
				       VIRTIO_MMIO_STATUS);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_STATUS,
			  status|old);
}

int
virtio_mmio_match(struct device *parent, void *cfdata, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("virtio,mmio", aa->aa_node))
			return 1;
#endif

	return 0;
}

void
virtio_mmio_attach(struct device *parent, struct device *self, void *aux)
{
	struct armv7_attach_args *aa = aux;
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)self;
	struct virtio_softc *vsc = &sc->sc_sc;
	struct armv7mem mem;
	uint32_t id, magic, version;
	int irq;

#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		uint32_t ints[3];

		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT", __func__);

		if (fdt_node_property_ints(aa->aa_node, "interrupts",
		    ints, 3) != 3)
			panic("%s: could not extract interrupt data from FDT",
			    __func__);

		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;

		irq = ints[1];
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;

		irq = aa->aa_dev->irq[0];
	}

	sc->sc_iosize = mem.size;
	sc->sc_iot = aa->aa_iot;
	sc->sc_dmat = aa->aa_dmat;
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    VIRTIO_MMIO_MAGIC_VALUE);
	if (magic != VIRTIO_MMIO_MAGIC) {
		printf(": wrong magic value 0x%08x; giving up\n", magic);
		return;
	}

	version = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_VERSION);
	if (version != 1) {
		printf(": unknown version 0x%02x; giving up\n", version);
		return;
	}

	id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_DEVICE_ID);
	printf(": Virtio %s Device", virtio_device_string(id));

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_GUEST_PAGE_SIZE,
	    PAGE_SIZE);

	printf("\n");

	/* No device connected. */
	if (id == 0)
		return;

	vsc->sc_ops = &virtio_mmio_ops;
	vsc->sc_dmat = sc->sc_dmat;
	sc->sc_config_offset = VIRTIO_MMIO_CONFIG;

	virtio_device_reset(vsc);
	virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
	virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);

	/* XXX: use softc as aux... */
	vsc->sc_childdevid = id;
	vsc->sc_child = NULL;
	config_found(self, sc, NULL);
	if (vsc->sc_child == NULL) {
		printf("%s: no matching child driver; not configured\n",
		    vsc->sc_dev.dv_xname);
		goto fail_1;
	}
	if (vsc->sc_child == VIRTIO_CHILD_ERROR) {
		printf("%s: virtio configuration failed\n",
		    vsc->sc_dev.dv_xname);
		goto fail_1;
	}

	sc->sc_ih = arm_intr_establish(irq, vsc->sc_ipl,
	    virtio_mmio_intr, sc, vsc->sc_dev.dv_xname);
	if (sc->sc_ih == NULL) {
		printf("%s: couldn't establish interrupt\n",
		    vsc->sc_dev.dv_xname);
		goto fail_2;
	}

	virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
	return;

fail_2:
	config_detach(vsc->sc_child, 0);
fail_1:
	/* no mmio_mapreg_unmap() or mmio_intr_unmap() */
	virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
}

int
virtio_mmio_detach(struct device *self, int flags)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)self;
	struct virtio_softc *vsc = &sc->sc_sc;
	int r;

	if (vsc->sc_child != 0 && vsc->sc_child != VIRTIO_CHILD_ERROR) {
		r = config_detach(vsc->sc_child, flags);
		if (r)
			return r;
	}
	KASSERT(vsc->sc_child == 0 || vsc->sc_child == VIRTIO_CHILD_ERROR);
	KASSERT(vsc->sc_vqs == 0);
	arm_intr_disestablish(sc->sc_ih);
	sc->sc_ih = 0;
	if (sc->sc_iosize)
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
	sc->sc_iosize = 0;

	return 0;
}

/*
 * Feature negotiation.
 * Prints available / negotiated features if guest_feature_names != NULL and
 * VIRTIO_DEBUG is 1
 */
uint32_t
virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint32_t guest_features,
			  const struct virtio_feature_name *guest_feature_names)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	uint32_t host, neg;

	/*
	 * indirect descriptors can be switched off by setting bit 1 in the
	 * driver flags, see config(8)
	 */
	if (!(vsc->sc_dev.dv_cfdata->cf_flags & 1) &&
	    !(vsc->sc_child->dv_cfdata->cf_flags & 1)) {
		guest_features |= VIRTIO_F_RING_INDIRECT_DESC;
	} else {
		printf("RingIndirectDesc disabled by UKC\n");
	}
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    VIRTIO_MMIO_HOST_FEATURES_SEL, 0);
	host = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
				VIRTIO_MMIO_HOST_FEATURES);
	neg = host & guest_features;
#if VIRTIO_DEBUG
	if (guest_feature_names)
		virtio_log_features(host, neg, guest_feature_names);
#endif
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    VIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			  VIRTIO_MMIO_GUEST_FEATURES, neg);
	vsc->sc_features = neg;
	if (neg & VIRTIO_F_RING_INDIRECT_DESC)
		vsc->sc_indirect = 1;
	else
		vsc->sc_indirect = 0;

	return neg;
}

/*
 * Device configuration registers.
 */
uint8_t
virtio_mmio_read_device_config_1(struct virtio_softc *vsc, int index)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
				sc->sc_config_offset + index);
}

uint16_t
virtio_mmio_read_device_config_2(struct virtio_softc *vsc, int index)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
				sc->sc_config_offset + index);
}

uint32_t
virtio_mmio_read_device_config_4(struct virtio_softc *vsc, int index)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
				sc->sc_config_offset + index);
}

uint64_t
virtio_mmio_read_device_config_8(struct virtio_softc *vsc, int index)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	uint64_t r;

	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
			     sc->sc_config_offset + index + sizeof(uint32_t));
	r <<= 32;
	r += bus_space_read_4(sc->sc_iot, sc->sc_ioh,
			      sc->sc_config_offset + index);
	return r;
}

void
virtio_mmio_write_device_config_1(struct virtio_softc *vsc,
			     int index, uint8_t value)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
			  sc->sc_config_offset + index, value);
}

void
virtio_mmio_write_device_config_2(struct virtio_softc *vsc,
			     int index, uint16_t value)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
			  sc->sc_config_offset + index, value);
}

void
virtio_mmio_write_device_config_4(struct virtio_softc *vsc,
			     int index, uint32_t value)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			  sc->sc_config_offset + index, value);
}

void
virtio_mmio_write_device_config_8(struct virtio_softc *vsc,
			     int index, uint64_t value)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			  sc->sc_config_offset + index,
			  value & 0xffffffff);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			  sc->sc_config_offset + index + sizeof(uint32_t),
			  value >> 32);
}

/*
 * Interrupt handler.
 */
int
virtio_mmio_intr(void *arg)
{
	struct virtio_mmio_softc *sc = arg;
	struct virtio_softc *vsc = &sc->sc_sc;
	int isr, r = 0;

	/* check and ack the interrupt */
	isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
			       VIRTIO_MMIO_INTERRUPT_STATUS);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			  VIRTIO_MMIO_INTERRUPT_ACK, isr);
	if ((isr & VIRTIO_MMIO_INT_CONFIG) &&
	    (vsc->sc_config_change != NULL))
		r = (vsc->sc_config_change)(vsc);
	if ((isr & VIRTIO_MMIO_INT_VRING) &&
	    (vsc->sc_intrhand != NULL))
		r |= (vsc->sc_intrhand)(vsc);

	return r;
}

void
virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx)
{
	struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NOTIFY,
	    idx);
}


code:
/Makefile/1.7/Sun Dec  8 14:46:39 2013//TOPENBSD_5_8_BASE
D/aviion////
D/compile////
D/conf////
D/dev////
D/include////
D/stand////

path: sys/arch/aviion/CVS/Entries


code: src/sys/arch/aviion

path: sys/arch/aviion/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.7 2013/12/08 14:46:39 espie Exp $

S=	${.CURDIR}/../..
KFILE=	GENERIC
.if exists(conf/GENERIC.MP)
KFILE=	GENERIC.MP
.endif
TDIRS=	${_arch} include
TAGS=	${.CURDIR}/tags

NOPROG=
NOMAN=
NOOBJ=
SUBDIR=	stand

# config the fattest kernel we can find into a temporary dir
# to create a Makefile.  Then use make to pull some variables
# out and push them into the sub-shell to expand the paths,
# and finally run ctags.
tags::
	TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \
	eval "S=${S}" && \
	config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \
	eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \
	eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \
	eval "_machdir=\$S/arch/$${_mach}" && \
	eval "_archdir=\$S/arch/$${_arch}" && \
	eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \
	eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \
	eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \
	eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \
	ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \
	egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \
	    sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3	\\1	/^\\2(\\3\\4$$/;" \
	    >> ${TAGS} && \
	sort -o ${TAGS} ${TAGS} && \
	rm -rf $${TDIR}

links:
	-for i in conf ${TDIRS}; do \
	    (cd $$i && rm -f tags; ln -s tags tags); done

obj:	_SUBDIRUSE

.include <bsd.prog.mk>

path: sys/arch/aviion/Makefile


path: sys/arch/aviion/aviion/CVS/Entries


code: src/sys/arch/aviion/aviion

path: sys/arch/aviion/aviion/CVS/Repository