code:
/*	$OpenBSD: imxesdhc.c,v 1.12 2015/05/30 03:20:54 jsg Exp $	*/
/*
 * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
 * Copyright (c) 2012-2013 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.
 */

/* i.MX SD/MMC support derived from /sys/dev/sdmmc/sdhc.c */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/bus.h>

#include <dev/sdmmc/sdmmcchip.h>
#include <dev/sdmmc/sdmmcvar.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/imx/imxccmvar.h>
#include <armv7/imx/imxgpiovar.h>

/* registers */
#define SDHC_DS_ADDR			0x00
#define SDHC_BLK_ATT			0x04
#define SDHC_CMD_ARG			0x08
#define SDHC_CMD_XFR_TYP		0x0c
#define SDHC_CMD_RSP0			0x10
#define SDHC_CMD_RSP1			0x14
#define SDHC_CMD_RSP2			0x18
#define SDHC_CMD_RSP3			0x1c
#define SDHC_DATA_BUFF_ACC_PORT		0x20
#define SDHC_PRES_STATE			0x24
#define SDHC_PROT_CTRL			0x28
#define SDHC_SYS_CTRL			0x2c
#define SDHC_INT_STATUS			0x30
#define SDHC_INT_STATUS_EN		0x34
#define SDHC_INT_SIGNAL_EN		0x38
#define SDHC_AUTOCMD12_ERR_STATUS	0x3c
#define SDHC_HOST_CTRL_CAP		0x40
#define SDHC_WTMK_LVL			0x44
#define SDHC_MIX_CTRL			0x48
#define SDHC_FORCE_EVENT		0x50
#define SDHC_ADMA_ERR_STATUS		0x54
#define SDHC_ADMA_SYS_ADDR		0x58
#define SDHC_DLL_CTRL			0x60
#define SDHC_DLL_STATUS			0x64
#define SDHC_CLK_TUNE_CTRL_STATUS	0x68
#define SDHC_VEND_SPEC			0xc0
#define SDHC_MMC_BOOT			0xc4
#define SDHC_VEND_SPEC2			0xc8
#define SDHC_HOST_CTRL_VER		0xfc

/* bits and bytes */
#define SDHC_BLK_ATT_BLKCNT_MAX			0xffff
#define SDHC_BLK_ATT_BLKCNT_SHIFT		16
#define SDHC_BLK_ATT_BLKSIZE_SHIFT		0
#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT		24
#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK	(0x3f << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT)
#define SDHC_CMD_XFR_TYP_CMDTYP_SHIFT		22
#define SDHC_CMD_XFR_TYP_DPSEL_SHIFT		21
#define SDHC_CMD_XFR_TYP_DPSEL			(1 << SDHC_CMD_XFR_TYP_DPSEL_SHIFT)
#define SDHC_CMD_XFR_TYP_CICEN_SHIFT		20
#define SDHC_CMD_XFR_TYP_CICEN			(1 << SDHC_CMD_XFR_TYP_CICEN_SHIFT)
#define SDHC_CMD_XFR_TYP_CCCEN_SHIFT		19
#define SDHC_CMD_XFR_TYP_CCCEN			(1 << SDHC_CMD_XFR_TYP_CCCEN_SHIFT)
#define SDHC_CMD_XFR_TYP_RSPTYP_SHIFT		16
#define SDHC_CMD_XFR_TYP_RSP_NONE		(0x0 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
#define SDHC_CMD_XFR_TYP_RSP136			(0x1 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
#define SDHC_CMD_XFR_TYP_RSP48			(0x2 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
#define SDHC_CMD_XFR_TYP_RSP48B			(0x3 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
#define SDHC_PRES_STATE_WPSPL			(1 << 19)
#define SDHC_PRES_STATE_BREN			(1 << 11)
#define SDHC_PRES_STATE_BWEN			(1 << 10)
#define SDHC_PRES_STATE_SDSTB			(1 << 3)
#define SDHC_PRES_STATE_DLA			(1 << 2)
#define SDHC_PRES_STATE_CDIHB			(1 << 1)
#define SDHC_PRES_STATE_CIHB			(1 << 0)
#define SDHC_SYS_CTRL_RSTA			(1 << 24)
#define SDHC_SYS_CTRL_RSTC			(1 << 25)
#define SDHC_SYS_CTRL_RSTD			(1 << 26)
#define SDHC_SYS_CTRL_CLOCK_MASK		(0xfff << 4)
#define SDHC_SYS_CTRL_CLOCK_DIV_SHIFT		4
#define SDHC_SYS_CTRL_CLOCK_PRE_SHIFT		8
#define SDHC_SYS_CTRL_DTOCV_SHIFT		16
#define SDHC_INT_STATUS_CC			(1 << 0)
#define SDHC_INT_STATUS_TC			(1 << 1)
#define SDHC_INT_STATUS_BGE			(1 << 2)
#define SDHC_INT_STATUS_DINT			(1 << 3)
#define SDHC_INT_STATUS_BWR			(1 << 4)
#define SDHC_INT_STATUS_BRR			(1 << 5)
#define SDHC_INT_STATUS_CINS			(1 << 6)
#define SDHC_INT_STATUS_CRM			(1 << 7)
#define SDHC_INT_STATUS_CINT			(1 << 8)
#define SDHC_INT_STATUS_CTOE			(1 << 16)
#define SDHC_INT_STATUS_CCE			(1 << 17)
#define SDHC_INT_STATUS_CEBE			(1 << 18)
#define SDHC_INT_STATUS_CIC			(1 << 19)
#define SDHC_INT_STATUS_DTOE			(1 << 20)
#define SDHC_INT_STATUS_DCE			(1 << 21)
#define SDHC_INT_STATUS_DEBE			(1 << 22)
#define SDHC_INT_STATUS_DMAE			(1 << 28)
#define SDHC_INT_STATUS_CMD_ERR			(SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CCE)
#define SDHC_INT_STATUS_ERR			(SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE | SDHC_INT_STATUS_CEBE | \
						 SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE | \
						 SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE)
#define SDHC_MIX_CTRL_DMAEN			(1 << 0)
#define SDHC_MIX_CTRL_BCEN			(1 << 1)
#define SDHC_MIX_CTRL_AC12EN			(1 << 2)
#define SDHC_MIX_CTRL_DTDSEL			(1 << 4)
#define SDHC_MIX_CTRL_MSBSEL			(1 << 5)
#define SDHC_PROT_CTRL_DMASEL_SDMA_MASK		(0x3 << 8)
#define SDHC_HOST_CTRL_CAP_MBL_SHIFT		16
#define SDHC_HOST_CTRL_CAP_MBL_MASK		0x7
#define SDHC_HOST_CTRL_CAP_HSS			(1 << 21)
#define SDHC_HOST_CTRL_CAP_VS33			(1 << 24)
#define SDHC_HOST_CTRL_CAP_VS30			(1 << 25)
#define SDHC_HOST_CTRL_CAP_VS18			(1 << 26)
#define SDHC_VEND_SPEC_FRC_SDCLK_ON		(1 << 8)
#define SDHC_WTMK_LVL_RD_WML_SHIFT		0
#define SDHC_WTMK_LVL_WR_WML_SHIFT		16

#define SDHC_COMMAND_TIMEOUT	hz
#define SDHC_BUFFER_TIMEOUT	hz
#define SDHC_TRANSFER_TIMEOUT	hz

void imxesdhc_attach(struct device *parent, struct device *self, void *args);

#include <machine/bus.h>

struct imxesdhc_softc {
	struct device sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	void			*sc_ih; /* Interrupt handler */
	u_int sc_flags;

	int unit;			/* unit id */
	struct device *sdmmc;		/* generic SD/MMC device */
	int clockbit;			/* clock control bit */
	u_int clkbase;			/* base clock frequency in KHz */
	int maxblklen;			/* maximum block length */
	int flags;			/* flags for this host */
	uint32_t ocr;			/* OCR value from capabilities */
//	u_int8_t regs[14];		/* host controller state */
	uint32_t intr_status;		/* soft interrupt status */
	uint32_t intr_error_status;	/*  */
};

/* Host controller functions called by the attachment driver. */
int	imxesdhc_host_found(struct imxesdhc_softc *, bus_space_tag_t,
	    bus_space_handle_t, bus_size_t, int);
void	imxesdhc_power(int, void *);
void	imxesdhc_shutdown(void *);
int	imxesdhc_intr(void *);

/* RESET MODES */
#define MMC_RESET_DAT	1
#define MMC_RESET_CMD	2
#define MMC_RESET_ALL	(MMC_RESET_CMD|MMC_RESET_DAT)

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

/* flag values */
#define SHF_USE_DMA		0x0001

/* SDHC should only be accessed with 4 byte reads or writes. */
#define HREAD4(sc, reg)							\
	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val)						\
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))

int	imxesdhc_host_reset(sdmmc_chipset_handle_t);
uint32_t imxesdhc_host_ocr(sdmmc_chipset_handle_t);
int	imxesdhc_host_maxblklen(sdmmc_chipset_handle_t);
int	imxesdhc_card_detect(sdmmc_chipset_handle_t);
int	imxesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
int	imxesdhc_bus_clock(sdmmc_chipset_handle_t, int);
void	imxesdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
void	imxesdhc_card_intr_ack(sdmmc_chipset_handle_t);
void	imxesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
int	imxesdhc_start_command(struct imxesdhc_softc *, struct sdmmc_command *);
int	imxesdhc_wait_state(struct imxesdhc_softc *, uint32_t, uint32_t);
int	imxesdhc_soft_reset(struct imxesdhc_softc *, int);
int	imxesdhc_wait_intr(struct imxesdhc_softc *, int, int);
void	imxesdhc_transfer_data(struct imxesdhc_softc *, struct sdmmc_command *);
void	imxesdhc_read_data(struct imxesdhc_softc *, u_char *, int);
void	imxesdhc_write_data(struct imxesdhc_softc *, u_char *, int);

//#define SDHC_DEBUG
#ifdef SDHC_DEBUG
int imxesdhcdebug = 20;
#define DPRINTF(n,s)	do { if ((n) <= imxesdhcdebug) printf s; } while (0)
#else
#define DPRINTF(n,s)	do {} while(0)
#endif

struct sdmmc_chip_functions imxesdhc_functions = {
	/* host controller reset */
	imxesdhc_host_reset,
	/* host controller capabilities */
	imxesdhc_host_ocr,
	imxesdhc_host_maxblklen,
	/* card detection */
	imxesdhc_card_detect,
	/* bus power and clock frequency */
	imxesdhc_bus_power,
	imxesdhc_bus_clock,
	/* command execution */
	imxesdhc_exec_command,
	/* card interrupt */
	imxesdhc_card_intr_mask,
	imxesdhc_card_intr_ack
};

struct cfdriver imxesdhc_cd = {
	NULL, "imxesdhc", DV_DULL
};

struct cfattach imxesdhc_ca = {
	sizeof(struct imxesdhc_softc), NULL, imxesdhc_attach
};

void
imxesdhc_attach(struct device *parent, struct device *self, void *args)
{
	struct imxesdhc_softc		*sc = (struct imxesdhc_softc *) self;
	struct armv7_attach_args	*aa = args;
	struct sdmmcbus_attach_args	 saa;
	int				 error = 1;
	uint32_t			 caps;

	sc->unit = aa->aa_dev->unit;
	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("imxesdhc_attach: bus_space_map failed!");

	printf("\n");

	/* XXX DMA channels? */

	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_SDMMC,
	   imxesdhc_intr, sc, sc->sc_dev.dv_xname);

	/*
	 * Reset the host controller and enable interrupts.
	 */
	if (imxesdhc_host_reset(sc))
		goto err;

	/* Determine host capabilities. */
	caps = HREAD4(sc, SDHC_HOST_CTRL_CAP);

	/*
	 * Determine the base clock frequency. (2.2.24)
	 */
	sc->clkbase = imxccm_get_usdhx(aa->aa_dev->unit + 1);

	/*
	 * Determine SD bus voltage levels supported by the controller.
	 */
	if (caps & SDHC_HOST_CTRL_CAP_VS18)
		SET(sc->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
	if (caps & SDHC_HOST_CTRL_CAP_VS30)
		SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
	if (caps & SDHC_HOST_CTRL_CAP_VS33)
		SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);

	/*
	 * Determine max block size.
	 */
	switch ((caps >> SDHC_HOST_CTRL_CAP_MBL_SHIFT)
	    & SDHC_HOST_CTRL_CAP_MBL_MASK) {
	case 0:
		sc->maxblklen = 512;
		break;
	case 1:
		sc->maxblklen = 1024;
		break;
	case 2:
		sc->maxblklen = 2048;
		break;
	case 3:
		sc->maxblklen = 4096;
		break;
	default:
		sc->maxblklen = 512;
		printf("invalid capability blocksize in capa %08x,"
		    " trying 512\n", caps);
	}

	/* somewhere this blksize might be used instead of the device's */
	sc->maxblklen = 512;

	/*
	 * Attach the generic SD/MMC bus driver.  (The bus driver must
	 * not invoke any chipset functions before it is attached.)
	 */

	bzero(&saa, sizeof(saa));
	saa.saa_busname = "sdmmc";
	saa.sct = &imxesdhc_functions;
	saa.sch = sc;
	if (caps & SDHC_HOST_CTRL_CAP_HSS)
		saa.caps |= SMC_CAPS_MMC_HIGHSPEED;

	sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
	if (sc->sdmmc == NULL) {
		error = 0;
		goto err;
	}

	return;

err:
	return;
}

/*
 * Power hook established by or called from attachment driver.
 */
void
imxesdhc_power(int why, void *arg)
{
}

/*
 * Shutdown hook established by or called from attachment driver.
 */
void
imxesdhc_shutdown(void *arg)
{
	struct imxesdhc_softc *sc = arg;

	/* XXX chip locks up if we don't disable it before reboot. */
	(void)imxesdhc_host_reset(sc);
}

/*
 * Reset the host controller.  Called during initialization, when
 * cards are removed, upon resume, and during error recovery.
 */
int
imxesdhc_host_reset(sdmmc_chipset_handle_t sch)
{
	struct imxesdhc_softc *sc = sch;
	u_int32_t imask;
	int error;
	int s;

	s = splsdmmc();

	/* Disable all interrupts. */
	HWRITE4(sc, SDHC_INT_STATUS_EN, 0);
	HWRITE4(sc, SDHC_INT_SIGNAL_EN, 0);

	/*
	 * Reset the entire host controller and wait up to 100ms for
	 * the controller to clear the reset bit.
	 */
	if ((error = imxesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTA)) != 0) {
		splx(s);
		return (error);
	}

	/* Set data timeout counter value to max for now. */
	HSET4(sc, SDHC_SYS_CTRL, 0xe << SDHC_SYS_CTRL_DTOCV_SHIFT);

	/* Enable interrupts. */
	imask = SDHC_INT_STATUS_CC | SDHC_INT_STATUS_TC |
	    SDHC_INT_STATUS_BGE |
#ifdef SDHC_DMA
	    SHDC_INT_STATUS_DINT;
#else
	    SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR;
#endif

	imask |= SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE |
	    SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CIC |
	    SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE |
	    SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE;

	HWRITE4(sc, SDHC_INT_STATUS_EN, imask);
	HWRITE4(sc, SDHC_INT_SIGNAL_EN, imask);

	// Use no or simple DMA
	HWRITE4(sc, SDHC_PROT_CTRL,
	    HREAD4(sc, SDHC_PROT_CTRL) & ~SDHC_PROT_CTRL_DMASEL_SDMA_MASK);

	splx(s);
	return 0;
}

uint32_t
imxesdhc_host_ocr(sdmmc_chipset_handle_t sch)
{
	struct imxesdhc_softc *sc = sch;
	return sc->ocr;
}

int
imxesdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
{
	struct imxesdhc_softc *sc = sch;
	return sc->maxblklen;
}

/*
 * Return non-zero if the card is currently inserted.
 */
int
imxesdhc_card_detect(sdmmc_chipset_handle_t sch)
{
	struct imxesdhc_softc *sc = sch;
	int gpio;

	switch (board_id)
	{
	case BOARD_ID_IMX6_CUBOXI:
	case BOARD_ID_IMX6_HUMMINGBOARD:
		switch (sc->unit) {
			case 1:
				gpio = 0*32 + 4;
				break;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_PHYFLEX:
		switch (sc->unit) {
			case 1:
				gpio = 0*32 + 4;
				break;
			case 2:
				gpio = 0*32 + 27;
				break;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_SABRELITE:
		switch (sc->unit) {
			case 2:
				gpio = 6*32 + 0;
				break;
			case 3:
				gpio = 1*32 + 6;
				break;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_SABRESD:
		switch (sc->unit) {
			case 1:
				gpio = 1*32 + 2;
				break;
			case 2:
				gpio = 1*32 + 0;
				break;
			case 3:
				return 1;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_UDOO:
		switch (sc->unit) {
			case 2:
				return 1;
			default:
				return 0;
		}
	case BOARD_ID_IMX6_UTILITE:
		switch (sc->unit) {
			case 2:
				gpio = 6*32 + 1;
				break;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_NOVENA:
		switch (sc->unit) {
			case 1:
				gpio = 0*32 + 4;
				break;
			/* no card detect */
			case 2:
				return 1;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	case BOARD_ID_IMX6_WANDBOARD:
		switch (sc->unit) {
			case 0:
				gpio = 0*32 + 2;
				break;
			case 2:
				gpio = 2*32 + 9;
				break;
			default:
				return 0;
		}
		imxgpio_set_dir(gpio, IMXGPIO_DIR_IN);
		return imxgpio_get_bit(gpio) ? 0 : 1;
	default:
		printf("%s: unhandled board\n", __func__);
		return 1;
	}
}

/*
 * Set or change SD bus voltage and enable or disable SD bus power.
 * Return zero on success.
 */
int
imxesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
{
	return 0;
}

/*
 * Set or change SDCLK frequency or disable the SD clock.
 * Return zero on success.
 */
int
imxesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
{
	struct imxesdhc_softc *sc = sch;
	int div, pre_div, cur_freq, s;
	int error = 0;

	s = splsdmmc();

	if (sc->clkbase / 16 > freq) {
		for (pre_div = 2; pre_div < 256; pre_div *= 2)
			if ((sc->clkbase / pre_div) <= (freq * 16))
				break;
	} else
		pre_div = 2;

	if (sc->clkbase == freq)
		pre_div = 1;

	for (div = 1; div <= 16; div++)
		if ((sc->clkbase / (div * pre_div)) <= freq)
			break;

	div -= 1;
	pre_div >>= 1;

	cur_freq = sc->clkbase / (pre_div * 2) / (div + 1);

	/* disable force CLK ouput active */
	HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);

	/* wait while clock is unstable */
	if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
		goto ret;

	HCLR4(sc, SDHC_SYS_CTRL, SDHC_SYS_CTRL_CLOCK_MASK);
	HSET4(sc, SDHC_SYS_CTRL, (div << SDHC_SYS_CTRL_CLOCK_DIV_SHIFT) | (pre_div << SDHC_SYS_CTRL_CLOCK_PRE_SHIFT));

	/* wait while clock is unstable */
	if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
		goto ret;

ret:
	splx(s);
	return error;
}

void
imxesdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
{
	printf("imxesdhc_card_intr_mask\n");
	/* - this is SDIO card interrupt */
	struct imxesdhc_softc *sc = sch;

	if (enable) {
		HSET4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
		HSET4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
	} else {
		HCLR4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
		HCLR4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
	}
}

void
imxesdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
{
	printf("imxesdhc_card_intr_ack\n");
	struct imxesdhc_softc *sc = sch;

	HWRITE4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
}

int
imxesdhc_wait_state(struct imxesdhc_softc *sc, uint32_t mask, uint32_t value)
{
	uint32_t state;
	int timeout;
	state = HREAD4(sc, SDHC_PRES_STATE);
	DPRINTF(3,("%s: wait_state %x %x %x)\n", HDEVNAME(sc),
	    mask, value, state));
	for (timeout = 1000; timeout > 0; timeout--) {
		if (((state = HREAD4(sc, SDHC_PRES_STATE)) & mask) == value)
			return 0;
		delay(10);
	}
	DPRINTF(0,("%s: timeout waiting for %x, state %x\n", HDEVNAME(sc),
	    value, state));
	return ETIMEDOUT;
}

void
imxesdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
{
	struct imxesdhc_softc *sc = sch;
	int error;

	/*
	 * Start the command, or mark `cmd' as failed and return.
	 */
	error = imxesdhc_start_command(sc, cmd);
	if (error != 0) {
		cmd->c_error = error;
		SET(cmd->c_flags, SCF_ITSDONE);
		return;
	}

	/*
	 * Wait until the command phase is done, or until the command
	 * is marked done for any other reason.
	 */
	if (!imxesdhc_wait_intr(sc, SDHC_INT_STATUS_CC, SDHC_COMMAND_TIMEOUT)) {
		cmd->c_error = ETIMEDOUT;
		SET(cmd->c_flags, SCF_ITSDONE);
		return;
	}

	/*
	 * The host controller removes bits [0:7] from the response
	 * data (CRC) and we pass the data up unchanged to the bus
	 * driver (without padding).
	 */
	if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
			cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
			cmd->c_resp[1] = HREAD4(sc, SDHC_CMD_RSP1);
			cmd->c_resp[2] = HREAD4(sc, SDHC_CMD_RSP2);
			cmd->c_resp[3] = HREAD4(sc, SDHC_CMD_RSP3);

#ifdef SDHC_DEBUG
			printf("resp[0] 0x%08x\nresp[1] 0x%08x\nresp[2] 0x%08x\nresp[3] 0x%08x\n", cmd->c_resp[0], cmd->c_resp[1], cmd->c_resp[2], cmd->c_resp[3]);
#endif
		} else  {
			cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
#ifdef SDHC_DEBUG
			printf("resp[0] 0x%08x\n", cmd->c_resp[0]);
#endif
		}
	}

	/*
	 * If the command has data to transfer in any direction,
	 * execute the transfer now.
	 */
	if (cmd->c_error == 0 && cmd->c_data)
		imxesdhc_transfer_data(sc, cmd);

	DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
	    HDEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error));
	SET(cmd->c_flags, SCF_ITSDONE);
}

int
imxesdhc_start_command(struct imxesdhc_softc *sc, struct sdmmc_command *cmd)
{
	u_int32_t blksize = 0;
	u_int32_t blkcount = 0;
	u_int32_t command;
	int error;
	int s;

	DPRINTF(1,("%s: start cmd %u arg=%#x data=%p dlen=%d flags=%#x "
	    "proc=\"%s\"\n", HDEVNAME(sc), cmd->c_opcode, cmd->c_arg,
	    cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ?
	    curproc->p_comm : ""));

	/*
	 * The maximum block length for commands should be the minimum
	 * of the host buffer size and the card buffer size. (1.7.2)
	 */

	/* Fragment the data into proper blocks. */
	if (cmd->c_datalen > 0) {
		blksize = MIN(cmd->c_datalen, cmd->c_blklen);
		blkcount = cmd->c_datalen / blksize;
		if (cmd->c_datalen % blksize > 0) {
			/* XXX: Split this command. (1.7.4) */
			printf("%s: data not a multiple of %d bytes\n",
			    HDEVNAME(sc), blksize);
			return EINVAL;
		}
	}

	/* Check limit imposed by 9-bit block count. (1.7.2) */
	if (blkcount > SDHC_BLK_ATT_BLKCNT_MAX) {
		printf("%s: too much data\n", HDEVNAME(sc));
		return EINVAL;
	}

	/* setup for PIO, check for write protection */
	if (!ISSET(cmd->c_flags, SCF_CMD_READ)) {
		if (!(HREAD4(sc, SDHC_PRES_STATE) & SDHC_PRES_STATE_WPSPL)) {
			printf("%s: card is write protected\n",
			    HDEVNAME(sc));
			return EINVAL;
		}
	}

#ifdef SDHC_DMA
	/* set watermark level */
	uint32_t wml = blksize / sizeof(uint32_t);
	if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
		if (wml > 16)
			wml = 16;
		HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_RD_WML_SHIFT);
	} else {
		if (wml > 128)
			wml = 128;
		HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_WR_WML_SHIFT);
	}
#endif

	/* Prepare transfer mode register value. (2.2.5) */
	command = 0;

	if (ISSET(cmd->c_flags, SCF_CMD_READ))
		command |= SDHC_MIX_CTRL_DTDSEL;
	if (blkcount > 0) {
		command |= SDHC_MIX_CTRL_BCEN;
#ifdef SDHC_DMA
		command |= SDHC_MIX_CTRL_DMAEN;
#endif
		if (blkcount > 1) {
			command |= SDHC_MIX_CTRL_MSBSEL;
			command |= SDHC_MIX_CTRL_AC12EN;
		}
	}

	command |= (cmd->c_opcode << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT) &
	   SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK;

	if (ISSET(cmd->c_flags, SCF_RSP_CRC))
		command |= SDHC_CMD_XFR_TYP_CCCEN;
	if (ISSET(cmd->c_flags, SCF_RSP_IDX))
		command |= SDHC_CMD_XFR_TYP_CICEN;
	if (cmd->c_data != NULL)
		command |= SDHC_CMD_XFR_TYP_DPSEL;

	if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
		command |= SDHC_CMD_XFR_TYP_RSP_NONE;
	else if (ISSET(cmd->c_flags, SCF_RSP_136))
		command |= SDHC_CMD_XFR_TYP_RSP136;
	else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
		command |= SDHC_CMD_XFR_TYP_RSP48B;
	else
		command |= SDHC_CMD_XFR_TYP_RSP48;

	/* Wait until command and data inhibit bits are clear. (1.5) */
	if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_CIHB, 0)) != 0)
		return error;

	s = splsdmmc();

	/*
	 * Start a CPU data transfer.  Writing to the high order byte
	 * of the SDHC_COMMAND register triggers the SD command. (1.5)
	 */
#ifdef SDHC_DMA
	if (cmd->c_data)
		HWRITE4(sc, SDHC_DS_ADDR, (uint32_t)cmd->c_data);
#endif
	HWRITE4(sc, SDHC_BLK_ATT, blkcount << SDHC_BLK_ATT_BLKCNT_SHIFT |
	    blksize << SDHC_BLK_ATT_BLKSIZE_SHIFT);
	HWRITE4(sc, SDHC_CMD_ARG, cmd->c_arg);
	HWRITE4(sc, SDHC_MIX_CTRL,
	    (HREAD4(sc, SDHC_MIX_CTRL) & (0xf << 22)) | (command & 0xffff));
	HWRITE4(sc, SDHC_CMD_XFR_TYP, command);

	splx(s);
	return 0;
}

void
imxesdhc_transfer_data(struct imxesdhc_softc *sc, struct sdmmc_command *cmd)
{
#ifndef SDHC_DMA
	u_char *datap = cmd->c_data;
	int i;
#endif
	int datalen;
	int mask;
	int error;

	mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
	    SDHC_PRES_STATE_BREN : SDHC_PRES_STATE_BWEN;
	error = 0;
	datalen = cmd->c_datalen;

	DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(sc),
	    MMC_R1(cmd->c_resp), datalen));

#ifndef SDHC_DMA
	while (datalen > 0) {
		if (!imxesdhc_wait_intr(sc, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR,
		    SDHC_BUFFER_TIMEOUT)) {
			error = ETIMEDOUT;
			break;
		}

		if ((error = imxesdhc_wait_state(sc, mask, mask)) != 0)
			break;

		/* FIXME: wait a bit, else it fails */
		delay(100);
		i = MIN(datalen, cmd->c_blklen);
		if (ISSET(cmd->c_flags, SCF_CMD_READ))
			imxesdhc_read_data(sc, datap, i);
		else
			imxesdhc_write_data(sc, datap, i);

		datap += i;
		datalen -= i;
	}
#endif

	if (error == 0 && !imxesdhc_wait_intr(sc, SDHC_INT_STATUS_TC,
	    SDHC_TRANSFER_TIMEOUT))
		error = ETIMEDOUT;

	if (error != 0)
		cmd->c_error = error;
	SET(cmd->c_flags, SCF_ITSDONE);

	DPRINTF(1,("%s: data transfer done (error=%d)\n",
	    HDEVNAME(sc), cmd->c_error));
}

void
imxesdhc_read_data(struct imxesdhc_softc *sc, u_char *datap, int datalen)
{
	while (datalen > 3) {
		*(uint32_t *)datap = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
		datap += 4;
		datalen -= 4;
	}
	if (datalen > 0) {
		uint32_t rv = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
		do {
			*datap++ = rv & 0xff;
			rv = rv >> 8;
		} while (--datalen > 0);
	}
}

void
imxesdhc_write_data(struct imxesdhc_softc *sc, u_char *datap, int datalen)
{
	while (datalen > 3) {
		DPRINTF(3,("%08x\n", *(uint32_t *)datap));
		HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, *((uint32_t *)datap));
		datap += 4;
		datalen -= 4;
	}
	if (datalen > 0) {
		uint32_t rv = *datap++;
		if (datalen > 1)
			rv |= *datap++ << 8;
		if (datalen > 2)
			rv |= *datap++ << 16;
		DPRINTF(3,("rv %08x\n", rv));
		HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, rv);
	}
}

/* Prepare for another command. */
int
imxesdhc_soft_reset(struct imxesdhc_softc *sc, int mask)
{
	int timo;

	DPRINTF(1,("%s: software reset reg=%#x\n", HDEVNAME(sc), mask));

	/* disable force CLK ouput active */
	HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);

	/* reset */
	HSET4(sc, SDHC_SYS_CTRL, mask);
	delay(10);

	for (timo = 1000; timo > 0; timo--) {
		if (!ISSET(HREAD4(sc, SDHC_SYS_CTRL), mask))
			break;
		delay(10);
	}
	if (timo == 0) {
		DPRINTF(1,("%s: timeout reg=%#x\n", HDEVNAME(sc),
		    HREAD4(sc, SDHC_SYS_CTRL)));
		return ETIMEDOUT;
	}

	return 0;
}

int
imxesdhc_wait_intr(struct imxesdhc_softc *sc, int mask, int timo)
{
	int status;
	int s;

	mask |= SDHC_INT_STATUS_ERR;
	s = splsdmmc();

	/* enable interrupts for brr and bwr */
	if (mask & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
		HSET4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));

	status = sc->intr_status & mask;
	while (status == 0) {
		if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
		    == EWOULDBLOCK) {
			status |= SDHC_INT_STATUS_ERR;
			break;
		}
		status = sc->intr_status & mask;
	}
	sc->intr_status &= ~status;
	DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(sc), status,
	    sc->intr_error_status));

	/* Command timeout has higher priority than command complete. */
	if (ISSET(status, SDHC_INT_STATUS_ERR)) {
		sc->intr_error_status = 0;
		(void)imxesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTC | SDHC_SYS_CTRL_RSTD);
		status = 0;
	}

	splx(s);
	return status;
}

/*
 * Established by attachment driver at interrupt priority IPL_SDMMC.
 */
int
imxesdhc_intr(void *arg)
{
	struct imxesdhc_softc *sc = arg;

	u_int32_t status;

	/* Find out which interrupts are pending. */
	status = HREAD4(sc, SDHC_INT_STATUS);

#ifndef SDHC_DMA
	/* disable interrupts for brr and bwr, else we get flooded */
	if (status & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
		HCLR4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));
#endif

	/* Acknowledge the interrupts we are about to handle. */
	HWRITE4(sc, SDHC_INT_STATUS, status);
	DPRINTF(2,("%s: interrupt status=0x%08x\n", HDEVNAME(sc),
	    status));

	/*
	 * Service error interrupts.
	 */
	if (ISSET(status, SDHC_INT_STATUS_CMD_ERR |
	    SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_DTOE)) {
		sc->intr_status |= status;
		sc->intr_error_status |= status & 0xffff0000;
		wakeup(&sc->intr_status);
	}

	/*
	 * Wake up the blocking process to service command
	 * related interrupt(s).
	 */
	if (ISSET(status, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR |
	    SDHC_INT_STATUS_TC | SDHC_INT_STATUS_CC)) {
		sc->intr_status |= status;
		wakeup(&sc->intr_status);
	}

	/*
	 * Service SD card interrupts.
	 */
	if (ISSET(status, SDHC_INT_STATUS_CINT)) {
		DPRINTF(0,("%s: card interrupt\n", HDEVNAME(sc)));
		HCLR4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
		sdmmc_card_intr(sc->sdmmc);
	}
	return 1;
}


code:
/* $OpenBSD: imxgpio.c,v 1.7 2015/05/14 03:13:20 jsg Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2012-2013 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.
 */

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

#include <arm/cpufunc.h>

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

#include <armv7/armv7/armv7var.h>
#include <armv7/imx/imxgpiovar.h>

/* iMX6 registers */
#define GPIO_DR			0x00
#define GPIO_GDIR		0x04
#define GPIO_PSR		0x08
#define GPIO_ICR1		0x0C
#define GPIO_ICR2		0x10
#define GPIO_IMR		0x14
#define GPIO_ISR		0x18
#define GPIO_EDGE_SEL		0x1C

#define GPIO_NUM_PINS		32

struct intrhand {
	int (*ih_func)(void *);		/* handler */
	void *ih_arg;			/* arg for handler */
	int ih_ipl;			/* IPL_* */
	int ih_irq;			/* IRQ number */
	int ih_gpio;			/* gpio pin */
	struct evcount	ih_count;
	char *ih_name;
};

struct imxgpio_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	void			*sc_ih_h;
	void			*sc_ih_l;
	int 			sc_max_il;
	int 			sc_min_il;
	int			sc_irq;
	struct intrhand		*sc_handlers[GPIO_NUM_PINS];
	unsigned int (*sc_get_bit)(struct imxgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_set_bit)(struct imxgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_clear_bit)(struct imxgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_set_dir)(struct imxgpio_softc *sc,
	    unsigned int gpio, unsigned int dir);
};

#define GPIO_PIN_TO_INST(x)	((x) >> 5)
#define GPIO_PIN_TO_OFFSET(x)	((x) & 0x1f)

void imxgpio_attach(struct device *parent, struct device *self, void *args);
void imxgpio_recalc_interrupts(struct imxgpio_softc *sc);
int imxgpio_irq(void *);
int imxgpio_irq_dummy(void *);

unsigned int imxgpio_v6_get_bit(struct imxgpio_softc *, unsigned int);
void imxgpio_v6_set_bit(struct imxgpio_softc *, unsigned int);
void imxgpio_v6_clear_bit(struct imxgpio_softc *, unsigned int);
void imxgpio_v6_set_dir(struct imxgpio_softc *, unsigned int, unsigned int);
unsigned int imxgpio_v6_get_dir(struct imxgpio_softc *, unsigned int);

struct cfattach	imxgpio_ca = {
	sizeof (struct imxgpio_softc), NULL, imxgpio_attach
};

struct cfdriver imxgpio_cd = {
	NULL, "imxgpio", DV_DULL
};

void
imxgpio_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct imxgpio_softc *sc = (struct imxgpio_softc *) self;

	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("imxgpio_attach: bus_space_map failed!");

	sc->sc_get_bit  = imxgpio_v6_get_bit;
	sc->sc_set_bit = imxgpio_v6_set_bit;
	sc->sc_clear_bit = imxgpio_v6_clear_bit;
	sc->sc_set_dir = imxgpio_v6_set_dir;

	printf("\n");

	/* XXX - IRQ */
	/* XXX - SYSCONFIG */
	/* XXX - CTRL */
	/* XXX - DEBOUNCE */
}

unsigned int
imxgpio_get_bit(unsigned int gpio)
{
	struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	return sc->sc_get_bit(sc, gpio);

}

void
imxgpio_set_bit(unsigned int gpio)
{
	struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	sc->sc_set_bit(sc, gpio);
}

void
imxgpio_clear_bit(unsigned int gpio)
{
	struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	sc->sc_clear_bit(sc, gpio);
}
void
imxgpio_set_dir(unsigned int gpio, unsigned int dir)
{
	struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	sc->sc_set_dir(sc, gpio, dir);
}

unsigned int
imxgpio_v6_get_bit(struct imxgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);

	return (val >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1;
}

void
imxgpio_v6_set_bit(struct imxgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
		val | (1 << GPIO_PIN_TO_OFFSET(gpio)));
}

void
imxgpio_v6_clear_bit(struct imxgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
		val & ~(1 << GPIO_PIN_TO_OFFSET(gpio)));
}

void
imxgpio_v6_set_dir(struct imxgpio_softc *sc, unsigned int gpio, unsigned int dir)
{
	int s;
	u_int32_t val;

	s = splhigh();

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
	if (dir == IMXGPIO_DIR_OUT)
		val |= 1 << GPIO_PIN_TO_OFFSET(gpio);
	else
		val &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val);

	splx(s);
}

unsigned int
imxgpio_v6_get_dir(struct imxgpio_softc *sc, unsigned int gpio)
{
	int s;
	u_int32_t val;

	s = splhigh();

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
	if (val & (1 << GPIO_PIN_TO_OFFSET(gpio)))
		val = IMXGPIO_DIR_OUT;
	else
		val = IMXGPIO_DIR_IN;

	splx(s);
	return val;
}

license: unknown


code:
/* $OpenBSD: imxgpiovar.h,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2012-2013 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 IMXGPIOVAR_H
#define IMXGPIOVAR_H

#define IMXGPIO_DIR_IN	0
#define IMXGPIO_DIR_OUT	1

unsigned int imxgpio_get_function(unsigned int gpio, unsigned int fn);
void imxgpio_set_function(unsigned int gpio, unsigned int fn);
unsigned int imxgpio_get_bit(unsigned int gpio);
void imxgpio_set_bit(unsigned int gpio);
void imxgpio_clear_bit(unsigned int gpio);
void imxgpio_set_dir(unsigned int gpio, unsigned int dir);

/* interrupts */
void imxgpio_clear_intr(unsigned int gpio);
void imxgpio_intr_mask(unsigned int gpio);
void imxgpio_intr_unmask(unsigned int gpio);
void imxgpio_intr_level(unsigned int gpio, unsigned int level);
void *imxgpio_intr_establish(unsigned int gpio, int level, int spl,
    int (*func)(void *), void *arg, char *name);
void imxgpio_intr_disestablish(void *cookie);

#endif /* IMXGPIOVAR_H */


code:
/* $OpenBSD: imxiic.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
/*
 * Copyright (c) 2013 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.
 */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/bus.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/imx/imxiomuxcvar.h>
#include <armv7/imx/imxccmvar.h>
#include <armv7/imx/imxiicvar.h>

/* registers */
#define I2C_IADR	0x00
#define I2C_IFDR	0x04
#define I2C_I2CR	0x08
#define I2C_I2SR	0x0C
#define I2C_I2DR	0x10

#define I2C_I2CR_RSTA	(1 << 2)
#define I2C_I2CR_TXAK	(1 << 3)
#define I2C_I2CR_MTX	(1 << 4)
#define I2C_I2CR_MSTA	(1 << 5)
#define I2C_I2CR_IIEN	(1 << 6)
#define I2C_I2CR_IEN	(1 << 7)
#define I2C_I2SR_RXAK	(1 << 0)
#define I2C_I2SR_IIF	(1 << 1)
#define I2C_I2SR_IBB	(1 << 5)

struct imxiic_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_size_t		sc_ios;
	void			*sc_ih;
	int			unit;

	struct rwlock		sc_buslock;
	struct i2c_controller	i2c_tag;

	uint16_t		frequency;
	uint16_t		intr_status;
	uint16_t		stopped;
};

void imxiic_attach(struct device *, struct device *, void *);
int imxiic_detach(struct device *, int);
void imxiic_setspeed(struct imxiic_softc *, u_int);
int imxiic_intr(void *);
int imxiic_wait_intr(struct imxiic_softc *, int, int);
int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t);
int imxiic_start(struct imxiic_softc *, int, int, void *, int);
int imxiic_read(struct imxiic_softc *, int, int, void *, int);
int imxiic_write(struct imxiic_softc *, int, int, const void *, int);

int imxiic_i2c_acquire_bus(void *, int);
void imxiic_i2c_release_bus(void *, int);
int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
    void *, size_t, int);

#define HREAD2(sc, reg)							\
	(bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE2(sc, reg, val)						\
	bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET2(sc, reg, bits)						\
	HWRITE2((sc), (reg), HREAD2((sc), (reg)) | (bits))
#define HCLR2(sc, reg, bits)						\
	HWRITE2((sc), (reg), HREAD2((sc), (reg)) & ~(bits))

struct cfattach imxiic_ca = {
	sizeof(struct imxiic_softc), NULL, imxiic_attach, imxiic_detach
};

struct cfdriver imxiic_cd = {
	NULL, "imxiic", DV_DULL
};

void
imxiic_attach(struct device *parent, struct device *self, void *args)
{
	struct imxiic_softc *sc = (struct imxiic_softc *)self;
	struct armv7_attach_args *aa = args;

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

#if 0
	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_BIO,
	    imxiic_intr, sc, sc->sc_dev.dv_xname);
#endif

	printf("\n");

	/* set iomux pins */
	imxiomuxc_enable_i2c(sc->unit);

	/* set speed to 100kHz */
	imxiic_setspeed(sc, 100);

	/* reset */
	HWRITE2(sc, I2C_I2CR, 0);
	HWRITE2(sc, I2C_I2SR, 0);

	sc->stopped = 1;
	rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);

	struct i2cbus_attach_args iba;

	sc->i2c_tag.ic_cookie = sc;
	sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus;
	sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus;
	sc->i2c_tag.ic_exec = imxiic_i2c_exec;

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

void
imxiic_setspeed(struct imxiic_softc *sc, u_int speed)
{
	if (!sc->frequency) {
		uint32_t i2c_clk_rate;
		uint32_t div;
		int i;

		i2c_clk_rate = imxccm_get_ipg_perclk();
		div = (i2c_clk_rate + speed - 1) / speed;
		if (div < imxiic_clk_div[0][0])
			i = 0;
		else if (div > imxiic_clk_div[49][0])
			i = 49;
		else
			for (i = 0; imxiic_clk_div[i][0] < div; i++);

		sc->frequency = imxiic_clk_div[i][1];
	}

	HWRITE2(sc, I2C_IFDR, sc->frequency);
}

#if 0
int
imxiic_intr(void *arg)
{
	struct imxiic_softc *sc = arg;
	u_int16_t status;

	status = HREAD2(sc, I2C_I2SR);

	if (ISSET(status, I2C_I2SR_IIF)) {
		/* acknowledge the interrupts */
		HWRITE2(sc, I2C_I2SR,
		    HREAD2(sc, I2C_I2SR) & ~I2C_I2SR_IIF);

		sc->intr_status |= status;
		wakeup(&sc->intr_status);
	}

	return (0);
}

int
imxiic_wait_intr(struct imxiic_softc *sc, int mask, int timo)
{
	int status;
	int s;

	s = splbio();

	status = sc->intr_status & mask;
	while (status == 0) {
		if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
		    == EWOULDBLOCK) {
			break;
		}
		status = sc->intr_status & mask;
	}
	status = sc->intr_status & mask;
	sc->intr_status &= ~status;

	splx(s);
	return status;
}
#endif

int
imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value)
{
	uint32_t state;
	int timeout;
	state = HREAD2(sc, I2C_I2SR);
	for (timeout = 1000; timeout > 0; timeout--) {
		if (((state = HREAD2(sc, I2C_I2SR)) & mask) == value)
			return 0;
		delay(10);
	}
	return ETIMEDOUT;
}

int
imxiic_read(struct imxiic_softc *sc, int addr, int subaddr, void *data, int len)
{
	int i;

	HWRITE2(sc, I2C_I2DR, addr | 1);

	if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
		return (EIO);
	while(!(HREAD2(sc, I2C_I2SR) & I2C_I2SR_IIF));
	if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
		return (EIO);

	HCLR2(sc, I2C_I2CR, I2C_I2CR_MTX);
	if (len)
		HCLR2(sc, I2C_I2CR, I2C_I2CR_TXAK);

	/* dummy read */
	HREAD2(sc, I2C_I2DR);

	for (i = 0; i < len; i++) {
		if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
			return (EIO);
		if (i == (len - 1)) {
			HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
			imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
			sc->stopped = 1;
		} else if (i == (len - 2)) {
			HSET2(sc, I2C_I2CR, I2C_I2CR_TXAK);
		}
		((uint8_t*)data)[i] = HREAD2(sc, I2C_I2DR);
	}

	return 0;
}

int
imxiic_write(struct imxiic_softc *sc, int addr, int subaddr, const void *data, int len)
{
	int i;

	HWRITE2(sc, I2C_I2DR, addr);

	if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
		return (EIO);
	if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
		return (EIO);

	for (i = 0; i < len; i++) {
		HWRITE2(sc, I2C_I2DR, ((uint8_t*)data)[i]);
		if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
			return (EIO);
		if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
			return (EIO);
	}
	return 0;
}

int
imxiic_i2c_acquire_bus(void *cookie, int flags)
{
	struct imxiic_softc *sc = cookie;

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

void
imxiic_i2c_release_bus(void *cookie, int flags)
{
	struct imxiic_softc *sc = cookie;

	(void) rw_exit(&sc->sc_buslock);
}

int
imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
    const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
{
	struct imxiic_softc *sc = cookie;
	uint32_t ret = 0;
	u_int8_t cmd = 0;

	if (!I2C_OP_STOP_P(op) || cmdlen > 1)
		return (EINVAL);

	if (cmdlen > 0)
		cmd = *(u_int8_t *)cmdbuf;

	addr &= 0x7f;

	/* clock gating */
	imxccm_enable_i2c(sc->unit);

	/* set speed to 100kHz */
	imxiic_setspeed(sc, 100);

	/* enable the controller */
	HWRITE2(sc, I2C_I2SR, 0);
	HWRITE2(sc, I2C_I2CR, I2C_I2CR_IEN);

	/* wait for it to be stable */
	delay(50);

	/* start transaction */
	HSET2(sc, I2C_I2CR, I2C_I2CR_MSTA);

	if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) {
		ret = (EIO);
		goto fail;
	}

	sc->stopped = 0;

	HSET2(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK);

	if (I2C_OP_READ_P(op)) {
		if (imxiic_read(sc, (addr << 1), cmd, buf, len) != 0)
			ret = (EIO);
	} else {
		if (imxiic_write(sc, (addr << 1), cmd, buf, len) != 0)
			ret = (EIO);
	}

fail:
	if (!sc->stopped) {
		HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
		imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
		sc->stopped = 1;
	}

	HWRITE2(sc, I2C_I2CR, 0);

	return ret;
}

int
imxiic_detach(struct device *self, int flags)
{
	struct imxiic_softc *sc = (struct imxiic_softc *)self;

	HWRITE2(sc, I2C_IADR, 0);
	HWRITE2(sc, I2C_IFDR, 0);
	HWRITE2(sc, I2C_I2CR, 0);
	HWRITE2(sc, I2C_I2SR, 0);

	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
	return 0;
}


code:
/* $OpenBSD: imxiicvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
/*
 * Copyright (c) 2013 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 IMXIICVAR_H
#define IMXIICVAR_H

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

#include <dev/i2c/i2cvar.h>

static uint16_t imxiic_clk_div[50][2] = {
	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
	{ 3072,	0x1E }, { 3840,	0x1F }
};

#endif


code:
/* $OpenBSD: imxiomuxc.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
/*
 * Copyright (c) 2013 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <armv7/armv7/armv7var.h>

/* registers */
#define IOMUXC_GPR1			0x004
#define IOMUXC_GPR8			0x020
#define IOMUXC_GPR12			0x030
#define IOMUXC_GPR13			0x034

#define IOMUXC_MUX_CTL_PAD_EIM_EB2	0x08C
#define IOMUXC_MUX_CTL_PAD_EIM_DATA16	0x090
#define IOMUXC_MUX_CTL_PAD_EIM_DATA17	0x094
#define IOMUXC_MUX_CTL_PAD_EIM_DATA18	0x098
#define IOMUXC_MUX_CTL_PAD_EIM_DATA21	0x0A4
#define IOMUXC_MUX_CTL_PAD_EIM_DATA28	0x0C4

#define IOMUXC_PAD_CTL_PAD_EIM_EB2	0x3A0
#define IOMUXC_PAD_CTL_PAD_EIM_DATA16	0x3A4
#define IOMUXC_PAD_CTL_PAD_EIM_DATA17	0x3A8
#define IOMUXC_PAD_CTL_PAD_EIM_DATA18	0x3AC
#define IOMUXC_PAD_CTL_PAD_EIM_DATA21	0x3B8
#define IOMUXC_PAD_CTL_PAD_EIM_DATA28	0x3D8

#define IOMUXC_I2C1_SCL_IN_SELECT_INPUT	0x898
#define IOMUXC_I2C1_SDA_IN_SELECT_INPUT	0x89C
#define IOMUXC_I2C2_SCL_IN_SELECT_INPUT	0x8A0
#define IOMUXC_I2C2_SDA_IN_SELECT_INPUT	0x8A4
#define IOMUXC_I2C3_SCL_IN_SELECT_INPUT	0x8A8
#define IOMUXC_I2C3_SDA_IN_SELECT_INPUT	0x8AC

/* bits and bytes */
#define IOMUXC_GPR1_REF_SSP_EN					(1 << 16)
#define IOMUXC_GPR1_TEST_POWERDOWN				(1 << 18)

#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1				(0 << 0)
#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB			(0 << 6)
#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB			(20 << 12)
#define IOMUXC_GPR8_PCS_TX_SWING_FULL				(127 << 18)
#define IOMUXC_GPR8_PCS_TX_SWING_LOW				(127 << 25)

#define IOMUXC_GPR12_LOS_LEVEL_MASK				(0x1f << 4)
#define IOMUXC_GPR12_LOS_LEVEL_9				(9 << 4)
#define IOMUXC_GPR12_APPS_PM_XMT_PME				(1 << 9)
#define IOMUXC_GPR12_APPS_LTSSM_ENABLE				(1 << 10)
#define IOMUXC_GPR12_APPS_INIT_RST				(1 << 11)
#define IOMUXC_GPR12_DEVICE_TYPE_RC				(2 << 12)
#define IOMUXC_GPR12_DEVICE_TYPE_MASK				(3 << 12)
#define IOMUXC_GPR12_APPS_PM_XMT_TURNOFF			(1 << 16)

#define IOMUXC_GPR13_SATA_PHY_1_FAST_EDGE_RATE			(0x00 << 0)
#define IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE			(0x02 << 0)
#define IOMUXC_GPR13_SATA_PHY_1_EDGE_RATE_MASK			0x3
#define IOMUXC_GPR13_SATA_PHY_2_1104V				(0x11 << 2)
#define IOMUXC_GPR13_SATA_PHY_3_333DB				(0x00 << 7)
#define IOMUXC_GPR13_SATA_PHY_4_9_16				(0x04 << 11)
#define IOMUXC_GPR13_SATA_PHY_5_SS				(0x01 << 14)
#define IOMUXC_GPR13_SATA_SPEED_3G				(0x01 << 15)
#define IOMUXC_GPR13_SATA_PHY_6					(0x03 << 16)
#define IOMUXC_GPR13_SATA_PHY_7_SATA2M				(0x12 << 19)
#define IOMUXC_GPR13_SATA_PHY_8_30DB				(0x05 << 24)
#define IOMUXC_GPR13_SATA_MASK					0x07FFFFFD

#define IOMUXC_PAD_CTL_SRE_SLOW		(1 << 0)
#define IOMUXC_PAD_CTL_SRE_FAST		(1 << 0)
#define IOMUXC_PAD_CTL_DSE_HIZ		(0 << 3)
#define IOMUXC_PAD_CTL_DSE_240OHM	(1 << 3)
#define IOMUXC_PAD_CTL_DSE_120OHM	(2 << 3)
#define IOMUXC_PAD_CTL_DSE_80OHM	(3 << 3)
#define IOMUXC_PAD_CTL_DSE_60OHM	(4 << 3)
#define IOMUXC_PAD_CTL_DSE_48OHM	(5 << 3)
#define IOMUXC_PAD_CTL_DSE_40OHM	(6 << 3)
#define IOMUXC_PAD_CTL_DSE_34OHM	(7 << 3)
#define IOMUXC_PAD_CTL_SPEED_TBD	(0 << 6)
#define IOMUXC_PAD_CTL_SPEED_LOW	(1 << 6)
#define IOMUXC_PAD_CTL_SPEED_MED	(2 << 6)
#define IOMUXC_PAD_CTL_SPEED_MAX	(3 << 6)
#define IOMUXC_PAD_CTL_ODE_DISABLED	(0 << 11)
#define IOMUXC_PAD_CTL_ODE_ENABLED	(1 << 11)
#define IOMUXC_PAD_CTL_PKE_DISABLED	(0 << 12)
#define IOMUXC_PAD_CTL_PKE_ENABLED	(1 << 12)
#define IOMUXC_PAD_CTL_PUE_KEEP		(0 << 13)
#define IOMUXC_PAD_CTL_PUE_PULL		(1 << 13)
#define IOMUXC_PAD_CTL_PUS_100K_OHM_PD	(0 << 14)
#define IOMUXC_PAD_CTL_PUS_47K_OHM_PU	(1 << 14)
#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU	(2 << 14)
#define IOMUXC_PAD_CTL_PUS_22K_OHM_PU	(3 << 14)
#define IOMUXC_PAD_CTL_HYS_DISABLED	(0 << 16)
#define IOMUXC_PAD_CTL_HYS_ENABLED	(1 << 16)

#define IOMUXC_IMX6Q_I2C_PAD_CTRL	(IOMUXC_PAD_CTL_SRE_FAST | IOMUXC_PAD_CTL_ODE_ENABLED | \
		IOMUXC_PAD_CTL_PKE_ENABLED | IOMUXC_PAD_CTL_PUE_PULL | IOMUXC_PAD_CTL_DSE_40OHM | \
		IOMUXC_PAD_CTL_PUS_100K_OHM_PU | IOMUXC_PAD_CTL_HYS_ENABLED | IOMUXC_PAD_CTL_SPEED_MED)

#define IOMUX_CONFIG_SION		(1 << 4)

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

struct imxiomuxc_softc *imxiomuxc_sc;

void imxiomuxc_attach(struct device *parent, struct device *self, void *args);
void imxiomuxc_enable_sata(void);
void imxiomuxc_enable_i2c(int);
void imxiomuxc_enable_pcie(void);
void imxiomuxc_pcie_refclk(int);
void imxiomuxc_pcie_test_powerdown(int);

struct cfattach imxiomuxc_ca = {
	sizeof (struct imxiomuxc_softc), NULL, imxiomuxc_attach
};

struct cfdriver imxiomuxc_cd = {
	NULL, "imxiomuxc", DV_DULL
};

void
imxiomuxc_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct imxiomuxc_softc *sc = (struct imxiomuxc_softc *) self;

	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("imxiomuxc_attach: bus_space_map failed!");

	printf("\n");
	imxiomuxc_sc = sc;
}

void
imxiomuxc_enable_sata(void)
{
	struct imxiomuxc_softc *sc = imxiomuxc_sc;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13,
	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13) & ~IOMUXC_GPR13_SATA_MASK) |
		IOMUXC_GPR13_SATA_PHY_1_FAST_EDGE_RATE | IOMUXC_GPR13_SATA_PHY_2_1104V |
		IOMUXC_GPR13_SATA_PHY_3_333DB | IOMUXC_GPR13_SATA_PHY_4_9_16 |
		IOMUXC_GPR13_SATA_SPEED_3G | IOMUXC_GPR13_SATA_PHY_6 |
		IOMUXC_GPR13_SATA_PHY_7_SATA2M | IOMUXC_GPR13_SATA_PHY_8_30DB);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13,
	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13) & ~IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE) |
		IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE);
}

void
imxiomuxc_enable_pcie(void)
{
	struct imxiomuxc_softc *sc = imxiomuxc_sc;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_APPS_LTSSM_ENABLE);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_DEVICE_TYPE_MASK) |
		IOMUXC_GPR12_DEVICE_TYPE_RC);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_LOS_LEVEL_MASK) |
		IOMUXC_GPR12_LOS_LEVEL_9);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR8,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR8) |
		IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1 | IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB |
		IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB | IOMUXC_GPR8_PCS_TX_SWING_FULL |
		IOMUXC_GPR8_PCS_TX_SWING_LOW);
}

void
imxiomuxc_pcie_refclk(int enable)
{
	struct imxiomuxc_softc *sc = imxiomuxc_sc;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) & ~IOMUXC_GPR1_REF_SSP_EN);

	if (enable)
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) | IOMUXC_GPR1_REF_SSP_EN);
}

void
imxiomuxc_pcie_test_powerdown(int enable)
{
	struct imxiomuxc_softc *sc = imxiomuxc_sc;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) & ~IOMUXC_GPR1_TEST_POWERDOWN);

	if (enable)
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) | IOMUXC_GPR1_TEST_POWERDOWN);
}

void
imxiomuxc_enable_i2c(int x)
{
	struct imxiomuxc_softc *sc = imxiomuxc_sc;

	/* let's just use EIM for those */
	switch (x) {
		case 0:
			/* scl in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA21, IOMUX_CONFIG_SION | 6);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C1_SCL_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA21, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			/* sda in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA28, IOMUX_CONFIG_SION | 1);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C1_SDA_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA28, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			break;
		case 1:
			/* scl in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_EB2, IOMUX_CONFIG_SION | 6);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C2_SCL_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_EB2, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			/* sda in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA16, IOMUX_CONFIG_SION | 6);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C2_SDA_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA16, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			break;
		case 2:
			/* scl in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA17, IOMUX_CONFIG_SION | 6);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C3_SCL_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA17, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			/* sda in select */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA18, IOMUX_CONFIG_SION | 6);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C3_SDA_IN_SELECT_INPUT, 0);
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA18, IOMUXC_IMX6Q_I2C_PAD_CTRL);
			break;
	}
}


code:
/* $OpenBSD: imxiomuxcvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
/*
 * Copyright (c) 2013 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 IMXIOMUXCVAR_H
#define IMXIOMUXCVAR_H

void imxiomuxc_enable_sata(void);
void imxiomuxc_enable_i2c(int);
void imxiomuxc_enable_pcie(void);
void imxiomuxc_pcie_refclk(int);
void imxiomuxc_pcie_test_powerdown(int);

#endif /* IMXIOMUXCVAR_H */


code:
/* $OpenBSD: imxocotp.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
/*
 * Copyright (c) 2012-2013 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/imx/imxocotpvar.h>

/* registers */
#define OCOTP_MAC0	0x620
#define OCOTP_MAC1	0x630

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

struct imxocotp_softc *imxocotp_sc;

void imxocotp_attach(struct device *parent, struct device *self, void *args);

struct cfattach imxocotp_ca = {
	sizeof (struct imxocotp_softc), NULL, imxocotp_attach
};

struct cfdriver imxocotp_cd = {
	NULL, "imxocotp", DV_DULL
};

void
imxocotp_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct imxocotp_softc *sc = (struct imxocotp_softc *) self;

	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("imxocotp_attach: bus_space_map failed!");

	printf("\n");
	imxocotp_sc = sc;
}

void
imxocotp_get_ethernet_address(u_int8_t* mac)
{
	uint32_t value;

	value = bus_space_read_4(imxocotp_sc->sc_iot, imxocotp_sc->sc_ioh, OCOTP_MAC0);
	mac[5] = value & 0xff;
	mac[4] = (value >> 8) & 0xff;
	mac[3] = (value >> 16) & 0xff;
	mac[2] = (value >> 24) & 0xff;
	value = bus_space_read_4(imxocotp_sc->sc_iot, imxocotp_sc->sc_ioh, OCOTP_MAC1);
	mac[1] = value & 0xff;
	mac[0] = (value >> 8) & 0xff;
}


code:
/* $OpenBSD: imxocotpvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
/*
 * Copyright (c) 2012-2013 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.
 */

void imxocotp_get_ethernet_address(u_int8_t* mac);


code:
/* $OpenBSD: imxuart.c,v 1.3 2015/05/12 02:49:48 jsg Exp $ */
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.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/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/imx/imxuartreg.h>
#include <armv7/imx/imxuartvar.h>
#include <armv7/armv7/armv7var.h>
#include <armv7/imx/imxccmvar.h>

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

struct imxuart_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

	u_int8_t	sc_initialize;
	u_int8_t	sc_cua;
	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
#define IMXUART_IBUFSIZE 128
#define IMXUART_IHIGHWATER 100
	u_int16_t		sc_ibufs[2][IMXUART_IBUFSIZE];
};

int     imxuartprobe(struct device *parent, void *self, void *aux);
void    imxuartattach(struct device *parent, struct device *self, void *aux);

void imxuartcnprobe(struct consdev *cp);
void imxuartcnprobe(struct consdev *cp);
void imxuartcninit(struct consdev *cp);
int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
    tcflag_t cflag);
int imxuartcngetc(dev_t dev);
void imxuartcnputc(dev_t dev, int c);
void imxuartcnpollc(dev_t dev, int on);
int  imxuart_param(struct tty *tp, struct termios *t);
void imxuart_start(struct tty *);
void imxuart_pwroff(struct imxuart_softc *sc);
void imxuart_diag(void *arg);
void imxuart_raisedtr(void *arg);
void imxuart_softint(void *arg);
struct imxuart_softc *imxuart_sc(dev_t dev);

int imxuart_intr(void *);

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

struct cfdriver imxuart_cd = {
	NULL, "imxuart", DV_TTY
};

struct cfattach imxuart_ca = {
	sizeof(struct imxuart_softc), imxuartprobe, imxuartattach
};

bus_space_tag_t	imxuartconsiot;
bus_space_handle_t imxuartconsioh;
bus_addr_t	imxuartconsaddr;
tcflag_t	imxuartconscflag = TTYDEF_CFLAG;
int		imxuartdefaultrate = B115200;

int
imxuartprobe(struct device *parent, void *self, void *aux)
{
	return 1;
}

struct cdevsw imxuartdev =
	cdev_tty_init(3/*XXX NIMXUART */ ,imxuart);		/* 12: serial port */

void
imxuartattach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct imxuart_softc *sc = (struct imxuart_softc *) self;

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

	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("imxuartattach: bus_space_map failed!");

	if (aa->aa_dev->mem[0].addr == imxuartconsaddr)
		printf(" console");

	timeout_set(&sc->sc_diag_tmo, imxuart_diag, sc);
	timeout_set(&sc->sc_dtr_tmo, imxuart_raisedtr, sc);
	sc->sc_si = softintr_establish(IPL_TTY, imxuart_softint, sc);

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

	printf("\n");
}

int
imxuart_intr(void *arg)
{
	struct imxuart_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 sr1;
	u_int16_t *p;
	u_int16_t c;

	sr1 = bus_space_read_2(iot, ioh, IMXUART_USR1);
	if (ISSET(sr1, IMXUART_SR1_TRDY) && 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 (sc->sc_tty == NULL)
		return(0);

	if(!ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR))
		return 0;

	p = sc->sc_ibufp;

	while(ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) {
		c = bus_space_read_1(iot, ioh, IMXUART_URXD);
		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_2(iot, ioh, IMXUART_UCR3,
				    sc->sc_ucr3);
			}

		}
		/* XXX - msr stuff ? */
	}
	sc->sc_ibufp = p;

	softintr_schedule(sc->sc_si);

	return 1;
}

int
imxuart_param(struct tty *tp, struct termios *t)
{
	struct imxuart_softc *sc = imxuart_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_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);

	if (ISSET(t->c_cflag, PARENB)) {
		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
		bus_space_write_2(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, "imxuartprm", 0);
			--sc->sc_halt;
			if (error) {
				imxuart_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 */

	imxuart_start(tp);

	return 0;
}

void
imxuart_start(struct tty *tp)
{
        struct imxuart_softc *sc = imxuart_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)) {
		splx(s);
		return;
	}
	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
		goto stopped;
#ifdef DAMNFUCKSHIT
	/* clear to send (IE the RTS pin on this shit) is not directly \
	 * readable - skip check for now
	 */
	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, IMXUART_CTS))
		goto stopped;
#endif
	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);
	}
	SET(tp->t_state, TS_BUSY);

	if (!ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
		SET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
		bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
	}

	{
		u_char buf[32];
		int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
		int i;
		for (i = 0; i < n; i++)
			bus_space_write_1(iot, ioh, IMXUART_UTXD, buf[i]);
	}
	splx(s);
	return;
stopped:
	if (ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
		CLR(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
		bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
	}
	splx(s);
}

void
imxuart_pwroff(struct imxuart_softc *sc)
{
}

void
imxuart_diag(void *arg)
{
	struct imxuart_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
imxuart_raisedtr(void *arg)
{
	struct imxuart_softc *sc = arg;

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

void
imxuart_softint(void *arg)
{
	struct imxuart_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 + IMXUART_IHIGHWATER;
	sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;

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

	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
imxuartopen(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct imxuart_softc *sc;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	struct tty *tp;
	int s;
	int error = 0;

	if (unit >= imxuart_cd.cd_ndevs)
		return ENXIO;
	sc = imxuart_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 = imxuart_start;
	tp->t_param = imxuart_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 = imxuartconscflag;
		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 = imxuartdefaultrate;

		s = spltty();

		sc->sc_initialize = 1;
		imxuart_param(tp, &tp->t_termios);
		ttsetwater(tp);
		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
		sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
		sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;

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

		sc->sc_ucr1 = bus_space_read_2(iot, ioh, IMXUART_UCR1);
		sc->sc_ucr2 = bus_space_read_2(iot, ioh, IMXUART_UCR2);
		sc->sc_ucr3 = bus_space_read_2(iot, ioh, IMXUART_UCR3);
		sc->sc_ucr4 = bus_space_read_2(iot, ioh, IMXUART_UCR4);

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

		bus_space_write_2(iot, ioh, IMXUART_UBIR,
		    (imxuartdefaultrate / 100) - 1);

		/* formula: clk / (rfdiv * 1600) */
		bus_space_write_2(iot, ioh, IMXUART_UBMR,
		    (imxccm_get_uartclk() * 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_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
		bus_space_write_2(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_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);

		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))
						imxuart_pwroff(sc);
					splx(s);
					return error;
				}
			}
		}
	}
	splx(s);
	return (*linesw[tp->t_line].l_open)(dev,tp,p);
}

int
imxuartclose(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct imxuart_softc *sc = imxuart_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_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
		timeout_add(&sc->sc_dtr_tmo, hz * 2);
	} else {
		/* no one else waiting; turn off the uart */
		imxuart_pwroff(sc);
	}
	CLR(tp->t_state, TS_BUSY | TS_FLUSH);

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

	return 0;
}

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

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

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

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

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

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

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

	sc = imxuart_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:
#if 0
		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
#endif
		break;

	case TIOCCDTR:
#if 0
		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
#endif
		break;

	case TIOCMSET:
#if 0
		(void) clmctl(dev, *(int *) data, DMSET);
#endif
		break;

	case TIOCMBIS:
#if 0
		(void) clmctl(dev, *(int *) data, DMBIS);
#endif
		break;

	case TIOCMBIC:
#if 0
		(void) clmctl(dev, *(int *) data, DMBIC);
#endif
		break;

        case TIOCMGET:
#if 0
		*(int *)data = clmctl(dev, 0, DMGET);
#endif
		break;

	case TIOCGFLAGS:
#if 0
		*(int *)data = cl->cl_swflags;
#endif
		break;

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

#if 0
		cl->cl_swflags = *(int *)data;
		cl->cl_swflags &= /* only allow valid flags */
		    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
#endif
		break;
	default:
		return (ENOTTY);
	}

	return 0;
}

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

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

struct imxuart_softc *
imxuart_sc(dev_t dev)
{
	int unit;
	struct imxuart_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= imxuart_cd.cd_ndevs)
		return NULL;
	sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
	return sc;
}

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

void
imxuartcninit(struct consdev *cp)
{
}

int
imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
{
	static struct consdev imxuartcons = {
		NULL, NULL, imxuartcngetc, imxuartcnputc, imxuartcnpollc, NULL,
		NODEV, CN_MIDPRI
	};

	if (bus_space_map(iot, iobase, IMXUART_SPACE, 0, &imxuartconsioh))
			return ENOMEM;

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

	imxuartconsiot = iot;
	imxuartconsaddr = iobase;
	imxuartconscflag = cflag;

	// XXXX: Overwrites some sensitive bits, recheck later.
	/*
	bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR1,
	    IMXUART_CR1_EN);
	bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR2,
	    IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
	*/

	return 0;
}

int
imxuartcngetc(dev_t dev)
{
	int c;
	int s;
	s = splhigh();
	while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
	    IMXUART_SR2_RDR) == 0)
		;
	c = bus_space_read_1(imxuartconsiot, imxuartconsioh, IMXUART_URXD);
	splx(s);
	return c;
}

void
imxuartcnputc(dev_t dev, int c)
{
	int s;
	s = splhigh();
	bus_space_write_1(imxuartconsiot, imxuartconsioh, IMXUART_UTXD, (uint8_t)c);
	while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
	    IMXUART_SR2_TXDC) == 0)
		;
	splx(s);
}

void
imxuartcnpollc(dev_t dev, int on)
{
}


code:
/* $OpenBSD: imxuartreg.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.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.
 */

#define		IMXUART_URXD			0x000
#define		IMXUART_RX_ERR			0x4000
#define		IMXUART_RX_OVERRUN		0x2000
#define		IMXUART_RX_FRMERR		0x1000
#define		IMXUART_RX_BRK			0x0800
#define		IMXUART_RX_PRERR		0x0400
#define		IMXUART_RX_PRERR_SH		10
#define		IMXUART_UTXD			0x040
#define		IMXUART_UCR1			0x080
#define		IMXUART_CR1_ADEN		0x8000
#define		IMXUART_CR1_ADBR		0x4000
#define		IMXUART_CR1_TRDYEN		0x2000
#define		IMXUART_CR1_IDEN		0x1000
#define		IMXUART_CR1_ICD			0xc000
#define		IMXUART_CR1_RRDYEN		0x0200
#define		IMXUART_CR1_RXDMAEN		0x0100
#define		IMXUART_CR1_IREN		0x0080
#define		IMXUART_CR1_TXMPTYEN		0x0040
#define		IMXUART_CR1_RTSDEN		0x0020
#define		IMXUART_CR1_SNDBRK		0x0010
#define		IMXUART_CR1_TXDMAEN		0x0008
#define		IMXUART_CR1_ATDMAEN		0x0004
#define		IMXUART_CR1_DOZE		0x0002
#define		IMXUART_CR1_EN			0x0001
#define		IMXUART_UCR2			0x084
#define		IMXUART_CR2_ESCI		0x8000
#define		IMXUART_CR2_IRTS		0x4000
#define		IMXUART_CR2_CTSC		0x2000
#define		IMXUART_CR2_CTS			0x1000
#define		IMXUART_CR2_ESCEN		0x0800
#define		IMXUART_CR2_RTEC		0x0600
#define		IMXUART_CR2_PREN		0x0100
#define		IMXUART_CR2_PROE		0x0080
#define		IMXUART_CR2_STPB		0x0040
#define		IMXUART_CR2_WS			0x0020
#define		IMXUART_CR2_RTSEN		0x0010
#define		IMXUART_CR2_ATEN		0x0008
#define		IMXUART_CR2_TXEN		0x0004
#define		IMXUART_CR2_RXEN		0x0002
#define		IMXUART_CR2_SRTS		0x0001
#define		IMXUART_UCR3			0x088
#define		IMXUART_CR3_DPEC		0xc000
#define		IMXUART_CR3_DTREN		0x2000
#define		IMXUART_CR3_PARERREN		0x1000
#define		IMXUART_CR3_FRAERREN		0x0800
#define		IMXUART_CR3_DSR			0x0400
#define		IMXUART_CR3_DCD			0x0200
#define		IMXUART_CR3_RI			0x0100
#define		IMXUART_CR3_ADNIMP		0x0080
#define		IMXUART_CR3_RXDSEN		0x0040
#define		IMXUART_CR3_AIRINTEN		0x0020
#define		IMXUART_CR3_AWAKEN		0x0010
#define		IMXUART_CR3_DTRDEN		0x0008
#define		IMXUART_CR3_RXDMUXSEL		0x0004
#define		IMXUART_CR3_INVT		0x0002
#define		IMXUART_CR3_ACIEN		0x0001
#define		IMXUART_UCR4			0x08c
#define		IMXUART_CR4_CSTL		0xfc00
#define		IMXUART_CR4_INVR		0x0200
#define		IMXUART_CR4_ENIRI		0x0100
#define		IMXUART_CR4_WKEN		0x0080
#define		IMXUART_CR4_IDDMAEN		0x0040
#define		IMXUART_CR4_IRSC		0x0020
#define		IMXUART_CR4_LPBYP		0x0010
#define		IMXUART_CR4_TCEN		0x0008
#define		IMXUART_CR4_BKEN		0x0004
#define		IMXUART_CR4_OREN		0x0002
#define		IMXUART_CR4_DREN		0x0001
#define		IMXUART_UFCR			0x090
#define		IMXUART_FCR_TXTL_SH		10
#define		IMXUART_FCR_TXTL_M		0x3f
#define		IMXUART_FCR_RFDIV_SH		7
#define		IMXUART_FCR_RFDIV_M		0x07
#define		IMXUART_FCR_RXTL_SH		0
#define		IMXUART_FCR_RXTL_M		0x3f
#define		IMXUART_USR1			0x094
#define		IMXUART_SR1_PARITYERR		0x8000
#define		IMXUART_SR1_RTSS		0x4000
#define		IMXUART_SR1_TRDY		0x2000
#define		IMXUART_SR1_RTSD		0x1000
#define		IMXUART_SR1_ESCF		0x0800
#define		IMXUART_SR1_FRAMERR		0x0400
#define		IMXUART_SR1_RRDY		0x0200
#define		IMXUART_SR1_AGTIM		0x0100
#define		IMXUART_SR1_DTRD		0x0080
#define		IMXUART_SR1_RXDS		0x0040
#define		IMXUART_SR1_AIRINT		0x0020
#define		IMXUART_SR1_AWAKE		0x0010
#define		IMXUART_USR2			0x098
#define		IMXUART_SR2_ADET		0x8000
#define		IMXUART_SR2_TXFE		0x4000
#define		IMXUART_SR2_DTRF		0x2000
#define		IMXUART_SR2_IDLE		0x1000
#define		IMXUART_SR2_ACST		0x0800
#define		IMXUART_SR2_RIDELT		0x0400
#define		IMXUART_SR2_RIIN		0x0200
#define		IMXUART_SR2_IRINT		0x0100
#define		IMXUART_SR2_WAKE		0x0080
#define		IMXUART_SR2_DCDELT		0x0040
#define		IMXUART_SR2_DCDIN		0x0020
#define		IMXUART_SR2_RTSF		0x0010
#define		IMXUART_SR2_TXDC		0x0008
#define		IMXUART_SR2_BRCD		0x0004
#define		IMXUART_SR2_ORE			0x0002
#define		IMXUART_SR2_RDR			0x0001
#define		IMXUART_UESC			0x09c
#define		IMXUART_UTIM			0x0a0
#define		IMXUART_UBIR			0x0a4
#define		IMXUART_UBMR			0x0a8
#define		IMXUART_UBRC			0x0ac
#define		IMXUART_ONEMS			0x0b0
#define		IMXUART_UTS			0x0b4
#define		IMXUART_SPACE			0x0c0


code:
/* $OpenBSD: imxuartvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.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.
 */

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


code:
/*	$OpenBSD: _float.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/

#include <arm/_float.h>


code:
/* 	$OpenBSD: _types.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/
/*	$NetBSD: types.h,v 1.4 2002/02/28 03:17:26 simonb Exp $	*/

#ifndef _MACHINE__TYPES_H_
#define	_MACHINE__TYPES_H_

#include <arm/_types.h>

#endif /* _MACHINE__TYPES_H_ */


code:
/*	$OpenBSD: apmvar.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/
#include <arm/apmvar.h>


code:
/*	$OpenBSD: atomic.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/

/* Public Domain */

#ifndef _MACHINE_ATOMIC_H_
#define _MACHINE_ATOMIC_H_

#include <arm/atomic.h>

#endif /* _MACHINE_ATOMIC_H_ */


code:
/*	$OpenBSD: bootconfig.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/
/*	$NetBSD: bootconfig.h,v 1.2 2001/06/21 22:08:28 chris Exp $	*/

/*
 * Copyright (c) 1994 Mark Brinicombe.
 * Copyright (c) 1994 Brini.
 * All rights reserved.
 *
 * This code is derived from software written for Brini by Mark Brinicombe
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Mark Brinicombe
 *	for the NetBSD Project.
 * 4. The name of the company nor the name of the author may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * boot configuration structures
 *
 * Created      : 12/09/94
 *
 * Based on kate/boot/bootconfig.h
 */

#if defined(_KERNEL) || defined(_STANDALONE)

typedef struct _PhysMem {
	u_int address;
	u_int pages;
} PhysMem;

#define	DRAM_BLOCKS	2
#define	MAX_BOOT_STRING 255

typedef struct _BootConfig {
	PhysMem dram[DRAM_BLOCKS];
	u_int dramblocks;
	char bootstring[MAX_BOOT_STRING];
} BootConfig;

extern BootConfig bootconfig;

#endif	/* _KERNEL || _STANDALONE */
#if defined(_KERNEL)
extern char *boot_args;
extern char *boot_file;
#endif	/* _KERNEL */

/* End of bootconfig.h */


code:
/*	$OpenBSD: cdefs.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/

#include <arm/cdefs.h>


code:
/*	$OpenBSD: conf.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/
/*	$NetBSD: conf.h,v 1.8 2002/02/10 12:26:03 chris Exp $	*/

#ifndef _MACHINE_CONF_H_
#define	_MACHINE_CONF_H_

#include <sys/conf.h>

/*
 * BEAGLEBOARD specific device includes go in here
 */

/*#define	CONF_HAVE_GPIO*/

#include <arm/conf.h>

#endif	/* _MACHINE_CONF_H_ */


code:
/*	$OpenBSD: db_machdep.h,v 1.1 2013/09/04 14:38:26 patrick Exp $	*/
/*	$NetBSD: db_machdep.h,v 1.3 2001/11/25 15:55:55 thorpej Exp $	*/

#include <arm/db_machdep.h>


code:
/*	$OpenBSD: disklabel.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/

#include <arm/disklabel.h>


code:
/*	$OpenBSD: elf_abi.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/

#include <arm/elf_abi.h>


code:
/*	$OpenBSD: endian.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/*	$NetBSD: endian.h,v 1.3 2001/11/25 15:55:56 thorpej Exp $	*/

#include <arm/endian.h>


code:
/*	$OpenBSD: exec.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/* public domain */
#include <arm/exec.h>


code:
/*	$OpenBSD: fenv.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/* public domain */
#include <arm/fenv.h>


code:
/*	$OpenBSD: ieeefp.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/*	$NetBSD: ieeefp.h,v 1.3 2001/11/25 15:55:56 thorpej Exp $	*/

#include <arm/ieeefp.h>


code:
/*	$OpenBSD: intr.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/*	$NetBSD: intr.h,v 1.12 2003/06/16 20:00:59 thorpej Exp $	*/

/*
 * Copyright (c) 2001, 2003 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed for the NetBSD Project by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef	_MACHINE_INTR_H_
#define	_MACHINE_INTR_H_

#ifdef _KERNEL

/* Interrupt priority "levels". */
#define	IPL_NONE	0	/* nothing */
#define	IPL_SOFT	1	/* generic software interrupts */
#define	IPL_SOFTCLOCK	2	/* software clock interrupt */
#define	IPL_SOFTNET	3	/* software network interrupt */
#define	IPL_SOFTTTY	4	/* software serial interrupt */
#define	IPL_BIO		5	/* block I/O */
#define	IPL_NET		6	/* network */
#define	IPL_TTY		7	/* terminals */
#define	IPL_VM		8	/* memory allocation */
#define	IPL_AUDIO	9	/* audio device */
#define	IPL_CLOCK	10	/* clock interrupt */
#define	IPL_STATCLOCK	11	/* statistics clock interrupt */
#define	IPL_SCHED	12	/* everything */
#define	IPL_HIGH	12	/* everything */

#define	NIPL		13

/* Interrupt priority "flags". */
#define	IPL_MPSAFE	0	/* no "mpsafe" interrupts */

/* Interrupt sharing types. */
#define	IST_NONE	0	/* none */
#define	IST_PULSE	1	/* pulsed */
#define	IST_EDGE	2	/* edge-triggered */
#define	IST_LEVEL	3	/* level-triggered */

#define IST_LEVEL_LOW	 IST_LEVEL
#define IST_LEVEL_HIGH   4
#define IST_EDGE_FALLING IST_EDGE
#define IST_EDGE_RISING  5
#define IST_EDGE_BOTH    6

#ifndef _LOCORE
#include <sys/device.h>
#include <sys/queue.h>

int     splraise(int);
int     spllower(int);
void    splx(int);

void	arm_do_pending_intr(int);
void	arm_set_intr_handler(int (*raise)(int), int (*lower)(int),
	void (*x)(int), void (*setipl)(int),
	void *(*intr_establish)(int irqno, int level, int (*func)(void *),
	    void *cookie, char *name),
	void (*intr_disestablish)(void *cookie),
	const char *(*intr_string)(void *cookie),
	void (*intr_handle)(void *));

struct arm_intr_func {
	int (*raise)(int);
	int (*lower)(int);
	void (*x)(int);
	void (*setipl)(int);
	void *(*intr_establish)(int irqno, int level, int (*func)(void *),
	    void *cookie, char *name);
	void (*intr_disestablish)(void *cookie);
	const char *(*intr_string)(void *cookie);
};

extern struct arm_intr_func arm_intr_func;

#define splraise(cpl)		(arm_intr_func.raise(cpl))
#define _splraise(cpl)		(arm_intr_func.raise(cpl))
#define spllower(cpl)		(arm_intr_func.lower(cpl))
#define splx(cpl)		(arm_intr_func.x(cpl))

#define	splhigh()	splraise(IPL_HIGH)
#define	splsoft()	splraise(IPL_SOFT)
#define	splsoftclock()	splraise(IPL_SOFTCLOCK)
#define	splsoftnet()	splraise(IPL_SOFTNET)
#define	splbio()	splraise(IPL_BIO)
#define	splnet()	splraise(IPL_NET)
#define	spltty()	splraise(IPL_TTY)
#define	splvm()		splraise(IPL_VM)
#define	splaudio()	splraise(IPL_AUDIO)
#define	splclock()	splraise(IPL_CLOCK)
#define	splstatclock()	splraise(IPL_STATCLOCK)

#define	spl0()		spllower(IPL_NONE)

#define	splsched()	splhigh()
#define	spllock()	splhigh()

void arm_init_smask(void); /* XXX */
extern uint32_t arm_smask[NIPL];
void arm_setsoftintr(int si);

#define _setsoftintr arm_setsoftintr

#include <arm/softintr.h>

void *arm_intr_establish(int irqno, int level, int (*func)(void *),
    void *cookie, char *name);
void arm_intr_disestablish(void *cookie);
const char *arm_intr_string(void *cookie);

/* XXX - this is probably the wrong location for this */
void arm_clock_register(void (*)(void), void (*)(u_int), void (*)(int),
    void (*)(void));

#ifdef DIAGNOSTIC
/*
 * Although this function is implemented in MI code, it must be in this MD
 * header because we don't want this header to include MI includes.
 */
void splassert_fail(int, int, const char *);
extern int splassert_ctl;
void arm_splassert_check(int, const char *);
#define splassert(__wantipl) do {                               \
	if (splassert_ctl > 0) {                                \
		arm_splassert_check(__wantipl, __func__);    \
	}                                                       \
} while (0)
#define splsoftassert(wantipl) splassert(wantipl)
#else
#define splassert(wantipl)      do { /* nothing */ } while (0)
#define splsoftassert(wantipl)  do { /* nothing */ } while (0)
#endif

#endif /* ! _LOCORE */

#define ARM_IRQ_HANDLER arm_intr

#endif /* _KERNEL */

#endif	/* _MACHINE_INTR_H_ */


code:
/* 	$OpenBSD: isa_machdep.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/* $NetBSD: isa_machdep.h,v 1.4 2002/01/07 22:58:08 chris Exp $ */

#ifndef _MACHINE_ISA_MACHDEP_H_
#define _MACHINE_ISA_MACHDEP_H_
#include <arm/isa_machdep.h>

#ifdef _KERNEL
#define ISA_FOOTBRIDGE_IRQ IRQ_IN_L2
void	isa_footbridge_init(u_int, u_int);
#endif /* _KERNEL */

#endif /* _MACHINE_ISA_MACHDEP_H_ */


code:
/*	$OpenBSD: limits.h,v 1.1 2013/09/04 14:38:27 patrick Exp $	*/
/*	$NetBSD: limits.h,v 1.3 2001/11/25 15:55:57 thorpej Exp $	*/

#include <arm/limits.h>


code:
/*	$OpenBSD: loadfile_machdep.h,v 1.3 2015/07/17 20:44:38 miod Exp $	*/
/*	$NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $	*/

/*-
 * Copyright (c) 1999 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Christos Zoulas.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define BOOT_ELF
#define ELFSIZE 32

#define LOAD_KERNEL		LOAD_ALL
#define COUNT_KERNEL		COUNT_ALL

#define LOADADDR(a)		((((u_long)(a)) + offset)&0xfffffff)
#define ALIGNENTRY(a)		((u_long)(a))
#define READ(f, b, c)		read((f), (void *)LOADADDR(b), (c))
#define BCOPY(s, d, c)		memcpy((void *)LOADADDR(d), (void *)(s), (c))
#define BZERO(d, c)		memset((void *)LOADADDR(d), 0, (c))
#define	WARN(a)			(void)(printf a, \
				    printf((errno ? ": %s\n" : "\n"), \
				    strerror(errno)))
#define PROGRESS(a)		(void) printf a
#define ALLOC(a)		alloc(a)
#define FREE(a, b)		free(a, b)

void run_loadfile(u_long *, int);