initial commit, pull in sys/arch/armv7/omap master
authorkremlin <ian@kremlin.cc>
Wed, 4 May 2016 04:49:38 +0000 (00:49 -0400)
committerkremlin <ian@kremlin.cc>
Wed, 4 May 2016 04:49:38 +0000 (00:49 -0400)
36 files changed:
am335x.c [new file with mode: 0644]
am335x_cm_padconf.c [new file with mode: 0644]
am335x_prcmreg.h [new file with mode: 0644]
dmtimer.c [new file with mode: 0644]
edma.c [new file with mode: 0644]
edmavar.h [new file with mode: 0644]
files.omap [new file with mode: 0644]
gptimer.c [new file with mode: 0644]
if_cpsw.c [new file with mode: 0644]
if_cpswreg.h [new file with mode: 0644]
intc.c [new file with mode: 0644]
intc.h [new file with mode: 0644]
omap.c [new file with mode: 0644]
omap3.c [new file with mode: 0644]
omap3_prcmreg.h [new file with mode: 0644]
omap4.c [new file with mode: 0644]
omap4_prcmreg.h [new file with mode: 0644]
omap_com.c [new file with mode: 0644]
omap_machdep.c [new file with mode: 0644]
omapid.c [new file with mode: 0644]
omdisplay.c [new file with mode: 0644]
omdog.c [new file with mode: 0644]
omehci.c [new file with mode: 0644]
omehcivar.h [new file with mode: 0644]
omgpio.c [new file with mode: 0644]
omgpiovar.h [new file with mode: 0644]
ommmc.c [new file with mode: 0644]
omohci.c [new file with mode: 0644]
omusbtll.c [new file with mode: 0644]
prcm.c [new file with mode: 0644]
prcmvar.h [new file with mode: 0644]
sitara_cm.c [new file with mode: 0644]
sitara_cm.h [new file with mode: 0644]
sitara_cmreg.h [new file with mode: 0644]
ti_iic.c [new file with mode: 0644]
ti_iicreg.h [new file with mode: 0644]

diff --git a/am335x.c b/am335x.c
new file mode 100644 (file)
index 0000000..05fe86e
--- /dev/null
+++ b/am335x.c
@@ -0,0 +1,264 @@
+/* $OpenBSD: am335x.c,v 1.7 2014/03/18 07:34:17 syl Exp $ */
+
+/*
+ * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
+ * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <machine/bus.h>
+
+#include <armv7/armv7/armv7var.h>
+
+#define PRCM_SIZE      0x2000
+#define PRCM_ADDR      0x44E00000
+
+#define SCM_SIZE       0x2000
+#define SCM_ADDR       0x44E10000
+
+#define INTC_SIZE      0x300
+#define INTC_ADDR      0x48200000
+
+#define DMTIMERx_SIZE  0x80
+#define DMTIMER0_ADDR  0x44E05000
+#define DMTIMER1_ADDR  0x44E31000      /* 1MS */
+#define DMTIMER2_ADDR  0x48040000
+#define DMTIMER3_ADDR  0x48042000
+#define DMTIMER4_ADDR  0x48044000
+#define DMTIMER5_ADDR  0x48046000
+#define DMTIMER6_ADDR  0x48048000
+#define DMTIMER7_ADDR  0x4804A000
+#define DMTIMER0_IRQ   66
+#define DMTIMER1_IRQ   67
+#define DMTIMER2_IRQ   68
+#define DMTIMER3_IRQ   69
+#define DMTIMER4_IRQ   92
+#define DMTIMER5_IRQ   93
+#define DMTIMER6_IRQ   94
+#define DMTIMER7_IRQ   95
+
+#define WD_SIZE                0x80
+#define WD_ADDR                0x44E35000
+#define WD_IRQ         91
+
+#define GPIOx_SIZE     0x200
+#define GPIO0_ADDR     0x44E07000
+#define GPIO1_ADDR     0x4804C000
+#define GPIO2_ADDR     0x481AC000
+#define GPIO3_ADDR     0x481AE000
+#define GPIO0_IRQ      96
+#define GPIO1_IRQ      98
+#define GPIO2_IRQ      32
+#define GPIO3_IRQ      62
+
+#define TPCC_SIZE      0x100000
+#define TPCC_ADDR      0x49000000
+#define TPTC0_ADDR     0x49800000
+#define TPTC1_ADDR     0x49900000
+#define TPTC2_ADDR     0x49a00000
+#define EDMACOMP_IRQ   12
+#define EDMAMPERR_IRQ  13
+#define EDMAERR_IRQ    14
+
+#define UARTx_SIZE     0x90
+#define UART0_ADDR     0x44E09000
+#define UART1_ADDR     0x48022000
+#define UART2_ADDR     0x48024000
+#define UART3_ADDR     0x481A6000
+#define UART4_ADDR     0x481A8000
+#define UART5_ADDR     0x481AA000
+#define UART0_IRQ      72
+#define UART1_IRQ      73
+#define UART2_IRQ      74
+#define UART3_IRQ      44
+#define UART4_IRQ      45
+#define UART5_IRQ      46
+
+#define HSMMCx_SIZE    0x200
+#define HSMMC0_ADDR    0x48060100
+#define HSMMC1_ADDR    0x481d8100
+#define HSMMC0_IRQ     64
+#define HSMMC1_IRQ     28
+
+#define CPSW_SIZE      0x4000
+#define CPSW_ADDR      0x4A100000
+#define CPSW_IRQ       40
+
+#define IICx_SIZE      0x1000
+#define IIC0_ADDR      0x44e0b000
+#define IIC1_ADDR      0x4802a000
+#define IIC2_ADDR      0x4819c000
+#define IIC0_IRQ       70
+#define IIC1_IRQ       71
+#define IIC2_IRQ       30
+
+struct armv7_dev am335x_devs[] = {
+
+       /*
+        * Power, Reset and Clock Manager
+        */
+
+       { .name = "prcm",
+         .unit = 0,
+         .mem = { { PRCM_ADDR, PRCM_SIZE } },
+       },
+
+       /*
+        * System Control Module
+        */
+
+       { .name = "sitaracm",
+         .unit = 0,
+         .mem = { { SCM_ADDR, SCM_SIZE } },
+       },
+
+       /*
+        * Interrupt Controller
+        */
+
+       { .name = "intc",
+         .unit = 0,
+         .mem = { { INTC_ADDR, INTC_SIZE } },
+       },
+
+       /*
+        * EDMA Controller
+        */
+       { .name = "edma",
+         .unit = 0,
+         .mem = { { TPCC_ADDR, TPCC_SIZE } },
+         .irq = { EDMACOMP_IRQ }
+       },
+
+       /*
+        * General Purpose Timers
+        */
+
+       { .name = "dmtimer",
+         .unit = 0,
+         .mem = { { DMTIMER2_ADDR, DMTIMERx_SIZE } },
+         .irq = { DMTIMER2_IRQ }
+       },
+
+       { .name = "dmtimer",
+         .unit = 1,
+         .mem = { { DMTIMER3_ADDR, DMTIMERx_SIZE } },
+         .irq = { DMTIMER3_IRQ }
+       },
+
+       /*
+        * Watchdog Timer
+        */
+
+       { .name = "omdog",
+         .unit = 0,
+         .mem = { { WD_ADDR, WD_SIZE } }
+       },
+
+       /*
+        * UART
+        */
+
+       { .name = "com",
+         .unit = 0,
+         .mem = { { UART0_ADDR, UARTx_SIZE } },
+         .irq = { UART0_IRQ }
+       },
+
+       /*
+        * GPIO 
+        */
+
+       { .name = "omgpio",
+         .unit = 0,
+         .mem = { { GPIO0_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO0_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 1,
+         .mem = { { GPIO1_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO1_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 2,
+         .mem = { { GPIO2_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO2_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 3,
+         .mem = { { GPIO3_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO3_IRQ }
+       },
+
+       /*
+        * IIC 
+        */
+
+       { .name = "tiiic",
+         .unit = 0,
+         .mem = { { IIC0_ADDR, IICx_SIZE } },
+         .irq = { IIC0_IRQ }
+       },
+
+       { .name = "tiiic",
+         .unit = 1,
+         .mem = { { IIC1_ADDR, IICx_SIZE } },
+         .irq = { IIC1_IRQ }
+       },
+
+       { .name = "tiiic",
+         .unit = 2,
+         .mem = { { IIC2_ADDR, IICx_SIZE } },
+         .irq = { IIC2_IRQ }
+       },
+
+       /*
+        * MMC
+        */
+
+       { .name = "ommmc",
+         .unit = 0,
+         .mem = { { HSMMC0_ADDR, HSMMCx_SIZE } },
+         .irq = { HSMMC0_IRQ }
+       },
+
+       { .name = "ommmc",
+         .unit = 1,
+         .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } },
+         .irq = { HSMMC1_IRQ }
+       },
+
+       /* cpsw Ethernet */
+       { .name = "cpsw",
+         .unit = 0,
+         .mem = { { CPSW_ADDR, CPSW_SIZE } },
+         .irq = { CPSW_IRQ }
+       },
+
+       /* Terminator */
+       { .name = NULL,
+         .unit = 0
+       }
+};
+
+void
+am335x_init(void)
+{
+       armv7_set_devs(am335x_devs);
+}
diff --git a/am335x_cm_padconf.c b/am335x_cm_padconf.c
new file mode 100644 (file)
index 0000000..3723b99
--- /dev/null
@@ -0,0 +1,350 @@
+/* $OpenBSD: am335x_cm_padconf.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */
+/* $NetBSD: am335x_cm_padconf.c,v 1.2 2013/05/06 18:53:40 rkujawa Exp $ */
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/gpio.h>
+#include <armv7/omap/sitara_cm.h>
+
+#define _PIN(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \
+       {       .reg_off = r, \
+               .gpio_pin = gp, \
+               .gpio_mode = gm, \
+               .ballname = b, \
+               .muxmodes[0] = m0, \
+               .muxmodes[1] = m1, \
+               .muxmodes[2] = m2, \
+               .muxmodes[3] = m3, \
+               .muxmodes[4] = m4, \
+               .muxmodes[5] = m5, \
+               .muxmodes[6] = m6, \
+               .muxmodes[7] = m7, \
+       }
+
+#define SLEWCTRL       (0x01 << 6) /* faster(0) or slower(1) slew rate. */
+#define RXACTIVE       (0x01 << 5) /* Input enable value for the Pad */
+#define PULLTYPESEL    (0x01 << 4) /* Pad pullup/pulldown type selection */
+#define PULLUDEN       (0x01 << 3) /* Pullup/pulldown disabled */
+
+#define PADCONF_OUTPUT                 (0)
+#define PADCONF_OUTPUT_PULLUP          (PULLTYPESEL)
+#define PADCONF_INPUT                  (RXACTIVE | PULLUDEN)
+#define PADCONF_INPUT_PULLUP           (RXACTIVE | PULLTYPESEL)
+#define PADCONF_INPUT_PULLDOWN         (RXACTIVE)
+#define PADCONF_INPUT_PULLUP_SLOW      (PADCONF_INPUT_PULLUP | SLEWCTRL)
+
+const struct sitara_cm_padstate ti_padstate_devmap[] = {
+       {"output",              PADCONF_OUTPUT },
+       {"output_pullup",       PADCONF_OUTPUT_PULLUP },
+       {"input",               PADCONF_INPUT },
+       {"input_pulldown",      PADCONF_INPUT_PULLDOWN },
+       {"input_pullup",        PADCONF_INPUT_PULLUP },
+       {"i2c",                 PADCONF_INPUT_PULLUP_SLOW },
+       { .state = NULL }
+};
+
+const struct sitara_cm_padconf ti_padconf_devmap[] = {
+       _PIN(0x800, "GPMC_AD0",         32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"),
+       _PIN(0x804, "GPMC_AD1",         33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"),
+       _PIN(0x808, "GPMC_AD2",         34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"),
+       _PIN(0x80C, "GPMC_AD3",         35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"),
+       _PIN(0x810, "GPMC_AD4",         36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"),
+       _PIN(0x814, "GPMC_AD5",         37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"),
+       _PIN(0x818, "GPMC_AD6",         38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"),
+       _PIN(0x81C, "GPMC_AD7",         39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"),
+       _PIN(0x820, "GPMC_AD8",         22, 7, "gpmc_ad8", "lcd_data23", "mmc1_dat0", "mmc2_dat4", "ehrpwm2A", NULL, NULL, "gpio0_22"),
+       _PIN(0x824, "GPMC_AD9",         23, 7, "gpmc_ad9", "lcd_data22", "mmc1_dat1", "mmc2_dat5", "ehrpwm2B", NULL, NULL, "gpio0_23"),
+       _PIN(0x828, "GPMC_AD10",        26, 7, "gpmc_ad10", "lcd_data21", "mmc1_dat2", "mmc2_dat6", "ehrpwm2_tripzone_in", NULL, NULL, "gpio0_26"),
+       _PIN(0x82C, "GPMC_AD11",        27, 7, "gpmc_ad11", "lcd_data20", "mmc1_dat3", "mmc2_dat7", "ehrpwm0_synco", NULL, NULL, "gpio0_27"),
+       _PIN(0x830, "GPMC_AD12",        44, 7, "gpmc_ad12", "lcd_data19", "mmc1_dat4", "mmc2_dat0", "eQEP2A_in", "pr1_mii0_txd2", "pr1_pru0_pru_r30_14", "gpio1_12"),
+       _PIN(0x834, "GPMC_AD13",        45, 7, "gpmc_ad13", "lcd_data18", "mmc1_dat5", "mmc2_dat1", "eQEP2B_in", "pr1_mii0_txd1", "pr1_pru0_pru_r30_15", "gpio1_13"),
+       _PIN(0x838, "GPMC_AD14",        46, 7, "gpmc_ad14", "lcd_data17", "mmc1_dat6", "mmc2_dat2", "eQEP2_index", "pr1_mii0_txd0", "pr1_pru0_pru_r31_14", "gpio1_14"),
+       _PIN(0x83C, "GPMC_AD15",        47, 7, "gpmc_ad15", "lcd_data16", "mmc1_dat7", "mmc2_dat3", "eQEP2_strobe", "pr1_ecap0_ecap_capin_apwm_o", "pr1_pru0_pru_r31_15", "gpio1_15"),
+       _PIN(0x840, "GPMC_A0",          48, 7, "gpmc_a0", "gmii2_txen", "rgmii2_tctl", "rmii2_txen", "gpmc_a16", "pr1_mii_mt1_clk", "ehrpwm1_tripzone_input", "gpio1_16"),
+       _PIN(0x844, "GPMC_A1",          49, 7, "gpmc_a1", "gmii2_rxdv", "rgmii2_rctl", "mmc2_dat0", "gpmc_a17", "pr1_mii1_txd3", "ehrpwm0_synco", "gpio1_17"),
+       _PIN(0x848, "GPMC_A2",          50, 7, "gpmc_a2", "gmii2_txd3", "rgmii2_td3", "mmc2_dat1", "gpmc_a18", "pr1_mii1_txd2", "ehrpwm1A", "gpio1_18"),
+       _PIN(0x84C, "GPMC_A3",          51, 7, "gpmc_a3", "gmii2_txd2", "rgmii2_td2", "mmc2_dat2", "gpmc_a19", "pr1_mii1_txd1", "ehrpwm1B", "gpio1_19"),
+       _PIN(0x850, "GPMC_A4",          52, 7, "gpmc_a4", "gmii2_txd1", "rgmii2_td1", "rmii2_tdx1", "gpmc_a20", "pr1_mii1_txd0", "eQEP1A_in", "gpio1_20"),
+       _PIN(0x854, "GPMC_A5",          53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"),
+       _PIN(0x858, "GPMC_A6",          54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"),
+       _PIN(0x85C, "GPMC_A7",          55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"),
+       _PIN(0x860, "GPMC_A8",          56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"),
+       _PIN(0x864, "GPMC_A9",          57, 7, "gmpc_a9", "gmii2_rxd2", "rgmii2_rd2", "mmc2_dat7 / rmii2_crs_dv", "gpmc_a25", "pr1_mii_mr1_clk", "mcasp0_fsx", "gpio1_25"),
+       _PIN(0x868, "GPMC_A10",         58, 7, "gmpc_a10", "gmii2_rxd1", "rgmii2_rd1", "rmii2_rxd1", "gpmc_a26", "pr1_mii1_rxdv", "mcasp0_arx0", "gpio1_26"),
+       _PIN(0x86C, "GPMC_A11",         59, 7, "gmpc_a11", "gmii2_rxd0", "rgmii2_rd0", "rmii2_rxd0", "gpmc_a27", "pr1_mii1_rxer", "mcasp0_axr1", "gpio1_27"),
+       _PIN(0x870, "GPMC_WAIT0",       30, 7, "gpmc_wait0", "gmii2_crs", "gpmc_csn4", "rmii2_crs_dv", "mmc1_sdcd", "pr1_mii1_col", "uart4_rxd", "gpio0_30"),
+       _PIN(0x874, "GPMC_WPn",         31, 7, "gpmc_wpn", "gmii2_rxerr", "gpmc_csn5", "rmii2_rxerr", "mmc2_sdcd", "pr1_mii1_txen", "uart4_txd", "gpio0_31"),
+       _PIN(0x878, "GPMC_BEn1",        60, 7, "gpmc_be1n", "gmii2_col", "gmpc_csn6","mmc2_dat3", "gpmc_dir", "pr1_mii1_rxlink", "mcasp0_aclkr", "gpio1_28"),
+       _PIN(0x87c, "GPMC_CSn0",        61, 7, "gpmc_csn0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio1_29"),
+       _PIN(0x880, "GPMC_CSn1",        62, 7, "gpmc_csn1", "gpmc_clk", "mmc1_clk", "pr1_edio_data_in6", "pr1_edio_data_out6", "pr1_pru1_pru_r30_12", "pr1_pru1_pru_r31_12", "gpio1_30"),
+       _PIN(0x884, "GPMC_CSn2",        63, 7, "gpmc_csn2", "gpmc_be1n", "mmc1_cmd", "pr1_edio_data_in7", "pr1_edio_data_out7", "pr1_pru1_pru_r30_13", "pr1_pru1_pru_r31_13", "gpio1_31"),
+       _PIN(0x888, "GPMC_CSn3",        64, 7, "gpmc_csn3", "gpmc_a3", "rmii2_crs_dv", "mmc2_cmd", "pr1_mii0_crs", "pr1_mdio_data", "EMU4", "gpio2_0"),
+       _PIN(0x88c, "GPMC_CLK",         65, 7, "gpmc_clk", "lcd_memory_clk", "gpmc_wait1", "mmc2_clk", "pr1_mii1_crs", "pr1_mdio_mdclk", "mcasp0_fsr", "gpio2_1"),
+       _PIN(0x890, "GPMC_ADVn_ALE",    66, 7, "gpmc_advn_ale", NULL, "timer4", NULL, NULL, NULL, NULL, "gpio2_2"),
+       _PIN(0x894, "GPMC_OEn_REn",     67, 7, "gpmc_oen_ren", NULL, "timer7", NULL, NULL, NULL, NULL, "gpio2_3"),
+       _PIN(0x898, "GPMC_WEn",         68, 7, "gpmc_wen", NULL, "timer6", NULL, NULL, NULL, NULL, "gpio2_4"),
+       _PIN(0x89c, "GPMC_BEn0_CLE",    67, 7, "gpmc_ben0_cle", NULL, "timer5", NULL, NULL, NULL, NULL, "gpio2_5"),
+       _PIN(0x8a0, "LCD_DATA0",        68, 7, "lcd_data0", "gpmc_a0", "pr1_mii_mt0_clk", "ehrpwm2A", NULL, "pr1_pru1_pru_r30_0", "pr1_pru1_pru_r31_0", "gpio2_6"),
+       _PIN(0x8a4, "LCD_DATA1",        69, 7, "lcd_data1", "gpmc_a1", "pr1_mii0_txen", "ehrpwm2B", NULL, "pr1_pru1_pru_r30_1", "pr1_pru1_pru_r31_1", "gpio2_7"),
+       _PIN(0x8a8, "LCD_DATA2",        70, 7, "lcd_data2", "gpmc_a2", "pr1_mii0_txd3", "ehrpwm2_tripzone_input", NULL, "pr1_pru1_pru_r30_2", "pr1_pru1_pru_r31_2", "gpio2_8"),
+       _PIN(0x8ac, "LCD_DATA3",        71, 7, "lcd_data3", "gpmc_a3", "pr1_mii0_txd2", "ehrpwm0_synco", NULL, "pr1_pru1_pru_r30_3", "pr1_pru1_pru_r31_3", "gpio2_9"),
+       _PIN(0x8b0, "LCD_DATA4",        72, 7, "lcd_data4", "gpmc_a4", "pr1_mii0_txd1", "eQEP2A_in", NULL, "pr1_pru1_pru_r30_4", "pr1_pru1_pru_r31_4", "gpio2_10"),
+       _PIN(0x8b4, "LCD_DATA5",        73, 7, "lcd_data5", "gpmc_a5", "pr1_mii0_txd0", "eQEP2B_in", NULL, "pr1_pru1_pru_r30_5", "pr1_pru1_pru_r31_5", "gpio2_11"),
+       _PIN(0x8b8, "LCD_DATA6",        74, 7, "lcd_data6", "gpmc_a6", "pr1_edio_data_in6", "eQEP2_index", "pr1_edio_data_out6", "pr1_pru1_pru_r30_6", "pr1_pru1_pru_r31_6", "gpio2_12"),
+       _PIN(0x8bc, "LCD_DATA7",        75, 7, "lcd_data7", "gpmc_a7", "pr1_edio_data_in7", "eQEP2_strobe", "pr1_edio_data_out7", "pr1_pru1_pru_r30_7", "pr1_pru1_pru_r31_7", "gpio2_13"),
+       _PIN(0x8c0, "LCD_DATA8",        76, 7, "lcd_data8", "gpmc_a12", "ehrpwm1_tripzone_input", "mcasp0_aclkx", "uart5_txd", "pr1_mii0_rxd3", "uart2_ctsn", "gpio2_14"),
+       _PIN(0x8c4, "LCD_DATA9",        76, 7, "lcd_data9", "gpmc_a13", "ehrpwm0_synco", "mcasp0_fsx", "uart5_rxd", "pr1_mii0_rxd2", "uart2_rtsn", "gpio2_15"),
+       _PIN(0x8c8, "LCD_DATA10",       77, 7, "lcd_data10", "gpmc_a14", "ehrpwm1A", "mcasp0_axr0", NULL, "pr1_mii0_rxd1", "uart3_ctsn", "gpio2_16"),
+       _PIN(0x8cc, "LCD_DATA11",       78, 7, "lcd_data11", "gpmc_a15", "ehrpwm1B", "mcasp0_ahclkr", "mcasp0_axr2", "pr1_mii0_rxd0", "uart3_rtsn", "gpio2_17"),
+       _PIN(0x8d0, "LCD_DATA12",       8, 7, "lcd_data12", "gpmc_a16", "eQEP1A_in", "mcasp0_aclkr", "mcasp0_axr2", "pr1_mii0_rxlink", "uart4_ctsn", "gpio0_8"),
+       _PIN(0x8d4, "LCD_DATA13",       9, 7, "lcd_data13", "gpmc_a17", "eQEP1B_in", "mcasp0_fsr", "mcasp0_axr3", "pr1_mii0_rxer", "uart4_rtsn", "gpio0_9"),
+       _PIN(0x8d8, "LCD_DATA14",       10, 7, "lcd_data14", "gpmc_a18", "eQEP1_index", "mcasp0_axr1", "uart5_rxd", "pr1_mii_mr0_clk", "uart5_ctsn", "gpio0_10"),
+       _PIN(0x8dc, "LCD_DATA15",       11, 7, "lcd_data15", "gpmc_a19", "eQEP1_strobe", "mcasp0_ahclkx", "mcasp0_axr3", "pr1_mii0_rxdv", "uart5_rtsn", "gpio0_11"),
+       _PIN(0x8e0, "LCD_VSYNC",        86, 7, "lcd_vsync", "gpmc_a8", "gpmc_a1", "pr1_edio_data_in2", "pr1_edio_data_out2", "pr1_pru1_pru_r30_8", "pr1_pru1_pru_r31_8", "gpio2_22"),
+       _PIN(0x8e4, "LCD_HSYNC",        87, 7, "lcd_hsync", "gmpc_a9", "gpmc_a2", "pr1_edio_data_in3", "pr1_edio_data_out3", "pr1_pru1_pru_r30_9", "pr1_pru1_pru_r31_9", "gpio2_23"),
+       _PIN(0x8e8, "LCD_PCLK",         88, 7, "lcd_pclk", "gpmc_a10", "pr1_mii0_crs", "pr1_edio_data_in4", "pr1_edio_data_out4", "pr1_pru1_pru_r30_10", "pr1_pru1_pru_r31_10", "gpio2_24"),
+       _PIN(0x8ec, "LCD_AC_BIAS_EN",   89, 7, "lcd_ac_bias_en", "gpmc_a11", "pr1_mii1_crs", "pr1_edio_data_in5", "pr1_edio_data_out5", "pr1_pru1_pru_r30_11", "pr1_pru1_pru_r31_11", "gpio2_25"),
+       _PIN(0x8f0, "MMC0_DAT3",        90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"),
+       _PIN(0x8f4, "MMC0_DAT2",        91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"),
+       _PIN(0x8f8, "MMC0_DAT1",        92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"),
+       _PIN(0x8fc, "MMC0_DAT0",        93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"),
+       _PIN(0x900, "MMC0_CLK",         94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"),
+       _PIN(0x904, "MMC0_CMD",         95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"),
+       _PIN(0x908, "MII1_COL",         96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"),
+       _PIN(0x90c, "MII1_CRS",         97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"),
+       _PIN(0x910, "MII1_RX_ER",       98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"),
+       _PIN(0x914, "MII1_TX_EN",       99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"),
+       _PIN(0x918, "MII1_RX_DV",       100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"),
+       _PIN(0x91c, "MII1_TXD3",        16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"),
+       _PIN(0x920, "MII1_TXD2",        17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"),
+       _PIN(0x924, "MII1_TXD1",        21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"),
+       _PIN(0x928, "MII1_TXD0",        28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"),
+       _PIN(0x92c, "MII1_TX_CLK",      105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"),
+       _PIN(0x930, "MII1_RX_CLK",      106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"),
+       _PIN(0x934, "MII1_RXD3",        82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"),
+       _PIN(0x938, "MII1_RXD2",        83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"),
+       _PIN(0x93c, "MII1_RXD1",        84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"),
+       _PIN(0x940, "MII1_RXD0",        85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"),
+       _PIN(0x944, "RMII1_REF_CLK",    29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"),
+       _PIN(0x948, "MDIO",             0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"),
+       _PIN(0x94c, "MDC",              1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"),
+       _PIN(0x950, "SPI0_SCLK",        2, 7, "spi0_sclk", "uart2_rxd", "I2C2_SDA", "ehrpwm0A", "pr1_uart0_cts_n", "pr1_edio_sof", "EMU2", "gpio0_2"),
+       _PIN(0x954, "SPI0_D0",          3, 7, "spi0_d0", "uart2_txd", "I2C2_SCL", "ehrpwm0B", "pr1_uart0_rts_n", "pr1_edio_latch_in", "EMU3", "gpio0_3"),
+       _PIN(0x958, "SPIO_D1",          4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"),
+       _PIN(0x95c, "SPI0_CS0",         5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"),
+       _PIN(0x960, "SPI0_CS1",         6, 7, "spi0_cs1", "uart3_rxd", "eCAP1_in_PWM1_out", "mcc0_pow", "xdm_event_intr2", "mmc0_sdcd", "EMU4", "gpio0_6"),
+       _PIN(0x964, "ECAP0_IN_PWM0_OUT",7, 7, "eCAP0_in_PWM0_out", "uart3_txd", "spi1_cs1", "pr1_ecap0_ecap_capin_apwm_o", "spi1_sclk", "mmc0_sdwp", "xdma_event_intr2", "gpio0_7"),
+       _PIN(0x968, "UART0_CTSn",       40, 7, "uart0_ctsn", "uart4_rxd", "dcan1_tx", "I2C1_SDA", "spi1_d0", "timer7", "pr1_edc_sync0_out", "gpio1_8"),
+       _PIN(0x96c, "UART0_RTSn",       41, 7, "uart0_rtsn", "uart4_txd", "dcan1_rx", "I2C1_SCL", "spi1_d1", "spi1_cs0", "pr1_edc_sync1_out", "gpio1_9"),
+       _PIN(0x970, "UART0_rxd",        42, 7, "uart0_rxd", "spi1_cs0", "dcan0_tx", "I2C2_SDA", "eCAP2_in_PWM2_out", "pr1_pru1_pru_r30_14", "pr1_pru1_pru_r31_14", "gpio1_10"),
+       _PIN(0x974, "UART0_txd",        43, 7, "uart0_txd", "spi1_cs1", "dcan0_rx", "I2C2_SCL", "eCAP1_in_PWM1_out", "pr1_pru1_pru_r30_15", "pr1_pru1_pru_r31_15", "gpio1_11"),
+       _PIN(0x978, "UART1_CTSn",       12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"),
+       _PIN(0x97c, "UART1_RTSn",       13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n        ", "pr1_edc_latch1_in", "gpio0_13"),
+       _PIN(0x980, "UART1_RXD",        14, 7, "uart1_rxd", "mmc1_sdwp", "dcan1_tx", "I2C1_SDA", NULL, "pr1_uart0_rxd", "pr1_pru1_pru_r31_16", "gpio0_14"),
+       _PIN(0x984, "UART1_TXD",        15, 7, "uart1_txd", "mmc2_sdwp", "dcan1_rx", "I2C1_SCL", NULL, "pr1_uart0_txd", "pr1_pru0_pru_r31_16", "gpio0_15"),
+       _PIN(0x988, "I2C0_SDA",         101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"),
+       _PIN(0x98c, "I2C0_SCL",         102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"),
+       _PIN(0x990, "MCASP0_ACLKX",     110, 7, "mcasp0_aclkx", "ehrpwm0A", NULL, "spi1_sclk", "mmc0_sdcd", "pr1_pru0_pru_r30_0", "pr1_pru0_pru_r31_0", "gpio3_14"),
+       _PIN(0x994, "MCASP0_FSX",       111, 7, "mcasp0_fsx", "ehrpwm0B", NULL, "spi1_d0", "mmc1_sdcd", "pr1_pru0_pru_r30_1", "pr1_pru0_pru_r31_1", "gpio3_15"),
+       _PIN(0x998, "MCASP0_AXR0",      112, 7, "mcasp0_axr0", "ehrpwm0_tripzone_input", NULL, "spi1_d1", "mmc2_sdcd", "pr1_pru0_pru_r30_2", "pr1_pru0_pru_r31_2", "gpio3_16"),
+       _PIN(0x99c, "MCASP0_AHCLKR",    113, 7, "mcasp0_ahclkr", "ehrpwm0_synci", "mcasp0_axr2", "spi1_cs0", "eCAP2_in_PWM2_out", "pr1_pru0_pru_r30_3", "pr1_pru0_pru_r31_3", "gpio3_17"),
+       _PIN(0x9a0, "MCASP0_ACLKR",     114, 7, "mcasp0_aclkr", "eQEP0A_in", "mcasp0_axr2", "mcasp1_aclkx", "mmc0_sdwp", "pr1_pru0_pru_r30_4", "pr1_pru0_pru_r31_4", "gpio3_18"),
+       _PIN(0x9a4, "MCASP0_FSR",       115, 7, "mcasp0_fsr", "eQEP0B_in", "mcasp0_axr3", "mcasp1_fsx", "EMU2", "pr1_pru0_pru_r30_5", "pr1_pru0_pru_r31_5", "gpio3_19"),
+       _PIN(0x9a8, "MCASP0_AXR1",      116, 7, "mcasp0_axr1", "eQEP0_index", NULL, "mcasp1_axr0", "EMU3", "pr1_pru0_pru_r30_6", "pr1_pru0_pru_r31_6", "gpio3_20"),
+       _PIN(0x9ac, "MCASP0_AHCLKX",    117, 7, "mcasp0_ahclkx", "eQEP0_strobe", "mcasp0_axr3", "mcasp1_axr1", "EMU4", "pr1_pru0_pru_r30_7", "pr1_pru0_pru_r31_7", "gpio3_21"),
+       _PIN(0x9b0, "XDMA_EVENT_INTR0", 19, 7, "xdma_event_intr0", NULL, "timer4", "clkout1", "spi1_cs1", "pr1_pru1_pru_r31_16", "EMU2", "gpio0_19"),
+       _PIN(0x9b4, "XDMA_EVENT_INTR1", 20, 7, "xdma_event_intr1", NULL, "tclkin", "clkout2", "timer7", "pr1_pru0_pru_r31_16", "EMU3", "gpio0_20"),
+#if 0
+       _PIN(0x9b8, "nresetin_out",     0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9bc, "porz",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9c0, "nnmi",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9c4, "osc0_in",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9c8, "osc0_out",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9cc, "osc0_vss",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9d0, "tms",              0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9d4, "tdi",              0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9d8, "tdo",              0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9dc, "tck",              0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9e0, "ntrst",            0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+       _PIN(0x9e4, "EMU0",             103, 7, "EMU0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_7"),
+       _PIN(0x9e8, "EMU1",             104, 0, "EMU1", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_8"),
+#if 0
+       _PIN(0x9ec, "osc1_in",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9f0, "osc1_out",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9f4, "osc1_vss",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9f8, "rtc_porz",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0x9fc, "pmic_power_en",    0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa00, "ext_wakeup",       0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa04, "enz_kaldo_1p8v",   0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+       _PIN(0xa08, "USB0_DM",          0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa0c, "USB0_DP",          0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa10, "USB0_CE",          0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa14, "USB0_ID",          0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa18, "USB0_VBUS",        0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa1c, "USB0_DRVVBUS",     18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"),
+       _PIN(0xa20, "USB1_DM",          0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa24, "USB1_DP",          0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa28, "USB1_CE",          0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa2c, "USB1_ID",          0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa30, "USB1_VBUS",        0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa34, "USB1_DRVVBUS",     109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"),
+#if 0
+       _PIN(0xa38, "ddr_resetn",       0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa3c, "ddr_csn0",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa40, "ddr_cke",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa44, "ddr_ck",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa48, "ddr_nck",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa4c, "ddr_casn",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa50, "ddr_rasn",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa54, "ddr_wen",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa58, "ddr_ba0",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa5c, "ddr_ba1",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa60, "ddr_ba2",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa64, "ddr_a0",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa68, "ddr_a1",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa6c, "ddr_a2",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa70, "ddr_a3",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa74, "ddr_a4",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa78, "ddr_a5",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa7c, "ddr_a6",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa80, "ddr_a7",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa84, "ddr_a8",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa88, "ddr_a9",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa8c, "ddr_a10",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa90, "ddr_a11",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa94, "ddr_a12",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa98, "ddr_a13",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xa9c, "ddr_a14",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaa0, "ddr_a15",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaa4, "ddr_odt",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaa8, "ddr_d0",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaac, "ddr_d1",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xab0, "ddr_d2",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xab4, "ddr_d3",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xab8, "ddr_d4",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xabc, "ddr_d5",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xac0, "ddr_d6",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xac4, "ddr_d7",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xac8, "ddr_d8",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xacc, "ddr_d9",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xad0, "ddr_d10",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xad4, "ddr_d11",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xad8, "ddr_d12",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xadc, "ddr_d13",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xae0, "ddr_d14",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xae4, "ddr_d15",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xae8, "ddr_dqm0",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaec, "ddr_dqm1",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaf0, "ddr_dqs0",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaf4, "ddr_dqsn0",        0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xaf8, "ddr_dqs1",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xafc, "ddr_dqsn1",        0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb00, "ddr_vref",         0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb04, "ddr_vtp",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb08, "ddr_strben0",      0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb0c, "ddr_strben1",      0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb2c, "ain0",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb28, "ain1",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb24, "ain2",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb20, "ain3",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb1c, "ain4",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb18, "ain5",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb14, "ain6",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb10, "ain7",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb30, "vrefp",            0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb34, "vrefn",            0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb38, "avdd",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb3c, "avss",             0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb40, "iforce",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb44, "vsense",           0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+       _PIN(0xb48, "testout",          0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+       {  .ballname = NULL  },
+};
+
+const struct sitara_cm_device sitara_cm_dev = {
+       .padconf_muxmode_mask   = 0x7,
+       .padconf_sate_mask      = 0x78,
+       .padstate               = (struct sitara_cm_padstate *) &ti_padstate_devmap,
+       .padconf                = (struct sitara_cm_padconf *) &ti_padconf_devmap,
+};
+
+int
+sitara_cm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags)
+{
+       unsigned int state = 0;
+       if (flags & GPIO_PIN_OUTPUT) {
+               if (flags & GPIO_PIN_PULLUP)
+                       state = PADCONF_OUTPUT_PULLUP;
+               else
+                       state = PADCONF_OUTPUT;
+       } else if (flags & GPIO_PIN_INPUT) {
+               if (flags & GPIO_PIN_PULLUP)
+                       state = PADCONF_INPUT_PULLUP;
+               else if (flags & GPIO_PIN_PULLDOWN)
+                       state = PADCONF_INPUT_PULLDOWN;
+               else
+                       state = PADCONF_INPUT;
+       }
+       return sitara_cm_padconf_set_gpiomode(gpio, state);
+}
+
+void
+sitara_cm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags)
+{
+       unsigned int state;
+       if (sitara_cm_padconf_get_gpiomode(gpio, &state) != 0)
+               *flags = 0;
+       else {
+               switch (state) {
+                       case PADCONF_OUTPUT:
+                               *flags = GPIO_PIN_OUTPUT;
+                               break;
+                       case PADCONF_OUTPUT_PULLUP:
+                               *flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP;
+                               break;
+                       case PADCONF_INPUT:
+                               *flags = GPIO_PIN_INPUT;
+                               break;
+                       case PADCONF_INPUT_PULLUP:
+                               *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+                               break;
+                       case PADCONF_INPUT_PULLDOWN:
+                               *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN;
+                               break;
+                       default:
+                               *flags = 0;
+                               break;
+               }
+       }
+}
diff --git a/am335x_prcmreg.h b/am335x_prcmreg.h
new file mode 100644 (file)
index 0000000..66f3fa7
--- /dev/null
@@ -0,0 +1,57 @@
+/* $OpenBSD: am335x_prcmreg.h,v 1.4 2014/03/18 07:34:17 syl Exp $ */
+/*
+ * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
+ *
+ * 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 AM335X_CLKCTRL_MODULEMODE_ENABLE       2
+#define AM335X_CLKCTRL_MODULEMODE_DISABLE      0
+#define AM335X_CLKCTRL_MODULEMODE_MASK         0x00000003
+
+#define PRCM_AM335X_CM_PER             0x0000
+#define PRCM_AM335X_USB0_CLKCTRL       0x001c
+#define PRCM_AM335X_TPTC0_CLKCTRL      0x0024
+#define PRCM_AM335X_MMC0_CLKCTRL       0x003c
+#define PRCM_AM335X_I2C2_CLKCTRL       0x0044
+#define PRCM_AM335X_I2C1_CLKCTRL       0x0048
+#define PRCM_AM335X_TIMER2_CLKCTRL     0x0080
+#define PRCM_AM335X_TIMER3_CLKCTRL     0x0084
+#define PRCM_AM335X_GPIO1_CLKCTRL      0x00ac
+#define PRCM_AM335X_GPIO2_CLKCTRL      0x00b0
+#define PRCM_AM335X_GPIO3_CLKCTRL      0x00b4
+#define PRCM_AM335X_TPCC_CLKCTRL       0x00bc
+#define PRCM_AM335X_MMC1_CLKCTRL       0x00f4
+#define PRCM_AM335X_MMC2_CLKCTRL       0x00f8
+#define PRCM_AM335X_TPTC1_CLKCTRL      0x00fc
+#define PRCM_AM335X_TPTC2_CLKCTRL      0x0100
+#define PRCM_AM335X_CM_WKUP            0x0400
+#define PRCM_AM335X_GPIO0_CLKCTRL      0x0408
+#define PRCM_AM335X_TIMER0_CLKCTRL     0x0410
+#define PRCM_AM335X_I2C0_CLKCTRL       0x04b8
+#define PRCM_AM335X_CM_DPLL            0x0500
+#define PRCM_AM335X_CLKSEL_TIMER2_CLK  0x0508
+#define PRCM_AM335X_CLKSEL_TIMER3_CLK  0x050c
+#define PRCM_AM335X_CM_MPU             0x0600
+#define PRCM_AM335X_CM_DEVICE          0x0700
+#define PRCM_AM335X_CM_RTC             0x0800
+#define PRCM_AM335X_CM_GFX             0x0900
+#define PRCM_AM335X_CM_CEFUSE          0x0a00
+#define PRCM_AM335X_PRM_IRQ            0x0b00
+#define PRCM_AM335X_PRM_PER            0x0c00
+#define PRCM_AM335X_PRM_WKUP           0x0d00
+#define PRCM_AM335X_PRM_MPU            0x0e00
+#define PRCM_AM335X_PRM_DEVICE         0x0f00
+#define PRCM_AM335X_PRM_RTC            0x1000
+#define PRCM_AM335X_PRM_GFX            0x1100
+#define PRCM_AM335X_PRM_CEFUSE         0x1200
diff --git a/dmtimer.c b/dmtimer.c
new file mode 100644 (file)
index 0000000..252b2fd
--- /dev/null
+++ b/dmtimer.c
@@ -0,0 +1,413 @@
+/*     $OpenBSD: dmtimer.c,v 1.6 2015/01/22 14:33:01 krw Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
+ *
+ * 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.
+ */
+
+/*
+ *     WARNING - this timer initializion has not been checked
+ *     to see if it will do _ANYTHING_ sane if the omap enters
+ *     low power mode.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/evcount.h>
+#include <sys/device.h>
+#include <sys/timetc.h>
+#include <dev/clock_subr.h>
+#include <machine/bus.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+
+/* registers */
+#define        DM_TIDR         0x000
+#define                DM_TIDR_MAJOR           0x00000700
+#define                DM_TIDR_MINOR           0x0000003f
+#define        DM_TIOCP_CFG    0x010
+#define        DM_TIOCP_CFG_IDLEMODE   (3<<2)
+#define        DM_TIOCP_CFG_EMUFREE    (1<<1)
+#define        DM_TIOCP_CFG_SOFTRESET  (1<<0)
+#define        DM_TISR         0x028
+#define                DM_TISR_TCAR            (1<<2)
+#define                DM_TISR_OVF             (1<<1)
+#define                DM_TISR_MAT             (1<<0)
+#define DM_TIER                0x2c
+#define                DM_TIER_TCAR_EN         (1<<2)
+#define                DM_TIER_OVF_EN          (1<<1)
+#define                DM_TIER_MAT_EN          (1<<0)
+#define DM_TIECR       0x30
+#define                DM_TIECR_TCAR_EN        (1<<2)
+#define                DM_TIECR_OVF_EN         (1<<1)
+#define                DM_TIECR_MAT_EN         (1<<0)
+#define        DM_TWER         0x034
+#define                DM_TWER_TCAR_EN         (1<<2)
+#define                DM_TWER_OVF_EN          (1<<1)
+#define                DM_TWER_MAT_EN          (1<<0)
+#define        DM_TCLR         0x038
+#define                DM_TCLR_GPO             (1<<14)
+#define                DM_TCLR_CAPT            (1<<13)
+#define                DM_TCLR_PT              (1<<12)
+#define                DM_TCLR_TRG             (3<<10)
+#define                DM_TCLR_TRG_O           (1<<10)
+#define                DM_TCLR_TRG_OM          (2<<10)
+#define                DM_TCLR_TCM             (3<<8)
+#define                DM_TCLR_TCM_RISE        (1<<8)
+#define                DM_TCLR_TCM_FALL        (2<<8)
+#define                DM_TCLR_TCM_BOTH        (3<<8)
+#define                DM_TCLR_SCPWM           (1<<7)
+#define                DM_TCLR_CE              (1<<6)
+#define                DM_TCLR_PRE             (1<<5)
+#define                DM_TCLR_PTV             (7<<2)
+#define                DM_TCLR_AR              (1<<1)
+#define                DM_TCLR_ST              (1<<0)
+#define        DM_TCRR         0x03c
+#define        DM_TLDR         0x040
+#define        DM_TTGR         0x044
+#define        DM_TWPS         0x048
+#define                DM_TWPS_TMAR            (1<<4)
+#define                DM_TWPS_TTGR            (1<<3)
+#define                DM_TWPS_TLDR            (1<<2)
+#define                DM_TWPS_TCLR            (1<<0)
+#define                DM_TWPS_TCRR            (1<<1)
+#define                DM_TWPS_ALL             0x1f
+#define        DM_TMAR         0x04c
+#define        DM_TCAR         0x050
+#define        DM_TSICR        0x054
+#define                DM_TSICR_POSTED         (1<<2)
+#define                DM_TSICR_SFT            (1<<1)
+#define        DM_TCAR2        0x058
+
+#define TIMER_FREQUENCY                        32768   /* 32kHz is used, selectable */
+#define MAX_TIMERS                     2
+
+static struct evcount clk_count;
+static struct evcount stat_count;
+
+void dmtimer_attach(struct device *parent, struct device *self, void *args);
+int dmtimer_intr(void *frame);
+void dmtimer_wait(int reg);
+void dmtimer_cpu_initclocks(void);
+void dmtimer_delay(u_int);
+void dmtimer_setstatclockrate(int newhz);
+
+u_int dmtimer_get_timecount(struct timecounter *);
+
+static struct timecounter dmtimer_timecounter = {
+       dmtimer_get_timecount, NULL, 0xffffffff, 0, "dmtimer", 0, NULL
+};
+
+bus_space_handle_t dmtimer_ioh0;
+int dmtimer_irq = 0;
+
+struct dmtimer_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh[MAX_TIMERS];
+       u_int32_t               sc_irq;
+       u_int32_t               sc_ticks_per_second;
+       u_int32_t               sc_ticks_per_intr;
+       u_int32_t               sc_ticks_err_cnt;
+       u_int32_t               sc_ticks_err_sum;
+       u_int32_t               sc_statvar;
+       u_int32_t               sc_statmin;
+       u_int32_t               sc_nexttickevent;
+       u_int32_t               sc_nextstatevent;
+};
+
+struct cfattach        dmtimer_ca = {
+       sizeof (struct dmtimer_softc), NULL, dmtimer_attach
+};
+
+struct cfdriver dmtimer_cd = {
+       NULL, "dmtimer", DV_DULL
+};
+
+void
+dmtimer_attach(struct device *parent, struct device *self, void *args)
+{
+       struct dmtimer_softc    *sc = (struct dmtimer_softc *)self;
+       struct armv7_attach_args *aa = args;
+       bus_space_handle_t      ioh;
+       u_int32_t               rev, cfg;
+
+       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, &ioh))
+               panic("%s: bus_space_map failed!\n", __func__);
+
+
+       prcm_setclock(1, PRCM_CLK_SPEED_32);
+       prcm_setclock(2, PRCM_CLK_SPEED_32);
+       prcm_enablemodule(PRCM_TIMER2);
+       prcm_enablemodule(PRCM_TIMER3);
+
+       /* reset */
+       bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG,
+           DM_TIOCP_CFG_SOFTRESET);
+       while (bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG)
+           & DM_TIOCP_CFG_SOFTRESET)
+               ;
+
+       if (self->dv_unit == 0) {
+               dmtimer_ioh0 = ioh;
+               dmtimer_irq = aa->aa_dev->irq[0];
+               /* enable write posted mode */
+               bus_space_write_4(sc->sc_iot, ioh, DM_TSICR, DM_TSICR_POSTED);
+               /* stop timer */
+               bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, 0);
+       } else if (self->dv_unit == 1) {
+               /* start timer because it is used in delay */
+               /* interrupts and posted mode are disabled */
+               sc->sc_irq = dmtimer_irq;
+               sc->sc_ioh[0] = dmtimer_ioh0;
+               sc->sc_ioh[1] = ioh;
+
+               bus_space_write_4(sc->sc_iot, ioh, DM_TCRR, 0);
+               bus_space_write_4(sc->sc_iot, ioh, DM_TLDR, 0);
+               bus_space_write_4(sc->sc_iot, ioh, DM_TCLR,
+                   DM_TCLR_AR | DM_TCLR_ST);
+
+               dmtimer_timecounter.tc_frequency = TIMER_FREQUENCY;
+               dmtimer_timecounter.tc_priv = sc;
+               tc_init(&dmtimer_timecounter);
+               arm_clock_register(dmtimer_cpu_initclocks, dmtimer_delay,
+                   dmtimer_setstatclockrate, NULL);
+       }
+       else
+               panic("attaching too many dmtimers at 0x%lx",
+                   aa->aa_dev->mem[0].addr);
+
+       /* set IDLEMODE to smart-idle */
+       cfg = bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG);
+       bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG,
+           (cfg & ~DM_TIOCP_CFG_IDLEMODE) | 0x02);
+
+       rev = bus_space_read_4(sc->sc_iot, ioh, DM_TIDR);
+       printf(" rev %d.%d\n", (rev & DM_TIDR_MAJOR) >> 8, rev & DM_TIDR_MINOR);
+}
+
+/*
+ * See comment in arm/xscale/i80321_clock.c
+ *
+ * Counter is count up, but with autoreload timers it is not possible
+ * to detect how many interrupts passed while interrupts were blocked.
+ * Also it is not possible to atomically add to the register.
+ *
+ * To work around this two timers are used, one is used as a reference
+ * clock without reload, however we just disable the interrupt it
+ * could generate.
+ *
+ * Internally this keeps track of when the next timer should fire
+ * and based on that time and the current value of the reference
+ * clock a number is written into the timer count register to schedule
+ * the next event.
+ */
+
+int
+dmtimer_intr(void *frame)
+{
+       struct dmtimer_softc    *sc = dmtimer_cd.cd_devs[1];
+       u_int32_t               now, r, nextevent;
+       int32_t                 duration;
+
+       now = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
+
+       while ((int32_t) (sc->sc_nexttickevent - now) <= 0) {
+               sc->sc_nexttickevent += sc->sc_ticks_per_intr;
+               sc->sc_ticks_err_sum += sc->sc_ticks_err_cnt;
+
+               while (sc->sc_ticks_err_sum  > hz) {
+                       sc->sc_nexttickevent += 1;
+                       sc->sc_ticks_err_sum -= hz;
+               }
+
+               clk_count.ec_count++;
+               hardclock(frame);
+       }
+
+       while ((int32_t) (sc->sc_nextstatevent - now) <= 0) {
+               do {
+                       r = random() & (sc->sc_statvar - 1);
+               } while (r == 0); /* random == 0 not allowed */
+               sc->sc_nextstatevent += sc->sc_statmin + r;
+               stat_count.ec_count++;
+               statclock(frame);
+       }
+       if ((sc->sc_nexttickevent - now) < (sc->sc_nextstatevent - now))
+               nextevent = sc->sc_nexttickevent;
+       else
+               nextevent = sc->sc_nextstatevent;
+
+       duration = nextevent -
+           bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
+
+       if (duration <= 0)
+               duration = 1; /* trigger immediately. */
+
+       if (duration > sc->sc_ticks_per_intr + 1) {
+               printf("%s: time lost!\n", __func__);
+               /*
+                * If interrupts are blocked too long, like during
+                * the root prompt or ddb, the timer can roll over,
+                * this will allow the system to continue to run
+                * even if time is lost.
+               */
+               duration = sc->sc_ticks_per_intr;
+               sc->sc_nexttickevent = now;
+               sc->sc_nextstatevent = now;
+       }
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR,
+               bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR));
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -duration);
+       dmtimer_wait(DM_TWPS_ALL);
+       return 1;
+}
+
+/*
+ * would be interesting to play with trigger mode while having one timer
+ * in 32KHz mode, and the other timer running in sysclk mode and use
+ * the high resolution speeds (matters more for delay than tick timer
+ */
+
+void
+dmtimer_cpu_initclocks()
+{
+       struct dmtimer_softc    *sc = dmtimer_cd.cd_devs[1];
+
+       stathz = 128;
+       profhz = 1024;
+
+       sc->sc_ticks_per_second = TIMER_FREQUENCY; /* 32768 */
+
+       setstatclockrate(stathz);
+
+       sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
+       sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
+       sc->sc_ticks_err_sum = 0; 
+
+       /* establish interrupts */
+       arm_intr_establish(sc->sc_irq, IPL_CLOCK, dmtimer_intr,
+           NULL, "tick");
+
+       /* setup timer 0 */
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TLDR, 0);
+
+       sc->sc_nexttickevent = sc->sc_nextstatevent = bus_space_read_4(sc->sc_iot,
+           sc->sc_ioh[1], DM_TCRR) + sc->sc_ticks_per_intr;
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TIER, DM_TIER_OVF_EN);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TWER, DM_TWER_OVF_EN);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, /*clear interrupt flags */
+               bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR));
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -sc->sc_ticks_per_intr);
+       dmtimer_wait(DM_TWPS_ALL);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCLR, /* autoreload and start */
+           DM_TCLR_AR | DM_TCLR_ST);
+       dmtimer_wait(DM_TWPS_ALL);
+}
+
+void
+dmtimer_wait(int reg)
+{
+       struct dmtimer_softc    *sc = dmtimer_cd.cd_devs[1];
+       while (bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TWPS) & reg)
+               ;
+}
+
+void
+dmtimer_delay(u_int usecs)
+{
+       struct dmtimer_softc    *sc = dmtimer_cd.cd_devs[1];
+       u_int32_t               clock, oclock, delta, delaycnt;
+       volatile int            j;
+       int                     csec, usec;
+
+       if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
+               csec = usecs / 10000;
+               usec = usecs % 10000;
+
+               delaycnt = (TIMER_FREQUENCY / 100) * csec +
+                   (TIMER_FREQUENCY / 100) * usec / 10000;
+       } else {
+               delaycnt = TIMER_FREQUENCY * usecs / 1000000;
+       }
+       if (delaycnt <= 1)
+               for (j = 100; j > 0; j--)
+                       ;
+
+       if (sc->sc_ioh[1] == 0) {
+               /* BAH */
+               for (; usecs > 0; usecs--)
+                       for (j = 100; j > 0; j--)
+                               ;
+               return;
+       }
+       oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
+       while (1) {
+               for (j = 100; j > 0; j--)
+                       ;
+               clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
+               delta = clock - oclock;
+               if (delta > delaycnt)
+                       break;
+       }
+       
+}
+
+void
+dmtimer_setstatclockrate(int newhz)
+{
+       struct dmtimer_softc    *sc = dmtimer_cd.cd_devs[1];
+       int minint, statint;
+       int s;
+       
+       s = splclock();
+
+       statint = sc->sc_ticks_per_second / newhz;
+       /* calculate largest 2^n which is smaller than just over half statint */
+       sc->sc_statvar = 0x40000000; /* really big power of two */
+       minint = statint / 2 + 100;
+       while (sc->sc_statvar > minint)
+               sc->sc_statvar >>= 1;
+
+       sc->sc_statmin = statint - (sc->sc_statvar >> 1);
+
+       splx(s);
+
+       /*
+        * XXX this allows the next stat timer to occur then it switches
+        * to the new frequency. Rather than switching instantly.
+        */
+}
+
+
+u_int
+dmtimer_get_timecount(struct timecounter *tc)
+{
+       struct dmtimer_softc *sc = dmtimer_timecounter.tc_priv;
+       
+       return bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
+}
diff --git a/edma.c b/edma.c
new file mode 100644 (file)
index 0000000..333bcc8
--- /dev/null
+++ b/edma.c
@@ -0,0 +1,283 @@
+/*     $OpenBSD: edma.c,v 1.5 2015/01/22 14:33:01 krw Exp $    */
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+#include <armv7/omap/edmavar.h>
+
+#define DEVNAME(s)             ((s)->sc_dev.dv_xname)
+
+struct edma_softc {
+       struct device           sc_dev;
+
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_tpcc;
+
+       void                    *sc_ih_comp;
+       edma_intr_cb_t          sc_intr_cb[64];
+       void                    *sc_intr_dat[64];
+};
+
+#define EDMA_NUM_DMA_CHANS     64
+#define EDMA_NUM_QDMA_CHANS    8
+#define EDMA_TPCC_DHCM(x)      (0x100 + (x * 4))
+#define EDMA_REG_X(x)          (0x1000 + (0x200 * x))
+#define EDMA_TPCC_PID          0x0
+#define EDMA_TPCC_EMCR         0x308
+#define EDMA_TPCC_EMCRH                0x30c
+#define EDMA_TPCC_CCERRCLR     0x31c
+#define EDMA_TPCC_DRAE0                0x340
+#define EDMA_TPCC_DRAEH0       0x344
+#define EDMA_TPCC_ESR          0x1010
+#define EDMA_TPCC_ESRH         0x1014
+#define EDMA_TPCC_EESR         0x1030
+#define EDMA_TPCC_EESRH                0x1034
+#define EDMA_TPCC_SECR         0x1040
+#define EDMA_TPCC_SECRH                0x1044
+#define EDMA_TPCC_IER          0x1050
+#define EDMA_TPCC_IERH         0x1054
+#define EDMA_TPCC_IECR         0x1058
+#define EDMA_TPCC_IECRH                0x105c
+#define EDMA_TPCC_IESR         0x1060
+#define EDMA_TPCC_IESRH                0x1064
+#define EDMA_TPCC_IPR          0x1068
+#define EDMA_TPCC_IPRH         0x106c
+#define EDMA_TPCC_ICR          0x1070
+#define EDMA_TPCC_ICRH         0x1074
+#define EDMA_TPCC_IEVAL                0x1078
+#define EDMA_TPCC_OPT(x)       (0x4000 + (x * 0x20))
+
+#define TPCC_READ_4(sc, reg)                                           \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg)))
+#define TPCC_WRITE_4(sc, reg, val)                                     \
+       (bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val)))
+#define TPCC_SET(sc, reg, val)                                         \
+       (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val))))
+#define TPCC_FILTSET(sc, reg, val, filt)                               \
+       (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val)))
+
+struct edma_softc *edma_sc;
+
+void   edma_attach(struct device *, struct device *, void *);
+int    edma_comp_intr(void *);
+
+struct cfattach edma_ca = {
+       sizeof(struct edma_softc), NULL, edma_attach
+};
+
+struct cfdriver edma_cd = {
+       NULL, "edma", DV_DULL
+};
+
+void
+edma_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+       struct edma_softc *sc = (struct edma_softc *)self;
+       uint32_t rev;
+       int i;
+
+       sc->sc_iot = aa->aa_iot;
+
+       /* Map Base address for TPCC and TPCTX */
+       if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_tpcc)) {
+               printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc));
+               return ;
+       }
+
+       /* Enable TPCC and TPTC0 in PRCM */
+       prcm_enablemodule(PRCM_TPCC);
+       prcm_enablemodule(PRCM_TPTC0);
+
+       rev = TPCC_READ_4(sc, EDMA_TPCC_PID);
+       printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+
+       /* XXX IPL_VM ? */
+       /* Enable interrupts line */
+       sc->sc_ih_comp = arm_intr_establish(aa->aa_dev->irq[0], IPL_VM,
+           edma_comp_intr, sc, DEVNAME(sc));
+       if (sc->sc_ih_comp == NULL) {
+               printf("%s: unable to establish interrupt comp\n", DEVNAME(sc));
+               bus_space_unmap(sc->sc_iot, sc->sc_tpcc,
+                   aa->aa_dev->mem[0].size);
+               return ;
+       }
+
+       /* Set global softc */
+       edma_sc = sc;
+
+       /* Clear Event Missed Events */
+       TPCC_WRITE_4(sc, EDMA_TPCC_EMCR, 0xffffffff);
+       TPCC_WRITE_4(sc, EDMA_TPCC_EMCRH, 0xffffffff);
+       TPCC_WRITE_4(sc, EDMA_TPCC_CCERRCLR, 0xffffffff);
+
+       /* Identity Map Channels PaRAM */
+       for (i = 0; i < EDMA_NUM_DMA_CHANS; i++)
+               TPCC_WRITE_4(sc, EDMA_TPCC_DHCM(i), i << 5);
+
+       /*
+        * Enable SHADOW Region 0 and only use this region
+        * This is needed to have working intr...
+        */
+       TPCC_WRITE_4(sc, EDMA_TPCC_DRAE0, 0xffffffff);
+       TPCC_WRITE_4(sc, EDMA_TPCC_DRAEH0, 0xffffffff);
+
+       return ;
+}
+
+int
+edma_comp_intr(void *arg)
+{
+       struct edma_softc *sc = arg;
+       uint32_t ipr, iprh;
+       int i;
+
+       ipr = TPCC_READ_4(sc, EDMA_TPCC_IPR);
+       iprh = TPCC_READ_4(sc, EDMA_TPCC_IPRH);
+
+       /* Lookup to intr in the first 32 chans */
+       for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
+               if (ISSET(ipr, (1<<i))) {
+                       TPCC_WRITE_4(sc, EDMA_TPCC_ICR, (1<<i));
+                       if (sc->sc_intr_cb[i])
+                               sc->sc_intr_cb[i](sc->sc_intr_dat[i]);
+               }
+       }
+
+       for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
+               if (ISSET(iprh, (1<<i))) {
+                       TPCC_WRITE_4(sc, EDMA_TPCC_ICRH, (1<<i));
+                       if (sc->sc_intr_cb[i + 32])
+                               sc->sc_intr_cb[i + 32](sc->sc_intr_dat[i + 32]);
+               }
+       }
+
+       /* Trig pending intr */
+       TPCC_WRITE_4(sc, EDMA_TPCC_IEVAL, 1);
+
+       return (1);
+}
+
+int
+edma_intr_dma_en(uint32_t ch, edma_intr_cb_t cb, void *dat)
+{
+       if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
+               return (EINVAL);
+
+       edma_sc->sc_intr_cb[ch] = cb;
+       edma_sc->sc_intr_dat[ch] = dat;
+
+       if (ch < 32) {
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR + EDMA_REG_X(0), 1 << ch);
+       } else {
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH + EDMA_REG_X(0),
+                   1 << (ch - 32));
+       }
+
+       return (0);
+}
+
+int
+edma_intr_dma_dis(uint32_t ch)
+{
+       if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
+               return (EINVAL);
+
+       if (ch < 32)
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECR, 1 << ch);
+       else
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECRH, 1 << (ch - 32));
+       edma_sc->sc_intr_cb[ch] = NULL;
+       edma_sc->sc_intr_dat[ch] = NULL;
+
+       return (0);
+}
+
+int
+edma_trig_xfer_man(uint32_t ch)
+{
+       if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
+               return (EINVAL);
+
+       /*
+        * Trig xfer
+        * enable IEVAL only if there is an intr associated
+        */
+       if (ch < 32) {
+               if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
+                       TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESR, 1 << ch);
+       } else {
+               if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
+                       TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESRH, 1 << (ch - 32));
+       }
+
+       return (0);
+}
+
+int
+edma_trig_xfer_by_dev(uint32_t ch)
+{
+       if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
+               return (EINVAL);
+
+       if (ch < 32) {
+               if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
+                       TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESR, 1 << ch);
+       } else {
+               if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
+                       TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
+               TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESRH, 1 << (ch - 32));
+       }
+       return (0);
+}
+
+void
+edma_param_write(uint32_t ch, struct edma_param *params)
+{
+       bus_space_write_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
+           EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
+}
+
+void
+edma_param_read(uint32_t ch, struct edma_param *params)
+{
+       bus_space_read_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
+           EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
+}
+
diff --git a/edmavar.h b/edmavar.h
new file mode 100644 (file)
index 0000000..e1a7ed3
--- /dev/null
+++ b/edmavar.h
@@ -0,0 +1,49 @@
+/*     $OpenBSD: edmavar.h,v 1.4 2015/01/22 14:33:01 krw Exp $ */
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __EDMAVAR_H__
+#define __EDMAVAR_H__
+
+typedef        void (*edma_intr_cb_t)(void *);
+
+/*
+ *     EDMA PaRAM dma descriptors
+ */
+struct edma_param{
+       uint32_t                opt;            /* Option */
+       uint32_t                src;            /* Ch source */
+       uint16_t                acnt;           /* 1st dim count */
+       uint16_t                bcnt;           /* 2nd dim count */
+       uint32_t                dst;            /* Chan dst addr */
+       int16_t                 srcbidx;        /* Src b index */
+       int16_t                 dstbidx;        /* Dst b index */
+       uint16_t                link;           /* Link addr */
+       uint16_t                bcntrld;        /* BCNT reload */
+       int16_t                 srccidx;        /* Source C index */
+       int16_t                 dstcidx;        /* Dest C index */
+       uint16_t                ccnt;           /* 3rd dim count */
+       uint16_t                res;            /* Reserved */
+} __attribute__((__packed__));
+
+int    edma_intr_dma_en(uint32_t, edma_intr_cb_t, void *); /* en it for chan */
+int    edma_intr_dma_dis(uint32_t);                /* disable intr for chan */
+int    edma_trig_xfer_man(uint32_t);               /* trig a dma xfer */
+int    edma_trig_xfer_by_dev(uint32_t);            /* dma xfer trig by dev */
+void   edma_param_write(uint32_t, struct edma_param *);
+void   edma_param_read(uint32_t, struct edma_param *);
+
+#endif /* __EDMAVAR_H__ */
diff --git a/files.omap b/files.omap
new file mode 100644 (file)
index 0000000..a50b93e
--- /dev/null
@@ -0,0 +1,92 @@
+#      $OpenBSD: files.omap,v 1.8 2016/05/02 08:15:55 patrick Exp $
+
+define omap {}
+device omap: omap
+attach omap at fdt
+file   arch/armv7/omap/omap_machdep.c          omap    needs-flag
+file   arch/armv7/omap/omap.c                  omap
+file   arch/armv7/omap/omap3.c
+file   arch/armv7/omap/omap4.c
+file   arch/armv7/omap/am335x.c
+
+device ommmc: sdmmcbus
+attach ommmc at omap
+file   arch/armv7/omap/ommmc.c                 ommmc
+
+device cpsw: ether, ifnet, mii, ifmedia
+attach cpsw at omap
+file   arch/armv7/omap/if_cpsw.c               cpsw
+
+device prcm
+attach prcm at omap
+file   arch/armv7/omap/prcm.c                  prcm
+
+device sitaracm
+attach sitaracm at omap
+file   arch/armv7/omap/am335x_cm_padconf.c     sitaracm
+file   arch/armv7/omap/sitara_cm.c             sitaracm
+
+device omgpio: gpiobus
+attach omgpio at omap
+file   arch/armv7/omap/omgpio.c                omgpio
+
+device tiiic: i2cbus
+attach tiiic at omap
+file   arch/armv7/omap/ti_iic.c                tiiic
+
+device edma
+attach edma at omap
+file   arch/armv7/omap/edma.c                  edma
+
+device intc
+attach intc at omap
+file   arch/armv7/omap/intc.c                  intc
+
+device gptimer
+attach gptimer at omap
+file   arch/armv7/omap/gptimer.c               gptimer
+
+device dmtimer
+attach dmtimer at omap
+file   arch/armv7/omap/dmtimer.c               dmtimer
+
+device omapid
+attach omapid at omap
+file   arch/armv7/omap/omapid.c                omapid
+
+device omdog
+attach omdog at omap
+file   arch/armv7/omap/omdog.c                 omdog
+
+attach ohci at omap with omohci
+file   arch/armv7/omap/omohci.c                omohci
+
+attach ehci at omap with omehci
+file   arch/armv7/omap/omehci.c                omehci
+
+# NS16550 compatible serial ports
+attach com at omap with com_omap
+file   arch/armv7/omap/omap_com.c              com_omap
+
+device omusbtll
+attach omusbtll at omap
+file arch/armv7/omap/omusbtll.c                        omusbtll
+
+device omkbd: wskbddev
+attach omkbd at omap
+file   arch/armv7/omap/omkbd.c                 omkbd
+
+# LCD frame buffer
+device omdisplay: wsemuldisplaydev, rasops16
+attach omdisplay at omap
+file arch/armv7/omap/omdisplay.c               omdisplay
+
+# MCSPI - spi 
+device mcspi 
+attach mcspi at omap
+file   arch/armv7/omap/mcspi.c                 mcspi
+
+# pseudo-Audio Device Driver
+device oaudio: audio
+attach oaudio at omap                          # configure after Atlas Driver
+file arch/armv7/omap/beagle_audio.c            oaudio
diff --git a/gptimer.c b/gptimer.c
new file mode 100644 (file)
index 0000000..e5fd996
--- /dev/null
+++ b/gptimer.c
@@ -0,0 +1,441 @@
+/* $OpenBSD: gptimer.c,v 1.4 2014/06/20 14:08:11 rapha Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *     WARNING - this timer initializion has not been checked
+ *     to see if it will do _ANYTHING_ sane if the omap enters
+ *     low power mode.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/evcount.h>
+#include <sys/device.h>
+#include <sys/timetc.h>
+#include <dev/clock_subr.h>
+#include <machine/bus.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+
+/* registers */
+#define        GP_TIDR         0x000
+#define                GP_TIDR_REV     0xff
+#define GP_TIOCP_CFG   0x010
+#define        GP_TIOCP_CFG_CLKA       0x000000300
+#define        GP_TIOCP_CFG_EMUFREE    0x000000020
+#define        GP_TIOCP_CFG_IDLEMODE   0x000000018
+#define        GP_TIOCP_CFG_ENAPWAKEUP 0x000000004
+#define        GP_TIOCP_CFG_SOFTRESET  0x000000002
+#define        GP_TIOCP_CFG_AUTOIDLE   0x000000001
+#define        GP_TISTAT       0x014
+#define        GP_TISTAT_RESETDONE     0x000000001
+#define        GP_TISR         0x018
+#define                GP_TISTAT_TCAR          0x00000004
+#define                GP_TISTAT_OVF           0x00000002
+#define                GP_TISTAT_MATCH         0x00000001
+#define GP_TIER                0x1c
+#define                GP_TIER_TCAR_EN         0x4
+#define                GP_TIER_OVF_EN          0x2
+#define                GP_TIER_MAT_EN          0x1
+#define        GP_TWER         0x020
+#define                GP_TWER_TCAR_EN         0x00000004
+#define                GP_TWER_OVF_EN          0x00000002
+#define                GP_TWER_MAT_EN          0x00000001
+#define        GP_TCLR         0x024
+#define                GP_TCLR_GPO             (1<<14)
+#define                GP_TCLR_CAPT            (1<<13)
+#define                GP_TCLR_PT              (1<<12)
+#define                GP_TCLR_TRG             (3<<10)
+#define                GP_TCLR_TRG_O           (1<<10)
+#define                GP_TCLR_TRG_OM          (2<<10)
+#define                GP_TCLR_TCM             (3<<8)
+#define                GP_TCLR_TCM_RISE        (1<<8)
+#define                GP_TCLR_TCM_FALL        (2<<8)
+#define                GP_TCLR_TCM_BOTH        (3<<8)
+#define                GP_TCLR_SCPWM           (1<<7)
+#define                GP_TCLR_CE              (1<<6)
+#define                GP_TCLR_PRE             (1<<5)
+#define                GP_TCLR_PTV             (7<<2)
+#define                GP_TCLR_AR              (1<<1)
+#define                GP_TCLR_ST              (1<<0)
+#define        GP_TCRR         0x028                           /* counter */
+#define        GP_TLDR         0x02c                           /* reload */
+#define        GP_TTGR         0x030
+#define        GP_TWPS         0x034
+#define                GP_TWPS_TCLR    0x01
+#define                GP_TWPS_TCRR    0x02
+#define                GP_TWPS_TLDR    0x04
+#define                GP_TWPS_TTGR    0x08
+#define                GP_TWPS_TMAR    0x10
+#define                GP_TWPS_ALL     0x1f
+#define        GP_TMAR         0x038
+#define        GP_TCAR         0x03C
+#define        GP_TSICR        0x040
+#define                GP_TSICR_POSTED         0x00000002
+#define                GP_TSICR_SFT            0x00000001
+#define        GP_TCAR2        0x044
+
+#define TIMER_FREQUENCY                        32768   /* 32kHz is used, selectable */
+
+static struct evcount clk_count;
+static struct evcount stat_count;
+#define GPT1_IRQ  38
+#define GPTIMER0_IRQ   38
+
+//static int clk_irq = GPT1_IRQ; /* XXX 37 */
+
+void gptimer_attach(struct device *parent, struct device *self, void *args);
+int gptimer_intr(void *frame);
+void gptimer_wait(int reg);
+void gptimer_cpu_initclocks(void);
+void gptimer_delay(u_int);
+void gptimer_setstatclockrate(int newhz);
+
+bus_space_tag_t gptimer_iot;
+bus_space_handle_t gptimer_ioh0,  gptimer_ioh1; 
+int gptimer_irq = 0;
+
+u_int gptimer_get_timecount(struct timecounter *);
+
+static struct timecounter gptimer_timecounter = {
+       gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
+};
+
+volatile u_int32_t nexttickevent;
+volatile u_int32_t nextstatevent;
+u_int32_t      ticks_per_second;
+u_int32_t      ticks_per_intr;
+u_int32_t      ticks_err_cnt;
+u_int32_t      ticks_err_sum;
+u_int32_t      statvar, statmin;
+
+struct cfattach        gptimer_ca = {
+       sizeof (struct device), NULL, gptimer_attach
+};
+
+struct cfdriver gptimer_cd = {
+       NULL, "gptimer", DV_DULL
+};
+
+void
+gptimer_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       bus_space_handle_t ioh;
+       u_int32_t rev;
+
+       gptimer_iot = aa->aa_iot;
+       if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &ioh))
+               panic("gptimer_attach: bus_space_map failed!");
+
+       rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR);
+
+       printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+       if (self->dv_unit == 0) {
+               gptimer_ioh0 = ioh;
+               gptimer_irq = aa->aa_dev->irq[0];
+               bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
+       } else if (self->dv_unit == 1) {
+               /* start timer because it is used in delay */
+               gptimer_ioh1 = ioh;
+               bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0);
+               gptimer_wait(GP_TWPS_ALL);
+               bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0);
+               gptimer_wait(GP_TWPS_ALL);
+               bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR,
+                   GP_TCLR_AR | GP_TCLR_ST);
+               gptimer_wait(GP_TWPS_ALL);
+
+               gptimer_timecounter.tc_frequency = TIMER_FREQUENCY;
+               tc_init(&gptimer_timecounter);
+       }
+       else
+               panic("attaching too many gptimers at 0x%lx",
+                   aa->aa_dev->mem[0].addr);
+
+       arm_clock_register(gptimer_cpu_initclocks, gptimer_delay,
+           gptimer_setstatclockrate, NULL);
+}
+
+/* 
+ * See comment in arm/xscale/i80321_clock.c
+ *
+ * counter is count up, but with autoreload timers it is not possible
+ * to detect how many  interrupts passed while interrupts were blocked.
+ * also it is not possible to atomically add to the register
+ * get get it to precisely fire at a non-fixed interval.
+ *
+ * To work around this two timers are used, GPT1 is used as a reference
+ * clock without reload , however we just ignore the interrupt it
+ * would (may?) generate.
+ *
+ * Internally this keeps track of when the next timer should fire
+ * and based on that time and the current value of the reference
+ * clock a number is written into the timer count register to schedule
+ * the next event.
+ */
+
+int
+gptimer_intr(void *frame)
+{
+       u_int32_t now, r;
+       u_int32_t nextevent, duration;
+
+       /* clear interrupt */
+       now = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+
+       while ((int32_t) (nexttickevent - now) < 0) {
+               nexttickevent += ticks_per_intr;
+               ticks_err_sum += ticks_err_cnt;
+#if 0
+               if (ticks_err_sum  > hz) {
+                       u_int32_t match_error;
+                       match_error = ticks_err_sum / hz
+                       ticks_err_sum -= (match_error * hz);
+               }
+#else
+               /* looping a few times is faster than divide */
+               while (ticks_err_sum  > hz) {
+                       nexttickevent += 1;
+                       ticks_err_sum -= hz;
+               }
+#endif
+               clk_count.ec_count++;
+               hardclock(frame);
+       }
+       while ((int32_t) (nextstatevent - now) < 0) {
+               do {
+                       r = random() & (statvar -1);
+               } while (r == 0); /* random == 0 not allowed */
+               nextstatevent += statmin + r;
+               /* XXX - correct nextstatevent? */
+               stat_count.ec_count++;
+               statclock(frame);
+       }
+       if ((nexttickevent - now) < (nextstatevent - now))
+                nextevent = nexttickevent;
+        else
+                nextevent = nextstatevent;
+
+/* XXX */
+       duration = nextevent -
+           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+#if 0
+       printf("duration 0x%x %x %x\n", nextevent -
+           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR),
+           bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TCRR),
+           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR));
+#endif
+
+
+        if (duration <= 0)
+                duration = 1; /* trigger immediately. */
+
+        if (duration > ticks_per_intr) {
+                /*
+                 * If interrupts are blocked too long, like during
+                 * the root prompt or ddb, the timer can roll over,
+                 * this will allow the system to continue to run
+                 * even if time is lost.
+                 */
+                duration = ticks_per_intr;
+                nexttickevent = now;
+                nextstatevent = now;
+        }
+
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
+               bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
+       gptimer_wait(GP_TWPS_ALL);
+        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -duration);
+       return 1;
+}
+
+/*
+ * would be interesting to play with trigger mode while having one timer
+ * in 32KHz mode, and the other timer running in sysclk mode and use
+ * the high resolution speeds (matters more for delay than tick timer
+ */
+
+void
+gptimer_cpu_initclocks()
+{
+//     u_int32_t now;
+       stathz = 128;
+       profhz = 1024;
+
+       ticks_per_second = TIMER_FREQUENCY;
+
+       setstatclockrate(stathz);
+
+       ticks_per_intr = ticks_per_second / hz;
+       ticks_err_cnt = ticks_per_second % hz;
+       ticks_err_sum = 0;; 
+
+       prcm_setclock(1, PRCM_CLK_SPEED_32);
+       prcm_setclock(2, PRCM_CLK_SPEED_32);
+       /* establish interrupts */
+       arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr,
+           NULL, "tick");
+
+       /* setup timer 0 (hardware timer 2) */
+       /* reset? - XXX */
+
+        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0);
+
+       nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot,
+           gptimer_ioh1, GP_TCRR) + ticks_per_intr;
+
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN);
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN);
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR,
+           GP_TCLR_AR | GP_TCLR_ST);
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
+               bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
+       gptimer_wait(GP_TWPS_ALL);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr);
+       gptimer_wait(GP_TWPS_ALL);
+}
+
+void
+gptimer_wait(int reg)
+{
+       while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg)
+               ;
+}
+
+#if 0
+void
+microtime(struct timeval *tvp)
+{
+       int s;
+       int deltacnt;
+       u_int32_t counter, expected;
+       s = splhigh();
+
+       if (1) {        /* not inited */
+               tvp->tv_sec = 0;
+               tvp->tv_usec = 0;
+               return;
+       }
+       s = splhigh();
+       counter = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+       expected = nexttickevent;
+
+       *tvp = time;
+       splx(s);
+
+       deltacnt = counter - expected + ticks_per_intr;
+
+#if 1
+       /* low frequency timer algorithm */
+       tvp->tv_usec += deltacnt * 1000000ULL / TIMER_FREQUENCY;
+#else
+       /* high frequency timer algorithm - XXX */
+       tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL);
+#endif
+
+       while (tvp->tv_usec >= 1000000) {
+               tvp->tv_sec++;
+               tvp->tv_usec -= 1000000;
+       }
+
+}
+#endif
+
+void
+gptimer_delay(u_int usecs)
+{
+       u_int32_t clock, oclock, delta, delaycnt;
+       volatile int j;
+       int csec, usec;
+
+       if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
+               csec = usecs / 10000;
+               usec = usecs % 10000;
+
+               delaycnt = (TIMER_FREQUENCY / 100) * csec +
+                   (TIMER_FREQUENCY / 100) * usec / 10000;
+       } else {
+               delaycnt = TIMER_FREQUENCY * usecs / 1000000;
+       }
+       if (delaycnt <= 1)
+               for (j = 100; j > 0; j--)
+                       ;
+
+       if (gptimer_ioh1 == 0) {
+               /* BAH */
+               for (; usecs > 0; usecs--)
+                       for (j = 100; j > 0; j--)
+                               ;
+               return;
+       }
+       oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+       while (1) {
+               for (j = 100; j > 0; j--)
+                       ;
+               clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+               delta = clock - oclock;
+               if (delta > delaycnt)
+                       break;
+       }
+       
+}
+
+void
+gptimer_setstatclockrate(int newhz)
+{
+       int minint, statint;
+       int s;
+       
+       s = splclock();
+
+       statint = ticks_per_second / newhz;
+       /* calculate largest 2^n which is smaller that just over half statint */
+       statvar = 0x40000000; /* really big power of two */
+       minint = statint / 2 + 100;
+       while (statvar > minint)
+               statvar >>= 1;
+
+       statmin = statint - (statvar >> 1);
+       
+       splx(s);
+
+       /*
+        * XXX this allows the next stat timer to occur then it switches
+        * to the new frequency. Rather than switching instantly.
+        */
+}
+
+
+u_int
+gptimer_get_timecount(struct timecounter *tc)
+{
+       return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
+}
diff --git a/if_cpsw.c b/if_cpsw.c
new file mode 100644 (file)
index 0000000..ad47506
--- /dev/null
+++ b/if_cpsw.c
@@ -0,0 +1,1254 @@
+/* $OpenBSD: if_cpsw.c,v 1.34 2016/04/13 11:33:59 mpi Exp $ */
+/*     $NetBSD: if_cpsw.c,v 1.3 2013/04/17 14:36:34 bouyer Exp $       */
+
+/*
+ * Copyright (c) 2013 Jonathan A. Kollasch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/pool.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+#include <sys/socket.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <arch/armv7/armv7/armv7var.h>
+#include <arch/armv7/omap/sitara_cm.h>
+#include <arch/armv7/omap/if_cpswreg.h>
+
+#define CPSW_TXFRAGS   16
+
+#define OMAP2SCM_MAC_ID0_LO    0x630
+#define OMAP2SCM_MAC_ID0_HI    0x634
+
+#define CPSW_CPPI_RAM_SIZE (0x2000)
+#define CPSW_CPPI_RAM_TXDESCS_SIZE (CPSW_CPPI_RAM_SIZE/2)
+#define CPSW_CPPI_RAM_RXDESCS_SIZE \
+    (CPSW_CPPI_RAM_SIZE - CPSW_CPPI_RAM_TXDESCS_SIZE)
+#define CPSW_CPPI_RAM_TXDESCS_BASE (CPSW_CPPI_RAM_OFFSET + 0x0000)
+#define CPSW_CPPI_RAM_RXDESCS_BASE \
+    (CPSW_CPPI_RAM_OFFSET + CPSW_CPPI_RAM_TXDESCS_SIZE)
+
+#define CPSW_NTXDESCS (CPSW_CPPI_RAM_TXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd))
+#define CPSW_NRXDESCS (CPSW_CPPI_RAM_RXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd))
+
+#define CPSW_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
+
+#define TXDESC_NEXT(x) cpsw_txdesc_adjust((x), 1)
+#define TXDESC_PREV(x) cpsw_txdesc_adjust((x), -1)
+
+#define RXDESC_NEXT(x) cpsw_rxdesc_adjust((x), 1)
+#define RXDESC_PREV(x) cpsw_rxdesc_adjust((x), -1)
+
+struct cpsw_ring_data {
+       bus_dmamap_t             tx_dm[CPSW_NTXDESCS];
+       struct mbuf             *tx_mb[CPSW_NTXDESCS];
+       bus_dmamap_t             rx_dm[CPSW_NRXDESCS];
+       struct mbuf             *rx_mb[CPSW_NRXDESCS];
+};
+
+struct cpsw_softc {
+       struct device            sc_dev;
+       bus_space_tag_t          sc_bst;
+       bus_space_handle_t       sc_bsh;
+       bus_dma_tag_t            sc_bdt;
+       bus_space_handle_t       sc_bsh_txdescs;
+       bus_space_handle_t       sc_bsh_rxdescs;
+       bus_addr_t               sc_txdescs_pa;
+       bus_addr_t               sc_rxdescs_pa;
+
+       struct arpcom            sc_ac;
+       struct mii_data          sc_mii;
+
+       struct cpsw_ring_data   *sc_rdp;
+       volatile u_int           sc_txnext;
+       volatile u_int           sc_txhead;
+       volatile u_int           sc_rxhead;
+
+       void                    *sc_rxthih;
+       void                    *sc_rxih;
+       void                    *sc_txih;
+       void                    *sc_miscih;
+
+       void                    *sc_txpad;
+       bus_dmamap_t             sc_txpad_dm;
+#define sc_txpad_pa sc_txpad_dm->dm_segs[0].ds_addr
+
+       volatile bool            sc_txrun;
+       volatile bool            sc_rxrun;
+       volatile bool            sc_txeoq;
+       volatile bool            sc_rxeoq;
+       struct timeout           sc_tick;
+       int                      sc_active_port;
+};
+
+#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
+
+void   cpsw_attach(struct device *, struct device *, void *);
+
+void   cpsw_start(struct ifnet *);
+int    cpsw_ioctl(struct ifnet *, u_long, caddr_t);
+void   cpsw_watchdog(struct ifnet *);
+int    cpsw_init(struct ifnet *);
+void   cpsw_stop(struct ifnet *);
+
+int    cpsw_mii_readreg(struct device *, int, int);
+void   cpsw_mii_writereg(struct device *, int, int, int);
+void   cpsw_mii_statchg(struct device *);
+
+void   cpsw_tick(void *);
+
+int    cpsw_new_rxbuf(struct cpsw_softc * const, const u_int);
+int    cpsw_mediachange(struct ifnet *);
+void   cpsw_mediastatus(struct ifnet *, struct ifmediareq *);
+
+int    cpsw_rxthintr(void *);
+int    cpsw_rxintr(void *);
+int    cpsw_txintr(void *);
+int    cpsw_miscintr(void *);
+
+void   cpsw_get_mac_addr(struct cpsw_softc *);
+
+struct cfattach cpsw_ca = {
+       sizeof(struct cpsw_softc),
+       NULL,
+       cpsw_attach
+};
+
+struct cfdriver cpsw_cd = {
+       NULL,
+       "cpsw",
+       DV_IFNET
+};
+
+static inline u_int
+cpsw_txdesc_adjust(u_int x, int y)
+{
+       return (((x) + y) & (CPSW_NTXDESCS - 1));
+}
+
+static inline u_int
+cpsw_rxdesc_adjust(u_int x, int y)
+{
+       return (((x) + y) & (CPSW_NRXDESCS - 1));
+}
+
+static inline void
+cpsw_set_txdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0;
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh_txdescs, o, n);
+}
+
+static inline void
+cpsw_set_rxdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0;
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, n);
+}
+
+static inline void
+cpsw_get_txdesc(struct cpsw_softc * const sc, const u_int i,
+    struct cpsw_cpdma_bd * const bdp)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
+       bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o,
+           (uint32_t *)bdp, 4);
+}
+
+static inline void
+cpsw_set_txdesc(struct cpsw_softc * const sc, const u_int i,
+    struct cpsw_cpdma_bd * const bdp)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
+       bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o,
+           (uint32_t *)bdp, 4);
+}
+
+static inline void
+cpsw_get_rxdesc(struct cpsw_softc * const sc, const u_int i,
+    struct cpsw_cpdma_bd * const bdp)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
+       bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o,
+           (uint32_t *)bdp, 4);
+}
+
+static inline void
+cpsw_set_rxdesc(struct cpsw_softc * const sc, const u_int i,
+    struct cpsw_cpdma_bd * const bdp)
+{
+       const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
+       bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o,
+           (uint32_t *)bdp, 4);
+}
+
+static inline bus_addr_t
+cpsw_txdesc_paddr(struct cpsw_softc * const sc, u_int x)
+{
+       KASSERT(x < CPSW_NTXDESCS);
+       return sc->sc_txdescs_pa + sizeof(struct cpsw_cpdma_bd) * x;
+}
+
+static inline bus_addr_t
+cpsw_rxdesc_paddr(struct cpsw_softc * const sc, u_int x)
+{
+       KASSERT(x < CPSW_NRXDESCS);
+       return sc->sc_rxdescs_pa + sizeof(struct cpsw_cpdma_bd) * x;
+}
+
+void
+cpsw_get_mac_addr(struct cpsw_softc *sc)
+{
+       struct arpcom *ac = &sc->sc_ac;
+       u_int32_t       mac_lo = 0, mac_hi = 0;
+
+       sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_LO, &mac_lo);
+       sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_HI, &mac_hi);
+
+       if ((mac_lo == 0) && (mac_hi == 0))
+               printf("%s: invalid ethernet address\n", DEVNAME(sc));
+       else {
+               ac->ac_enaddr[0] = (mac_hi >>  0) & 0xff;
+               ac->ac_enaddr[1] = (mac_hi >>  8) & 0xff;
+               ac->ac_enaddr[2] = (mac_hi >> 16) & 0xff;
+               ac->ac_enaddr[3] = (mac_hi >> 24) & 0xff;
+               ac->ac_enaddr[4] = (mac_lo >>  0) & 0xff;
+               ac->ac_enaddr[5] = (mac_lo >>  8) & 0xff;
+       }
+}
+
+static void
+cpsw_mdio_init(struct cpsw_softc *sc)
+{
+       uint32_t alive, link;
+       u_int tries;
+
+       sc->sc_active_port = 0;
+
+       /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+       /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOCONTROL,
+           (1<<30) | (1<<18) | 0xFF);
+
+       for(tries = 0; tries < 1000; tries++) {
+               alive = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOALIVE) & 3;
+               if (alive)
+                       break;
+               delay(1);
+       }
+
+       if (alive == 0) {
+               printf("%s: no PHY is alive\n", DEVNAME(sc));
+               return;
+       }
+
+       link = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOLINK) & 3;
+
+       if (alive == 3) {
+               /* both ports are alive, prefer one with link */
+               if (link == 2)
+                       sc->sc_active_port = 1;
+       } else if (alive == 2)
+               sc->sc_active_port = 1;
+
+       /* Select the port to monitor */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERPHYSEL0,
+           sc->sc_active_port);
+}
+
+void
+cpsw_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct cpsw_softc *sc = (struct cpsw_softc *)self;
+       struct armv7_attach_args *aa = aux;
+       struct arpcom * const ac = &sc->sc_ac;
+       struct ifnet * const ifp = &ac->ac_if;
+       u_int32_t idver;
+       int error;
+       u_int i;
+
+       timeout_set(&sc->sc_tick, cpsw_tick, sc);
+
+       cpsw_get_mac_addr(sc);
+
+       sc->sc_rxthih = arm_intr_establish(aa->aa_dev->irq[0] +
+           CPSW_INTROFF_RXTH, IPL_NET, cpsw_rxthintr, sc, DEVNAME(sc));
+       sc->sc_rxih = arm_intr_establish(aa->aa_dev->irq[0] +
+           CPSW_INTROFF_RX, IPL_NET, cpsw_rxintr, sc, DEVNAME(sc));
+       sc->sc_txih = arm_intr_establish(aa->aa_dev->irq[0] +
+           CPSW_INTROFF_TX, IPL_NET, cpsw_txintr, sc, DEVNAME(sc));
+       sc->sc_miscih = arm_intr_establish(aa->aa_dev->irq[0] +
+           CPSW_INTROFF_MISC, IPL_NET, cpsw_miscintr, sc, DEVNAME(sc));
+
+       sc->sc_bst = aa->aa_iot;
+       sc->sc_bdt = aa->aa_dmat;
+
+       error = bus_space_map(sc->sc_bst, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_bsh);
+       if (error) {
+               printf("can't map registers: %d\n", error);
+               return;
+       }
+
+       sc->sc_txdescs_pa = aa->aa_dev->mem[0].addr +
+           CPSW_CPPI_RAM_TXDESCS_BASE;
+       error = bus_space_subregion(sc->sc_bst, sc->sc_bsh,
+           CPSW_CPPI_RAM_TXDESCS_BASE, CPSW_CPPI_RAM_TXDESCS_SIZE,
+           &sc->sc_bsh_txdescs);
+       if (error) {
+               printf("can't subregion tx ring SRAM: %d\n", error);
+               return;
+       }
+
+       sc->sc_rxdescs_pa = aa->aa_dev->mem[0].addr +
+           CPSW_CPPI_RAM_RXDESCS_BASE;
+       error = bus_space_subregion(sc->sc_bst, sc->sc_bsh,
+           CPSW_CPPI_RAM_RXDESCS_BASE, CPSW_CPPI_RAM_RXDESCS_SIZE,
+           &sc->sc_bsh_rxdescs);
+       if (error) {
+               printf("can't subregion rx ring SRAM: %d\n", error);
+               return;
+       }
+
+       sc->sc_rdp = malloc(sizeof(*sc->sc_rdp), M_TEMP, M_WAITOK);
+       KASSERT(sc->sc_rdp != NULL);
+
+       for (i = 0; i < CPSW_NTXDESCS; i++) {
+               if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES,
+                   CPSW_TXFRAGS, MCLBYTES, 0, 0,
+                   &sc->sc_rdp->tx_dm[i])) != 0) {
+                       printf("unable to create tx DMA map: %d\n", error);
+               }
+               sc->sc_rdp->tx_mb[i] = NULL;
+       }
+
+       for (i = 0; i < CPSW_NRXDESCS; i++) {
+               if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, 1,
+                   MCLBYTES, 0, 0, &sc->sc_rdp->rx_dm[i])) != 0) {
+                       printf("unable to create rx DMA map: %d\n", error);
+               }
+               sc->sc_rdp->rx_mb[i] = NULL;
+       }
+
+       sc->sc_txpad = dma_alloc(ETHER_MIN_LEN, PR_WAITOK | PR_ZERO);
+       KASSERT(sc->sc_txpad != NULL);
+       bus_dmamap_create(sc->sc_bdt, ETHER_MIN_LEN, 1, ETHER_MIN_LEN, 0,
+           BUS_DMA_WAITOK, &sc->sc_txpad_dm);
+       bus_dmamap_load(sc->sc_bdt, sc->sc_txpad_dm, sc->sc_txpad,
+           ETHER_MIN_LEN, NULL, BUS_DMA_WAITOK|BUS_DMA_WRITE);
+       bus_dmamap_sync(sc->sc_bdt, sc->sc_txpad_dm, 0, ETHER_MIN_LEN,
+           BUS_DMASYNC_PREWRITE);
+
+       idver = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_IDVER);
+       printf(": version %d.%d (%d), address %s\n",
+           CPSW_SS_IDVER_MAJ(idver), CPSW_SS_IDVER_MIN(idver),
+           CPSW_SS_IDVER_RTL(idver), ether_sprintf(ac->ac_enaddr));
+
+       ifp->if_softc = sc;
+       ifp->if_capabilities = 0;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_start = cpsw_start;
+       ifp->if_ioctl = cpsw_ioctl;
+       ifp->if_watchdog = cpsw_watchdog;
+       IFQ_SET_MAXLEN(&ifp->if_snd, CPSW_NTXDESCS - 1);
+       memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
+
+       cpsw_stop(ifp);
+
+       sc->sc_mii.mii_ifp = ifp;
+       sc->sc_mii.mii_readreg = cpsw_mii_readreg;
+       sc->sc_mii.mii_writereg = cpsw_mii_writereg;
+       sc->sc_mii.mii_statchg = cpsw_mii_statchg;
+
+       cpsw_mdio_init(sc);
+
+       ifmedia_init(&sc->sc_mii.mii_media, 0, cpsw_mediachange,
+           cpsw_mediastatus);
+       mii_attach(self, &sc->sc_mii, 0xffffffff,
+           MII_PHY_ANY, MII_OFFSET_ANY, 0);
+       if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+               printf("no PHY found!\n");
+               ifmedia_add(&sc->sc_mii.mii_media,
+                   IFM_ETHER|IFM_MANUAL, 0, NULL);
+               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
+       } else {
+               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+       }
+
+       if_attach(ifp);
+       ether_ifattach(ifp);
+
+       return;
+}
+
+int
+cpsw_mediachange(struct ifnet *ifp)
+{
+       struct cpsw_softc *sc = ifp->if_softc;
+
+       if (LIST_FIRST(&sc->sc_mii.mii_phys))
+               mii_mediachg(&sc->sc_mii);
+
+       return (0);
+}
+
+void
+cpsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct cpsw_softc *sc = ifp->if_softc;
+
+       if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
+               mii_pollstat(&sc->sc_mii);
+               ifmr->ifm_active = sc->sc_mii.mii_media_active;
+               ifmr->ifm_status = sc->sc_mii.mii_media_status;
+       }
+}
+
+void
+cpsw_start(struct ifnet *ifp)
+{
+       struct cpsw_softc * const sc = ifp->if_softc;
+       struct cpsw_ring_data * const rdp = sc->sc_rdp;
+       struct cpsw_cpdma_bd bd;
+       struct mbuf *m;
+       bus_dmamap_t dm;
+       u_int eopi = ~0;
+       u_int seg;
+       u_int txfree;
+       int txstart = -1;
+       int error;
+       bool pad;
+       u_int mlen;
+
+       if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
+           ifq_is_oactive(&ifp->if_snd) ||
+           IFQ_IS_EMPTY(&ifp->if_snd))
+               return;
+
+       if (sc->sc_txnext >= sc->sc_txhead)
+               txfree = CPSW_NTXDESCS - 1 + sc->sc_txhead - sc->sc_txnext;
+       else
+               txfree = sc->sc_txhead - sc->sc_txnext - 1;
+
+       for (;;) {
+               if (txfree <= CPSW_TXFRAGS) {
+                       ifq_set_oactive(&ifp->if_snd);
+                       break;
+               }
+
+               IFQ_DEQUEUE(&ifp->if_snd, m);
+               if (m == NULL)
+                       break;
+
+               dm = rdp->tx_dm[sc->sc_txnext];
+               error = bus_dmamap_load_mbuf(sc->sc_bdt, dm, m, BUS_DMA_NOWAIT);
+               switch (error) {
+               case 0:
+                       break;
+
+               case EFBIG: /* mbuf chain is too fragmented */
+                       if (m_defrag(m, M_DONTWAIT) == 0 &&
+                           bus_dmamap_load_mbuf(sc->sc_bdt, dm, m,
+                           BUS_DMA_NOWAIT) == 0)
+                               break;
+
+                       /* FALLTHROUGH */
+               default:
+                       m_freem(m);
+                       ifp->if_oerrors++;
+                       continue;
+               }
+
+               mlen = dm->dm_mapsize;
+               pad = mlen < CPSW_PAD_LEN;
+
+               KASSERT(rdp->tx_mb[sc->sc_txnext] == NULL);
+               rdp->tx_mb[sc->sc_txnext] = m;
+
+#if NBPFILTER > 0
+               if (ifp->if_bpf)
+                       bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+
+               bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize,
+                   BUS_DMASYNC_PREWRITE);
+
+               if (txstart == -1)
+                       txstart = sc->sc_txnext;
+               eopi = sc->sc_txnext;
+               for (seg = 0; seg < dm->dm_nsegs; seg++) {
+                       bd.next = cpsw_txdesc_paddr(sc,
+                           TXDESC_NEXT(sc->sc_txnext));
+                       bd.bufptr = dm->dm_segs[seg].ds_addr;
+                       bd.bufoff = 0;
+                       bd.buflen = dm->dm_segs[seg].ds_len;
+                       bd.pktlen = 0;
+                       bd.flags = 0;
+
+                       if (seg == 0) {
+                               bd.flags = CPDMA_BD_OWNER | CPDMA_BD_SOP;
+                               bd.pktlen = MAX(mlen, CPSW_PAD_LEN);
+                       }
+
+                       if (seg == dm->dm_nsegs - 1 && !pad)
+                               bd.flags |= CPDMA_BD_EOP;
+
+                       cpsw_set_txdesc(sc, sc->sc_txnext, &bd);
+                       txfree--;
+                       eopi = sc->sc_txnext;
+                       sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext);
+               }
+               if (pad) {
+                       bd.next = cpsw_txdesc_paddr(sc,
+                           TXDESC_NEXT(sc->sc_txnext));
+                       bd.bufptr = sc->sc_txpad_pa;
+                       bd.bufoff = 0;
+                       bd.buflen = CPSW_PAD_LEN - mlen;
+                       bd.pktlen = 0;
+                       bd.flags = CPDMA_BD_EOP;
+
+                       cpsw_set_txdesc(sc, sc->sc_txnext, &bd);
+                       txfree--;
+                       eopi = sc->sc_txnext;
+                       sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext);
+               }
+       }
+
+       if (txstart >= 0) {
+               ifp->if_timer = 5;
+               /* terminate the new chain */
+               KASSERT(eopi == TXDESC_PREV(sc->sc_txnext));
+               cpsw_set_txdesc_next(sc, TXDESC_PREV(sc->sc_txnext), 0);
+               
+               /* link the new chain on */
+               cpsw_set_txdesc_next(sc, TXDESC_PREV(txstart),
+                   cpsw_txdesc_paddr(sc, txstart));
+               if (sc->sc_txeoq) {
+                       /* kick the dma engine */
+                       sc->sc_txeoq = false;
+                       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0),
+                           cpsw_txdesc_paddr(sc, txstart));
+               }
+       }
+}
+
+int
+cpsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct cpsw_softc *sc = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s = splnet();
+       int error = 0;
+
+       switch (cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               /* FALLTHROUGH */
+       case SIOCSIFFLAGS:
+               if (ifp->if_flags & IFF_UP) {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               error = ENETRESET;
+                       else
+                               cpsw_init(ifp);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               cpsw_stop(ifp);
+               }
+               break;
+       case SIOCSIFMEDIA:
+               ifr->ifr_media &= ~IFM_ETH_FMASK;
+               /* FALLTHROUGH */
+       case SIOCGIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+               break;
+       default:
+               error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+               break;
+       }
+       if (error == ENETRESET) {
+               if (ifp->if_flags & IFF_RUNNING)
+                       cpsw_init(ifp);
+               error = 0;
+       }
+
+       splx(s);
+
+       return error;
+}
+
+void
+cpsw_watchdog(struct ifnet *ifp)
+{
+       printf("%s: device timeout\n", ifp->if_xname);
+
+       ifp->if_oerrors++;
+       cpsw_init(ifp);
+       cpsw_start(ifp);
+}
+
+static int
+cpsw_mii_wait(struct cpsw_softc * const sc, int reg)
+{
+       u_int tries;
+
+       for(tries = 0; tries < 1000; tries++) {
+               if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg) & (1U << 31)) == 0)
+                       return 0;
+               delay(1);
+       }
+       return ETIMEDOUT;
+}
+
+int
+cpsw_mii_readreg(struct device *dev, int phy, int reg)
+{
+       struct cpsw_softc * const sc = (struct cpsw_softc *)dev;
+       uint32_t v;
+
+       if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+               return 0;
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0, (1U << 31) |
+           ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+       if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+               return 0;
+
+       v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0);
+       if (v & (1 << 29))
+               return v & 0xffff;
+       else
+               return 0;
+}
+
+void
+cpsw_mii_writereg(struct device *dev, int phy, int reg, int val)
+{
+       struct cpsw_softc * const sc = (struct cpsw_softc *)dev;
+       uint32_t v;
+
+       KASSERT((val & 0xffff0000UL) == 0);
+
+       if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+               goto out;
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0, (1U << 31) | (1 << 30) |
+           ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16) | val);
+
+       if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+               goto out;
+
+       v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0);
+       if ((v & (1 << 29)) == 0)
+out:
+               printf("%s error\n", __func__);
+
+}
+
+void
+cpsw_mii_statchg(struct device *self)
+{
+       return;
+}
+
+int
+cpsw_new_rxbuf(struct cpsw_softc * const sc, const u_int i)
+{
+       struct cpsw_ring_data * const rdp = sc->sc_rdp;
+       const u_int h = RXDESC_PREV(i);
+       struct cpsw_cpdma_bd bd;
+       struct mbuf *m;
+       int error = ENOBUFS;
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == NULL) {
+               goto reuse;
+       }
+
+       MCLGET(m, M_DONTWAIT);
+       if ((m->m_flags & M_EXT) == 0) {
+               m_freem(m);
+               goto reuse;
+       }
+
+       /* We have a new buffer, prepare it for the ring. */
+
+       if (rdp->rx_mb[i] != NULL)
+               bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]);
+
+       m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+       rdp->rx_mb[i] = m;
+
+       error = bus_dmamap_load_mbuf(sc->sc_bdt, rdp->rx_dm[i], rdp->rx_mb[i],
+           BUS_DMA_READ|BUS_DMA_NOWAIT);
+       if (error) {
+               printf("can't load rx DMA map %d: %d\n", i, error);
+       }
+
+       bus_dmamap_sync(sc->sc_bdt, rdp->rx_dm[i],
+           0, rdp->rx_dm[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+       error = 0;
+
+reuse:
+       /* (re-)setup the descriptor */
+       bd.next = 0;
+       bd.bufptr = rdp->rx_dm[i]->dm_segs[0].ds_addr;
+       bd.bufoff = 0;
+       bd.buflen = MIN(0x7ff, rdp->rx_dm[i]->dm_segs[0].ds_len);
+       bd.pktlen = 0;
+       bd.flags = CPDMA_BD_OWNER;
+
+       cpsw_set_rxdesc(sc, i, &bd);
+       /* and link onto ring */
+       cpsw_set_rxdesc_next(sc, h, cpsw_rxdesc_paddr(sc, i));
+
+       return error;
+}
+
+int
+cpsw_init(struct ifnet *ifp)
+{
+       struct cpsw_softc * const sc = ifp->if_softc;
+       struct arpcom *ac = &sc->sc_ac;
+       struct mii_data * const mii = &sc->sc_mii;
+       int i;
+
+       cpsw_stop(ifp);
+
+       sc->sc_txnext = 0;
+       sc->sc_txhead = 0;
+
+       /* Reset wrapper */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET) & 1);
+
+       /* Reset SS */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET) & 1);
+
+       /* Clear table (30) and enable ALE(31) and set passthrough (4) */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_CONTROL, (3 << 30) | 0x10);
+
+       /* Reset and init Sliver port 1 and 2 */
+       for (i = 0; i < 2; i++) {
+               /* Reset */
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i), 1);
+               while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i)) & 1);
+               /* Set Slave Mapping */
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_RX_PRI_MAP(i), 0x76543210);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_TX_PRI_MAP(i+1), 0x33221100);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_RX_MAXLEN(i), 0x5f2);
+               /* Set MAC Address */
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_SA_HI(i+1),
+                   ac->ac_enaddr[0] | (ac->ac_enaddr[1] << 8) |
+                   (ac->ac_enaddr[2] << 16) | (ac->ac_enaddr[3] << 24));
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_SA_LO(i+1),
+                   ac->ac_enaddr[4] | (ac->ac_enaddr[5] << 8));
+
+               /* Set MACCONTROL for ports 0,1: FULLDUPLEX(0), GMII_EN(5),
+                  IFCTL_A(15), IFCTL_B(16) FIXME */
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_MACCONTROL(i),
+                   1 | (1<<5) | (1<<15) | (1<<16));
+
+               /* Set ALE port to forwarding(3) on the active port */
+               if (i == sc->sc_active_port)
+                       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_PORTCTL(i+1), 3);
+       }
+
+       /* Set Host Port Mapping */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+
+       /* Set ALE port to forwarding(3) */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_PORTCTL(0), 3);
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_PTYPE, 0);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_STAT_PORT_EN, 7);
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET) & 1);
+
+       for (i = 0; i < 8; i++) {
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(i), 0);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(i), 0);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(i), 0);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(i), 0);
+       }
+
+       bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_txdescs, 0, 0,
+           CPSW_CPPI_RAM_TXDESCS_SIZE/4);
+
+       sc->sc_txhead = 0;
+       sc->sc_txnext = 0;
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_FREEBUFFER(0), 0);
+
+       bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, 0, 0,
+           CPSW_CPPI_RAM_RXDESCS_SIZE/4);
+
+       /* Initialize RX Buffer Descriptors */
+       cpsw_set_rxdesc_next(sc, RXDESC_PREV(0), 0);
+       for (i = 0; i < CPSW_NRXDESCS; i++) {
+               cpsw_new_rxbuf(sc, i);
+       }
+       sc->sc_rxhead = 0;
+
+       /* align layer 3 header to 32-bit */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_BUFFER_OFFSET, ETHER_ALIGN);
+
+       /* Clear all interrupt Masks */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+
+       /* Enable TX & RX DMA */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CONTROL, 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CONTROL, 1);
+
+       /* Enable interrupt pacing for C0 RX/TX (IMAX set to max intr/ms allowed) */
+#define CPSW_VBUSP_CLK_MHZ     2400    /* hardcoded for BBB */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_IMAX(0), 2);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_IMAX(0), 2);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_INT_CONTROL, 3 << 16 | CPSW_VBUSP_CLK_MHZ/4);
+
+       /* Enable TX and RX interrupt receive for core 0 */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_EN(0), 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_EN(0), 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_EN(0), 0x1F);
+
+       /* Enable host Error Interrupt */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTMASK_SET, 2);
+
+       /* Enable interrupts for TX and RX Channel 0 */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_SET, 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_SET, 1);
+
+       /* Ack stalled irqs */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
+
+       cpsw_mdio_init(sc);
+
+       mii_mediachg(mii);
+
+       /* Write channel 0 RX HDP */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0), cpsw_rxdesc_paddr(sc, 0));
+       sc->sc_rxrun = true;
+       sc->sc_rxeoq = false;
+
+       sc->sc_txrun = true;
+       sc->sc_txeoq = true;
+
+       ifp->if_flags |= IFF_RUNNING;
+       ifq_clr_oactive(&ifp->if_snd);
+
+       timeout_add_sec(&sc->sc_tick, 1);
+
+       return 0;
+}
+
+void
+cpsw_stop(struct ifnet *ifp)
+{
+       struct cpsw_softc * const sc = ifp->if_softc;
+       struct cpsw_ring_data * const rdp = sc->sc_rdp;
+       u_int i;
+
+#if 0
+       /* XXX find where disable comes from */
+       printf("%s: ifp %p disable %d\n", __func__, ifp, disable);
+#endif
+       if ((ifp->if_flags & IFF_RUNNING) == 0)
+               return;
+
+       timeout_del(&sc->sc_tick);
+
+       mii_down(&sc->sc_mii);
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_CLEAR, 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_CLEAR, 1);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_EN(0), 0x0);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_EN(0), 0x0);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_EN(0), 0x1F);
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_TEARDOWN, 0);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_TEARDOWN, 0);
+       i = 0;
+       while ((sc->sc_txrun || sc->sc_rxrun) && i < 10000) {
+               delay(10);
+               if ((sc->sc_txrun == true) && cpsw_txintr(sc) == 0)
+                       sc->sc_txrun = false;
+               if ((sc->sc_rxrun == true) && cpsw_rxintr(sc) == 0)
+                       sc->sc_rxrun = false;
+               i++;
+       }
+       /* printf("%s toredown complete in %u\n", __func__, i); */
+
+       /* Reset wrapper */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET) & 1);
+
+       /* Reset SS */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET) & 1);
+
+       for (i = 0; i < 2; i++) {
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i), 1);
+               while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i)) & 1);
+       }
+
+       /* Reset CPDMA */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET, 1);
+       while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET) & 1);
+
+       /* Release any queued transmit buffers. */
+       for (i = 0; i < CPSW_NTXDESCS; i++) {
+               bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[i]);
+               m_freem(rdp->tx_mb[i]);
+               rdp->tx_mb[i] = NULL;
+       }
+
+       ifp->if_flags &= ~IFF_RUNNING;
+       ifp->if_timer = 0;
+       ifq_clr_oactive(&ifp->if_snd);
+
+       /* XXX Not sure what this is doing calling disable here
+           where is disable set?
+       */
+#if 0
+       if (!disable)
+               return;
+#endif
+
+       for (i = 0; i < CPSW_NRXDESCS; i++) {
+               bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]);
+               m_freem(rdp->rx_mb[i]);
+               rdp->rx_mb[i] = NULL;
+       }
+}
+
+int
+cpsw_rxthintr(void *arg)
+{
+       struct cpsw_softc * const sc = arg;
+
+       /* this won't deassert the interrupt though */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH);
+
+       return 1;
+}
+
+int
+cpsw_rxintr(void *arg)
+{
+       struct cpsw_softc * const sc = arg;
+       struct ifnet * const ifp = &sc->sc_ac.ac_if;
+       struct cpsw_ring_data * const rdp = sc->sc_rdp;
+       struct cpsw_cpdma_bd bd;
+       bus_dmamap_t dm;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct mbuf *m;
+       u_int i;
+       u_int len, off;
+
+       sc->sc_rxeoq = false;
+       
+       for (;;) {
+               KASSERT(sc->sc_rxhead < CPSW_NRXDESCS);
+
+               i = sc->sc_rxhead;
+               dm = rdp->rx_dm[i];
+               m = rdp->rx_mb[i];
+
+               KASSERT(dm != NULL);
+               KASSERT(m != NULL);
+
+               cpsw_get_rxdesc(sc, i, &bd);
+
+               if (bd.flags & CPDMA_BD_OWNER)
+                       break;
+
+               if (bd.flags & CPDMA_BD_TDOWNCMPLT) {
+                       sc->sc_rxrun = false;
+                       goto done;
+               }
+
+               bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize,
+                   BUS_DMASYNC_POSTREAD);
+
+               if (cpsw_new_rxbuf(sc, i) != 0) {
+                       /* drop current packet, reuse buffer for new */
+                       ifp->if_ierrors++;
+                       goto next;
+               }
+
+               if ((bd.flags & (CPDMA_BD_SOP|CPDMA_BD_EOP)) !=
+                   (CPDMA_BD_SOP|CPDMA_BD_EOP)) {
+                       if (bd.flags & CPDMA_BD_SOP) {
+                               printf("cpsw: rx packet too large\n");
+                               ifp->if_ierrors++;
+                       }
+                       m_freem(m);
+                       goto next;
+               }
+
+               off = bd.bufoff;
+               len = bd.pktlen;
+
+               if (bd.flags & CPDMA_BD_PASSCRC)
+                       len -= ETHER_CRC_LEN;
+
+               m->m_pkthdr.len = m->m_len = len;
+               m->m_data += off;
+
+               ml_enqueue(&ml, m);
+
+next:
+               sc->sc_rxhead = RXDESC_NEXT(sc->sc_rxhead);
+               if (bd.flags & CPDMA_BD_EOQ) {
+                       sc->sc_rxeoq = true;
+                       sc->sc_rxrun = false;
+               }
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(0),
+                   cpsw_rxdesc_paddr(sc, i));
+       }
+
+       if (sc->sc_rxeoq) {
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0),
+                                 cpsw_rxdesc_paddr(sc, sc->sc_rxhead));
+               sc->sc_rxrun = true;
+               sc->sc_rxeoq = false;
+       }
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR,
+           CPSW_INTROFF_RX);
+
+done:
+       if_input(ifp, &ml);
+
+       return 1;
+}
+
+void
+cpsw_tick(void *arg)
+{
+       struct cpsw_softc *sc = arg;
+       int s;
+
+       s = splnet();
+       mii_tick(&sc->sc_mii);
+       splx(s);
+
+       timeout_add_sec(&sc->sc_tick, 1);
+}
+
+int
+cpsw_txintr(void *arg)
+{
+       struct cpsw_softc * const sc = arg;
+       struct ifnet * const ifp = &sc->sc_ac.ac_if;
+       struct cpsw_ring_data * const rdp = sc->sc_rdp;
+       struct cpsw_cpdma_bd bd;
+       bool handled = false;
+       uint32_t tx0_cp;
+       u_int cpi;
+
+       KASSERT(sc->sc_txrun);
+
+       tx0_cp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
+
+       if (tx0_cp == 0xfffffffc) {
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0), 0xfffffffc);
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0), 0);
+               sc->sc_txrun = false;
+               return 0;
+       }
+
+       for (;;) {
+               tx0_cp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
+               cpi = (tx0_cp - sc->sc_txdescs_pa) /
+                   sizeof(struct cpsw_cpdma_bd);
+               KASSERT(sc->sc_txhead < CPSW_NTXDESCS);
+
+               cpsw_get_txdesc(sc, sc->sc_txhead, &bd);
+
+               if (bd.buflen == 0) {
+                       /* Debugger(); */
+               }
+
+               if ((bd.flags & CPDMA_BD_SOP) == 0)
+                       goto next;
+
+               if (bd.flags & CPDMA_BD_OWNER) {
+                       printf("pwned %x %x %x\n", cpi, sc->sc_txhead,
+                           sc->sc_txnext);
+                       break;
+               }
+
+               if (bd.flags & CPDMA_BD_TDOWNCMPLT) {
+                       sc->sc_txrun = false;
+                       return 1;
+               }
+
+               bus_dmamap_sync(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead],
+                   0, rdp->tx_dm[sc->sc_txhead]->dm_mapsize,
+                   BUS_DMASYNC_POSTWRITE);
+               bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead]);
+
+               m_freem(rdp->tx_mb[sc->sc_txhead]);
+               rdp->tx_mb[sc->sc_txhead] = NULL;
+
+               ifp->if_opackets++;
+
+               handled = true;
+
+               ifq_clr_oactive(&ifp->if_snd);
+
+next:
+               if ((bd.flags & (CPDMA_BD_EOP|CPDMA_BD_EOQ)) ==
+                   (CPDMA_BD_EOP|CPDMA_BD_EOQ))
+                       sc->sc_txeoq = true;
+
+               if (sc->sc_txhead == cpi) {
+                       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0),
+                           cpsw_txdesc_paddr(sc, cpi));
+                       sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead);
+                       break;
+               }
+               sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead);
+               if (sc->sc_txeoq == true)
+                       break;
+       }
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
+
+       if ((sc->sc_txnext != sc->sc_txhead) && sc->sc_txeoq) {
+               if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0)) == 0) {
+                       sc->sc_txeoq = false;
+                       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0),
+                           cpsw_txdesc_paddr(sc, sc->sc_txhead));
+               }
+       }
+
+       if (handled && sc->sc_txnext == sc->sc_txhead)
+               ifp->if_timer = 0;
+
+       if (handled)
+               cpsw_start(ifp);
+
+       return handled;
+}
+
+int
+cpsw_miscintr(void *arg)
+{
+       struct cpsw_softc * const sc = arg;
+       uint32_t miscstat;
+       uint32_t dmastat;
+       uint32_t stat;
+
+       miscstat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_STAT(0));
+       printf("%s %x FIRE\n", __func__, miscstat);
+
+       if (miscstat & CPSW_MISC_HOST_PEND) {
+               /* Host Error */
+               dmastat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTSTAT_MASKED);
+               printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
+
+               printf("rxhead %02x\n", sc->sc_rxhead);
+
+               stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMASTATUS);
+               printf("CPSW_CPDMA_DMASTATUS %x\n", stat);
+               stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0));
+               printf("CPSW_CPDMA_TX0_HDP %x\n", stat);
+               stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
+               printf("CPSW_CPDMA_TX0_CP %x\n", stat);
+               stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0));
+               printf("CPSW_CPDMA_RX0_HDP %x\n", stat);
+               stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(0));
+               printf("CPSW_CPDMA_RX0_CP %x\n", stat);
+
+               /* Debugger(); */
+
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTMASK_CLEAR, dmastat);
+               dmastat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTSTAT_MASKED);
+               printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
+       }
+
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
+
+       return 1;
+}
diff --git a/if_cpswreg.h b/if_cpswreg.h
new file mode 100644 (file)
index 0000000..98ff229
--- /dev/null
@@ -0,0 +1,146 @@
+/* $OpenBSD: if_cpswreg.h,v 1.6 2016/03/02 01:31:41 canacar Exp $ */
+
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _IF_CPSWREG_H
+#define        _IF_CPSWREG_H
+
+#define CPSW_SS_OFFSET                 0x0000
+#define CPSW_SS_IDVER                  (CPSW_SS_OFFSET + 0x00)
+#define  CPSW_SS_IDVER_RTL(_r)                 (((_r) >> 11) & 0x1f)
+#define  CPSW_SS_IDVER_MAJ(_r)                 (((_r) >> 8) & 0x7)
+#define  CPSW_SS_IDVER_MIN(_r)                 ((_r) & 0xff)
+#define CPSW_SS_SOFT_RESET             (CPSW_SS_OFFSET + 0x08)
+#define CPSW_SS_STAT_PORT_EN           (CPSW_SS_OFFSET + 0x0C)
+#define CPSW_SS_PTYPE                  (CPSW_SS_OFFSET + 0x10)
+
+#define CPSW_PORT_OFFSET               0x0100
+#define CPSW_PORT_P_TX_PRI_MAP(p)      (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
+#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP  (CPSW_PORT_OFFSET + 0x01C)
+#define CPSW_PORT_P0_CPDMA_RX_CH_MAP   (CPSW_PORT_OFFSET + 0x020)
+#define CPSW_PORT_P_SA_LO(p)           (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100))
+#define CPSW_PORT_P_SA_HI(p)           (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100))
+
+#define CPSW_CPDMA_OFFSET              0x0800
+#define CPSW_CPDMA_TX_CONTROL          (CPSW_CPDMA_OFFSET + 0x04)
+#define CPSW_CPDMA_TX_TEARDOWN         (CPSW_CPDMA_OFFSET + 0x08)
+#define CPSW_CPDMA_RX_CONTROL          (CPSW_CPDMA_OFFSET + 0x14)
+#define CPSW_CPDMA_RX_TEARDOWN         (CPSW_CPDMA_OFFSET + 0x18)
+#define CPSW_CPDMA_SOFT_RESET          (CPSW_CPDMA_OFFSET + 0x1c)
+#define CPSW_CPDMA_DMACONTROL          (CPSW_CPDMA_OFFSET + 0x20)
+#define CPSW_CPDMA_DMASTATUS           (CPSW_CPDMA_OFFSET + 0x24)
+#define CPSW_CPDMA_RX_BUFFER_OFFSET    (CPSW_CPDMA_OFFSET + 0x28)
+#define CPSW_CPDMA_TX_INTSTAT_RAW      (CPSW_CPDMA_OFFSET + 0x80)
+#define CPSW_CPDMA_TX_INTSTAT_MASKED   (CPSW_CPDMA_OFFSET + 0x84)
+#define CPSW_CPDMA_TX_INTMASK_SET      (CPSW_CPDMA_OFFSET + 0x88)
+#define CPSW_CPDMA_TX_INTMASK_CLEAR    (CPSW_CPDMA_OFFSET + 0x8C)
+#define CPSW_CPDMA_CPDMA_EOI_VECTOR    (CPSW_CPDMA_OFFSET + 0x94)
+#define CPSW_CPDMA_RX_INTSTAT_RAW      (CPSW_CPDMA_OFFSET + 0xA0)
+#define CPSW_CPDMA_RX_INTSTAT_MASKED   (CPSW_CPDMA_OFFSET + 0xA4)
+#define CPSW_CPDMA_RX_INTMASK_SET      (CPSW_CPDMA_OFFSET + 0xA8)
+#define CPSW_CPDMA_RX_INTMASK_CLEAR    (CPSW_CPDMA_OFFSET + 0xAc)
+#define CPSW_CPDMA_DMA_INTSTAT_RAW     (CPSW_CPDMA_OFFSET + 0xB0)
+#define CPSW_CPDMA_DMA_INTSTAT_MASKED  (CPSW_CPDMA_OFFSET + 0xB4)
+#define CPSW_CPDMA_DMA_INTMASK_SET     (CPSW_CPDMA_OFFSET + 0xB8)
+#define CPSW_CPDMA_DMA_INTMASK_CLEAR   (CPSW_CPDMA_OFFSET + 0xBC)
+#define CPSW_CPDMA_RX_FREEBUFFER(p)    (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
+
+#define CPSW_STATS_OFFSET              0x0900
+
+#define CPSW_STATERAM_OFFSET           0x0A00
+#define CPSW_CPDMA_TX_HDP(p)           (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_HDP(p)           (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_CP(p)            (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_CP(p)            (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04))
+
+#define CPSW_CPTS_OFFSET               0x0C00
+
+#define CPSW_ALE_OFFSET                        0x0D00
+#define CPSW_ALE_CONTROL               (CPSW_ALE_OFFSET + 0x08)
+#define CPSW_ALE_TBLCTL                        (CPSW_ALE_OFFSET + 0x20)
+#define CPSW_ALE_TBLW2                 (CPSW_ALE_OFFSET + 0x34)
+#define CPSW_ALE_TBLW1                 (CPSW_ALE_OFFSET + 0x38)
+#define CPSW_ALE_TBLW0                 (CPSW_ALE_OFFSET + 0x3C)
+#define CPSW_ALE_PORTCTL(p)            (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
+
+#define CPSW_SL_OFFSET                 0x0D80
+#define CPSW_SL_MACCONTROL(p)          (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
+#define CPSW_SL_SOFT_RESET(p)          (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
+#define CPSW_SL_RX_MAXLEN(p)           (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
+#define CPSW_SL_RX_PRI_MAP(p)          (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24)
+
+#define MDIO_OFFSET                    0x1000
+#define MDIOCONTROL                    (MDIO_OFFSET + 0x04)
+#define MDIOALIVE                      (MDIO_OFFSET + 0x08)
+#define MDIOLINK                       (MDIO_OFFSET + 0x0C)
+#define MDIOUSERACCESS0                        (MDIO_OFFSET + 0x80)
+#define MDIOUSERPHYSEL0                        (MDIO_OFFSET + 0x84)
+
+#define CPSW_WR_OFFSET                 0x1200
+#define CPSW_WR_SOFT_RESET             (CPSW_WR_OFFSET + 0x04)
+#define CPSW_WR_CONTROL                        (CPSW_WR_OFFSET + 0x08)
+#define CPSW_WR_INT_CONTROL            (CPSW_WR_OFFSET + 0x0c)
+#define CPSW_WR_C_RX_THRESH_EN(p)      (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10)
+#define CPSW_WR_C_RX_EN(p)             (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14)
+#define CPSW_WR_C_TX_EN(p)             (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18)
+#define CPSW_WR_C_MISC_EN(p)           (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C)
+#define CPSW_WR_C_RX_THRESH_STAT(p)    (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40)
+#define CPSW_WR_C_RX_STAT(p)           (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
+#define CPSW_WR_C_TX_STAT(p)           (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
+#define CPSW_WR_C_MISC_STAT(p)         (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
+#define CPSW_WR_C_RX_IMAX(p)           (CPSW_WR_OFFSET + (0x08 * (p)) + 0x70)
+#define CPSW_WR_C_TX_IMAX(p)           (CPSW_WR_OFFSET + (0x08 * (p)) + 0x74)
+#define  CPSW_MISC_HOST_PEND                   0x0004
+
+#define CPSW_CPPI_RAM_OFFSET           0x2000
+
+#define CPDMA_BD_SOP                   (1<<15)
+#define CPDMA_BD_EOP                   (1<<14)
+#define CPDMA_BD_OWNER                 (1<<13)
+#define CPDMA_BD_EOQ                   (1<<12)
+#define CPDMA_BD_TDOWNCMPLT            (1<<11)
+#define CPDMA_BD_PASSCRC               (1<<10)
+#define CPDMA_BD_PKT_ERR_MASK          (3<< 4)
+
+struct cpsw_cpdma_bd {
+       uint32_t next;
+       uint32_t bufptr;
+       uint16_t buflen;
+       uint16_t bufoff;
+       uint16_t pktlen;
+       uint16_t flags;
+};
+
+/* Interrupt offsets */
+#define CPSW_INTROFF_RXTH      0
+#define CPSW_INTROFF_RX                1
+#define CPSW_INTROFF_TX                2
+#define CPSW_INTROFF_MISC      3
+
+#endif /*_IF_CPSWREG_H */
diff --git a/intc.c b/intc.c
new file mode 100644 (file)
index 0000000..335f9e6
--- /dev/null
+++ b/intc.c
@@ -0,0 +1,423 @@
+/* $OpenBSD: intc.c,v 1.4 2016/01/31 00:14:50 jsg Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <machine/bus.h>
+#include <armv7/armv7/armv7var.h>
+#include "intc.h"
+
+#define INTC_NUM_IRQ intc_nirq
+#define INTC_NUM_BANKS (intc_nirq/32)
+#define INTC_MAX_IRQ 128
+#define INTC_MAX_BANKS (INTC_MAX_IRQ/32)
+
+/* registers */
+#define        INTC_REVISION           0x00    /* R */
+#define        INTC_SYSCONFIG          0x10    /* RW */
+#define                INTC_SYSCONFIG_AUTOIDLE         0x1
+#define                INTC_SYSCONFIG_SOFTRESET        0x2
+#define        INTC_SYSSTATUS          0x14    /* R */
+#define                INTC_SYSSYSTATUS_RESETDONE      0x1
+#define        INTC_SIR_IRQ            0x40    /* R */ 
+#define        INTC_SIR_FIQ            0x44    /* R */
+#define        INTC_CONTROL            0x48    /* RW */
+#define                INTC_CONTROL_NEWIRQ     0x1
+#define                INTC_CONTROL_NEWFIQ     0x2
+#define                INTC_CONTROL_GLOBALMASK 0x1
+#define        INTC_PROTECTION         0x4c    /* RW */
+#define                INTC_PROTECTION_PROT 1  /* only privileged mode */
+#define        INTC_IDLE               0x50    /* RW */
+
+#define INTC_IRQ_TO_REG(i)     (((i) >> 5) & 0x3)
+#define INTC_IRQ_TO_REGi(i)    ((i) & 0x1f)
+#define        INTC_ITRn(i)            0x80+(0x20*i)+0x00      /* R */
+#define        INTC_MIRn(i)            0x80+(0x20*i)+0x04      /* RW */
+#define        INTC_CLEARn(i)          0x80+(0x20*i)+0x08      /* RW */
+#define        INTC_SETn(i)            0x80+(0x20*i)+0x0c      /* RW */
+#define        INTC_ISR_SETn(i)        0x80+(0x20*i)+0x10      /* RW */
+#define        INTC_ISR_CLEARn(i)      0x80+(0x20*i)+0x14      /* RW */
+#define INTC_PENDING_IRQn(i)   0x80+(0x20*i)+0x18      /* R */
+#define INTC_PENDING_FIQn(i)   0x80+(0x20*i)+0x1c      /* R */
+
+#define INTC_ILRn(i)           0x100+(4*i)
+#define                INTC_ILR_IRQ    0x0             /* not of FIQ */
+#define                INTC_ILR_FIQ    0x1
+#define                INTC_ILR_PRIs(pri)      ((pri) << 2)
+#define                INTC_ILR_PRI(reg)       (((reg) >> 2) & 0x2f)
+#define                INTC_MIN_PRI    63
+#define                INTC_STD_PRI    32
+#define                INTC_MAX_PRI    0
+
+struct intrhand {
+       TAILQ_ENTRY(intrhand) ih_list;  /* link on intrq list */
+       int (*ih_func)(void *);         /* handler */
+       void *ih_arg;                   /* arg for handler */
+       int ih_ipl;                     /* IPL_* */
+       int ih_irq;                     /* IRQ number */
+       struct evcount  ih_count;
+       char *ih_name;
+};
+
+struct intrq {
+       TAILQ_HEAD(, intrhand) iq_list; /* handler list */
+       int iq_irq;                     /* IRQ to mask while handling */
+       int iq_levels;                  /* IPL_*'s this IRQ has */
+       int iq_ist;                     /* share type */
+};
+
+volatile int softint_pending;
+
+struct intrq intc_handler[INTC_MAX_IRQ];
+u_int32_t intc_smask[NIPL];
+u_int32_t intc_imask[INTC_MAX_BANKS][NIPL];
+
+bus_space_tag_t                intc_iot;
+bus_space_handle_t     intc_ioh;
+int                    intc_nirq;
+
+void   intc_attach(struct device *, struct device *, void *);
+int    intc_spllower(int new);
+int    intc_splraise(int new);
+void   intc_setipl(int new);
+void   intc_calc_mask(void);
+
+struct cfattach        intc_ca = {
+       sizeof (struct device), NULL, intc_attach
+};
+
+struct cfdriver intc_cd = {
+       NULL, "intc", DV_DULL
+};
+
+int intc_attached = 0;
+
+void
+intc_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       int i;
+       u_int32_t rev;
+
+       intc_iot = aa->aa_iot;
+       if (bus_space_map(intc_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &intc_ioh))
+               panic("intc_attach: bus_space_map failed!");
+
+       rev = bus_space_read_4(intc_iot, intc_ioh, INTC_REVISION);
+
+       printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+
+       /* software reset of the part? */
+       /* set protection bit (kernel only)? */
+#if 0
+       bus_space_write_4(intc_iot, intc_ioh, INTC_PROTECTION,
+            INTC_PROTECTION_PROT);
+#endif
+
+       /* enable interface clock power saving mode */
+       bus_space_write_4(intc_iot, intc_ioh, INTC_SYSCONFIG,
+           INTC_SYSCONFIG_AUTOIDLE);
+
+       switch (board_id) {
+       case BOARD_ID_AM335X_BEAGLEBONE:
+               intc_nirq = 128;
+               break;
+       default:
+               intc_nirq = 96;
+               break;
+       }
+
+       /* mask all interrupts */
+       for (i = 0; i < INTC_NUM_BANKS; i++)
+               bus_space_write_4(intc_iot, intc_ioh, INTC_MIRn(i), 0xffffffff);
+
+       for (i = 0; i < INTC_NUM_IRQ; i++) {
+               bus_space_write_4(intc_iot, intc_ioh, INTC_ILRn(i),
+                   INTC_ILR_PRIs(INTC_MIN_PRI)|INTC_ILR_IRQ);
+
+               TAILQ_INIT(&intc_handler[i].iq_list);
+       }
+
+       intc_calc_mask();
+       bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL,
+           INTC_CONTROL_NEWIRQ);
+
+       intc_attached = 1;
+
+       /* insert self as interrupt handler */
+       arm_set_intr_handler(intc_splraise, intc_spllower, intc_splx,
+           intc_setipl,
+           intc_intr_establish, intc_intr_disestablish, intc_intr_string,
+           intc_irq_handler);
+
+       intc_setipl(IPL_HIGH);  /* XXX ??? */
+       enable_interrupts(PSR_I);
+}
+
+void
+intc_calc_mask(void)
+{
+       struct cpu_info *ci = curcpu();
+       int irq;
+       struct intrhand *ih;
+       int i;
+
+       for (irq = 0; irq < INTC_NUM_IRQ; irq++) {
+               int max = IPL_NONE;
+               int min = IPL_HIGH;
+               TAILQ_FOREACH(ih, &intc_handler[irq].iq_list, ih_list) {
+                       if (ih->ih_ipl > max)
+                               max = ih->ih_ipl;
+
+                       if (ih->ih_ipl < min)
+                               min = ih->ih_ipl;
+               }
+
+               intc_handler[irq].iq_irq = max;
+
+               if (max == IPL_NONE)
+                       min = IPL_NONE;
+
+#ifdef DEBUG_INTC
+               if (min != IPL_NONE) {
+                       printf("irq %d to block at %d %d reg %d bit %d\n",
+                           irq, max, min, INTC_IRQ_TO_REG(irq),
+                           INTC_IRQ_TO_REGi(irq));
+               }
+#endif
+               /* Enable interrupts at lower levels, clear -> enable */
+               for (i = 0; i < min; i++)
+                       intc_imask[INTC_IRQ_TO_REG(irq)][i] &=
+                           ~(1 << INTC_IRQ_TO_REGi(irq));
+               for (; i <= IPL_HIGH; i++)
+                       intc_imask[INTC_IRQ_TO_REG(irq)][i] |=
+                           1 << INTC_IRQ_TO_REGi(irq);
+               /* XXX - set enable/disable, priority */ 
+               bus_space_write_4(intc_iot, intc_ioh, INTC_ILRn(irq),
+                   INTC_ILR_PRIs(NIPL-max)|INTC_ILR_IRQ);
+       }
+       arm_init_smask();
+       intc_setipl(ci->ci_cpl);
+}
+
+void
+intc_splx(int new)
+{
+       struct cpu_info *ci = curcpu();
+       intc_setipl(new);
+
+       if (ci->ci_ipending & arm_smask[ci->ci_cpl])
+               arm_do_pending_intr(ci->ci_cpl);
+}
+
+int
+intc_spllower(int new)
+{
+       struct cpu_info *ci = curcpu();
+       int old = ci->ci_cpl;
+       intc_splx(new);
+       return (old);
+}
+
+int
+intc_splraise(int new)
+{
+       struct cpu_info *ci = curcpu();
+       int old;
+       old = ci->ci_cpl;
+
+       /*
+        * setipl must always be called because there is a race window
+        * where the variable is updated before the mask is set
+        * an interrupt occurs in that window without the mask always
+        * being set, the hardware might not get updated on the next
+        * splraise completely messing up spl protection.
+        */
+       if (old > new)
+               new = old;
+
+       intc_setipl(new);
+  
+       return (old);
+}
+
+void
+intc_setipl(int new)
+{
+       struct cpu_info *ci = curcpu();
+       int i;
+       int psw;
+       if (intc_attached == 0)
+               return;
+
+       psw = disable_interrupts(PSR_I);
+#if 0
+       {
+               volatile static int recursed = 0;
+               if (recursed == 0) {
+                       recursed = 1;
+                       if (new != 12) 
+                               printf("setipl %d\n", new);
+                       recursed = 0;
+               }
+       }
+#endif
+       ci->ci_cpl = new;
+       for (i = 0; i < INTC_NUM_BANKS; i++)
+               bus_space_write_4(intc_iot, intc_ioh,
+                   INTC_MIRn(i), intc_imask[i][new]);
+       bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL,
+           INTC_CONTROL_NEWIRQ);
+       restore_interrupts(psw);
+}
+
+void
+intc_intr_bootstrap(vaddr_t addr)
+{
+       int i, j;
+       extern struct bus_space armv7_bs_tag;
+       intc_iot = &armv7_bs_tag;
+       intc_ioh = addr;
+       for (i = 0; i < INTC_NUM_BANKS; i++)
+               for (j = 0; j < NIPL; j++)
+                       intc_imask[i][j] = 0xffffffff;
+}
+
+void
+intc_irq_handler(void *frame)
+{
+       int irq, pri, s;
+       struct intrhand *ih;
+       void *arg;
+
+       irq = bus_space_read_4(intc_iot, intc_ioh, INTC_SIR_IRQ);
+#ifdef DEBUG_INTC
+       printf("irq %d fired\n", irq);
+#endif
+
+       pri = intc_handler[irq].iq_irq;
+       s = intc_splraise(pri);
+       TAILQ_FOREACH(ih, &intc_handler[irq].iq_list, ih_list) {
+               if (ih->ih_arg != 0)
+                       arg = ih->ih_arg;
+               else
+                       arg = frame;
+
+               if (ih->ih_func(arg)) 
+                       ih->ih_count.ec_count++;
+
+       }
+       bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL,
+           INTC_CONTROL_NEWIRQ);
+
+       intc_splx(s);
+}
+
+void *
+intc_intr_establish(int irqno, int level, int (*func)(void *),
+    void *arg, char *name)
+{
+       int psw;
+       struct intrhand *ih;
+
+       if (irqno < 0 || irqno >= INTC_NUM_IRQ)
+               panic("intc_intr_establish: bogus irqnumber %d: %s",
+                    irqno, name);
+       psw = disable_interrupts(PSR_I);
+
+       /* no point in sleeping unless someone can free memory. */
+       ih = (struct intrhand *)malloc (sizeof *ih, M_DEVBUF,
+           cold ? M_NOWAIT : M_WAITOK);
+       if (ih == NULL)
+               panic("intr_establish: can't malloc handler info");
+       ih->ih_func = func;
+       ih->ih_arg = arg;
+       ih->ih_ipl = level;
+       ih->ih_irq = irqno;
+       ih->ih_name = name;
+
+       TAILQ_INSERT_TAIL(&intc_handler[irqno].iq_list, ih, ih_list);
+
+       if (name != NULL)
+               evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+#ifdef DEBUG_INTC
+       printf("intc_intr_establish irq %d level %d [%s]\n", irqno, level,
+           name);
+#endif
+       intc_calc_mask();
+       
+       restore_interrupts(psw);
+       return (ih);
+}
+
+void
+intc_intr_disestablish(void *cookie)
+{
+       int psw;
+       struct intrhand *ih = cookie;
+       int irqno = ih->ih_irq;
+       psw = disable_interrupts(PSR_I);
+       TAILQ_REMOVE(&intc_handler[irqno].iq_list, ih, ih_list);
+       if (ih->ih_name != NULL)
+               evcount_detach(&ih->ih_count);
+       free(ih, M_DEVBUF, 0);
+       restore_interrupts(psw);
+}
+
+const char *
+intc_intr_string(void *cookie)
+{
+       return "huh?";
+}
+
+
+#if 0
+int intc_tst(void *a);
+
+int
+intc_tst(void *a)
+{
+       printf("inct_tst called\n");
+       bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_CLEARn(0), 2);
+       return 1;
+}
+
+void intc_test(void);
+void intc_test(void)
+{
+       void * ih;
+       printf("about to register handler\n");
+       ih = intc_intr_establish(1, IPL_BIO, intc_tst, NULL, "intctst");
+
+       printf("about to set bit\n");
+       bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_SETn(0), 2);
+
+       printf("about to clear bit\n");
+       bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_CLEARn(0), 2);
+
+       printf("about to remove handler\n");
+       intc_intr_disestablish(ih);
+
+       printf("done\n");
+}
+#endif
diff --git a/intc.h b/intc.h
new file mode 100644 (file)
index 0000000..bc0a59f
--- /dev/null
+++ b/intc.h
@@ -0,0 +1,74 @@
+/*     $OpenBSD: intc.h,v 1.2 2014/03/29 18:09:28 guenther Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _OMAPINTC_INTR_H_
+#define _OMAPINTC_INTR_H_
+
+#ifndef _LOCORE
+
+#include <arm/armreg.h>
+#include <arm/cpufunc.h>
+#include <machine/intr.h>
+#include <arm/softintr.h>
+
+extern volatile int current_spl_level;
+extern volatile int softint_pending;
+void intc_do_pending(void);
+
+#define SI_TO_IRQBIT(si)  (1U<<(si))
+void intc_setipl(int new);
+void intc_splx(int new);
+int intc_splraise(int ipl);
+int intc_spllower(int ipl);
+void intc_setsoftintr(int si);
+
+/*
+ * An useful function for interrupt handlers.
+ * XXX: This shouldn't be here.
+ */
+static __inline int
+find_first_bit( uint32_t bits )
+{
+       int count;
+
+       /* since CLZ is available only on ARMv5, this isn't portable
+        * to all ARM CPUs.  This file is for OMAPINTC processor. 
+        */
+       asm( "clz %0, %1" : "=r" (count) : "r" (bits) );
+       return 31-count;
+}
+
+
+/*
+ * This function *MUST* be called very early on in a port's
+ * initarm() function, before ANY spl*() functions are called.
+ *
+ * The parameter is the virtual address of the OMAPINTC's Interrupt
+ * Controller registers.
+ */
+void intc_intr_bootstrap(vaddr_t);
+
+void intc_irq_handler(void *);
+void *intc_intr_establish(int irqno, int level, int (*func)(void *),
+    void *cookie, char *name);
+void intc_intr_disestablish(void *cookie);
+const char *intc_intr_string(void *cookie);
+
+#endif /* ! _LOCORE */
+
+#endif /* _OMAPINTC_INTR_H_ */
+
diff --git a/omap.c b/omap.c
new file mode 100644 (file)
index 0000000..9cb946d
--- /dev/null
+++ b/omap.c
@@ -0,0 +1,189 @@
+/* $OpenBSD: omap.c,v 1.9 2016/05/02 15:27:24 patrick Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.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/systm.h>
+
+#include <machine/bus.h>
+
+#include <arm/mainbus/mainbus.h>
+#include <armv7/armv7/armv7var.h>
+
+int    omap_match(struct device *, void *, void *);
+void   omap3_init();
+void   omap4_init();
+void   am335x_init();
+
+struct cfattach omap_ca = {
+       sizeof(struct armv7_softc), omap_match, armv7_attach
+};
+
+struct cfdriver omap_cd = {
+       NULL, "omap", DV_DULL
+};
+
+struct board_dev beagleboard_devs[] = {
+       { "prcm",       0 },
+       { "intc",       0 },
+       { "gptimer",    0 },
+       { "gptimer",    1 },
+       { "omdog",      0 },
+       { "omgpio",     0 },
+       { "omgpio",     1 },
+       { "omgpio",     2 },
+       { "omgpio",     3 },
+       { "omgpio",     4 },
+       { "omgpio",     5 },
+       { "ommmc",      0 },            /* HSMMC1 */
+       { "com",        2 },            /* UART3 */
+       { NULL,         0 }
+};
+
+struct board_dev beaglebone_devs[] = {
+       { "prcm",       0 },
+       { "sitaracm",   0 },
+       { "intc",       0 },
+       { "edma",       0 },
+       { "dmtimer",    0 },
+       { "dmtimer",    1 },
+       { "omdog",      0 },
+       { "omgpio",     0 },
+       { "omgpio",     1 },
+       { "omgpio",     2 },
+       { "omgpio",     3 },
+       { "tiiic",      0 },
+       { "tiiic",      1 },
+       { "tiiic",      2 },
+       { "ommmc",      0 },            /* HSMMC0 */
+       { "ommmc",      1 },            /* HSMMC1 */
+       { "com",        0 },            /* UART0 */
+       { "cpsw",       0 },
+       { NULL,         0 }
+};
+
+struct board_dev overo_devs[] = {
+       { "prcm",       0 },
+       { "intc",       0 },
+       { "gptimer",    0 },
+       { "gptimer",    1 },
+       { "omdog",      0 },
+       { "omgpio",     0 },
+       { "omgpio",     1 },
+       { "omgpio",     2 },
+       { "omgpio",     3 },
+       { "omgpio",     4 },
+       { "omgpio",     5 },
+       { "ommmc",      0 },            /* HSMMC1 */
+       { "com",        2 },            /* UART3 */
+       { NULL,         0 }
+};
+
+struct board_dev pandaboard_devs[] = {
+       { "omapid",     0 },
+       { "prcm",       0 },
+       { "omdog",      0 },
+       { "omgpio",     0 },
+       { "omgpio",     1 },
+       { "omgpio",     2 },
+       { "omgpio",     3 },
+       { "omgpio",     4 },
+       { "omgpio",     5 },
+       { "ommmc",      0 },            /* HSMMC1 */
+       { "com",        2 },            /* UART3 */
+       { "ehci",       0 },
+       { NULL,         0 }
+};
+
+struct armv7_board omap_boards[] = {
+       {
+               BOARD_ID_OMAP3_BEAGLE,
+               "TI OMAP3 BeagleBoard",
+               beagleboard_devs,
+               omap3_init,
+       },
+       {
+               BOARD_ID_AM335X_BEAGLEBONE,
+               "TI AM335x BeagleBone",
+               beaglebone_devs,
+               am335x_init,
+       },
+       {
+               BOARD_ID_OMAP3_OVERO,
+               "Gumstix OMAP3 Overo",
+               overo_devs,
+               omap3_init,
+       },
+       {
+               BOARD_ID_OMAP4_PANDA,
+               "TI OMAP4 PandaBoard",
+               pandaboard_devs,
+               omap4_init,
+       },
+       { 0, NULL, NULL, NULL },
+};
+
+struct board_dev *
+omap_board_devs(void)
+{
+       int i;
+
+       for (i = 0; omap_boards[i].name != NULL; i++) {
+               if (omap_boards[i].board_id == board_id)
+                       return (omap_boards[i].devs);
+       }
+       return (NULL);
+}
+
+void
+omap_board_init(void)
+{
+       int i;
+
+       for (i = 0; omap_boards[i].name != NULL; i++) {
+               if (omap_boards[i].board_id == board_id) {
+                       omap_boards[i].init();
+                       break;
+               }
+       }
+}
+
+const char *
+omap_board_name(void)
+{
+       int i;
+
+       for (i = 0; omap_boards[i].name != NULL; i++) {
+               if (omap_boards[i].board_id == board_id)
+                       return (omap_boards[i].name);
+       }
+       return (NULL);
+}
+
+int
+omap_match(struct device *parent, void *cfdata, void *aux)
+{
+       union mainbus_attach_args *ma = (union mainbus_attach_args *)aux;
+       struct cfdata *cf = (struct cfdata *)cfdata;
+
+       if (ma->ma_name == NULL)
+               return (0);
+
+       if (strcmp(cf->cf_driver->cd_name, ma->ma_name) != 0)
+               return (0);
+
+       return (omap_board_devs() != NULL);
+}
diff --git a/omap3.c b/omap3.c
new file mode 100644 (file)
index 0000000..bf2feb5
--- /dev/null
+++ b/omap3.c
@@ -0,0 +1,196 @@
+/* $OpenBSD: omap3.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
+
+/*
+ * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <machine/bus.h>
+
+#include <armv7/armv7/armv7var.h>
+
+#define PRCM_ADDR      0x48004000
+#define PRCM_SIZE      0x2000
+
+#define INTC_ADDR      0x48200000
+#define INTC_SIZE      0x200
+
+#define GPTIMERx_SIZE  0x100
+#define GPTIMER1_ADDR  0x48318000
+#define GPTIMER1_IRQ   37
+#define GPTIMER2_ADDR  0x49032000
+#define GPTIMER2_IRQ   38
+
+#define WD_ADDR                0x48314000
+#define WD_SIZE                0x80
+
+#define GPIOx_SIZE     0x1000
+#define GPIO1_ADDR     0x48310000
+#define GPIO2_ADDR     0x49050000
+#define GPIO3_ADDR     0x49052000
+#define GPIO4_ADDR     0x49054000
+#define GPIO5_ADDR     0x49056000
+#define GPIO6_ADDR     0x49058000
+
+#define GPIO1_IRQ      29
+#define GPIO2_IRQ      30
+#define GPIO3_IRQ      31
+#define GPIO4_IRQ      32
+#define GPIO5_IRQ      33
+#define GPIO6_IRQ      34
+
+#define UARTx_SIZE     0x400
+#define UART1_ADDR     0x4806A000
+#define UART2_ADDR     0x4806C000
+#define UART3_ADDR     0x49020000
+
+#define UART1_IRQ      72
+#define UART2_IRQ      73
+#define UART3_IRQ      74
+
+#define HSMMCx_SIZE    0x200
+#define HSMMC1_ADDR    0x4809c000
+#define HSMMC1_IRQ     83
+
+#define USBTLL_ADDR    0x48062000
+#define USBTLL_SIZE    0x1000
+
+struct armv7_dev omap3_devs[] = {
+
+       /*
+        * Power, Reset and Clock Manager
+        */
+
+       { .name = "prcm",
+         .unit = 0,
+         .mem = { { PRCM_ADDR, PRCM_SIZE } },
+       },
+
+       /*
+        * Interrupt Controller
+        */
+
+       { .name = "intc",
+         .unit = 0,
+         .mem = { { INTC_ADDR, INTC_SIZE } },
+       },
+
+       /*
+        * General Purpose Timers
+        */
+
+       { .name = "gptimer",
+         .unit = 1,                    /* XXX see gptimer.c */
+         .mem = { { GPTIMER1_ADDR, GPTIMERx_SIZE } },
+         .irq = { GPTIMER1_IRQ }
+       },
+
+       { .name = "gptimer",
+         .unit = 0,                    /* XXX see gptimer.c */
+         .mem = { { GPTIMER2_ADDR, GPTIMERx_SIZE } },
+         .irq = { GPTIMER2_IRQ }
+       },
+
+       /*
+        * GPIO
+        */
+
+       { .name = "omgpio",
+         .unit = 0,
+         .mem = { { GPIO1_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO1_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 1,
+         .mem = { { GPIO2_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO2_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 2,
+         .mem = { { GPIO3_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO3_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 3,
+         .mem = { { GPIO4_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO4_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 4,
+         .mem = { { GPIO5_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO5_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 5,
+         .mem = { { GPIO6_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO6_IRQ }
+       },
+
+       /*
+        * Watchdog Timer
+        */
+
+       { .name = "omdog",
+         .unit = 0,
+         .mem = { { WD_ADDR, WD_SIZE } }
+       },
+
+       /*
+        * UART
+        */
+
+       { .name = "com",
+         .unit = 2,
+         .mem = { { UART3_ADDR, UARTx_SIZE } },
+         .irq = { UART3_IRQ }
+       },
+
+       /*
+        * MMC
+        */
+
+       { .name = "ommmc",
+         .unit = 0,
+         .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } },
+         .irq = { HSMMC1_IRQ }
+       },
+
+       /*
+        * USB
+        */
+
+       { .name = "omusbtll",
+         .unit = 0,
+         .mem = { { USBTLL_ADDR, USBTLL_SIZE } },
+       },
+
+       /* Terminator */
+       { .name = NULL,
+         .unit = 0,
+       }
+};
+
+void
+omap3_init(void)
+{
+       armv7_set_devs(omap3_devs);
+}
diff --git a/omap3_prcmreg.h b/omap3_prcmreg.h
new file mode 100644 (file)
index 0000000..02f5e7e
--- /dev/null
@@ -0,0 +1,222 @@
+/* $OpenBSD: omap3_prcmreg.h,v 1.3 2013/10/28 11:11:50 rapha Exp $ */
+/*
+ * Copyright (c) 2007, 2009, 2012 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* XXX - verify these definitions and correctly merge them with omap4 */
+#define        CM_FCLKEN_IVA2          0x0000
+#define        CM_CLKEN_PLL_IVA2       0x0004
+#define        CM_IDLEST_IVA2          0x0020
+#define        CM_IDLEST_PLL_IVA2      0x0024
+#define        CM_AUTOIDLE_PLL_IVA2    0x0034
+#define        CM_CLKSEL1_PLL_IVA2     0x0040
+#define        CM_CLKSEL2_PLL_IVA2     0x0044
+#define        CM_CLKSTCTRL_IVA2       0x0048
+#define        CM_CLKSTST_IVA2         0x004c
+#define        CM_CLKSEL_MPU           0x0940
+#define        CM_CLKSTCTRL_MPU        0x0948
+#define        RM_RSTST_MPU            0x0958
+#define        PM_WKDEP_MPU            0x09C8
+#define        PM_EVGENCTRL_MPU        0x09D4
+#define        PM_EVEGENONTIM_MPU      0x09D8
+#define        PM_EVEGENOFFTIM_MPU     0x09DC
+#define        PM_PWSTCTRL_MPU         0x09E0
+#define        PM_PWSTST_MPU           0x09E4
+#define        CM_FCLKEN1_CORE         0x0a00
+#define        CM_FCLKEN1_CORE_MSK     0x41fffe00
+#define        CM_FCLKEN2_CORE         0x0a04
+#define        CM_FCLKEN2_CORE_MSK     0x00000000
+#define        CM_FCLKEN3_CORE         0x0a08
+#define        CM_FCLKEN3_CORE_MSK     0x00000007
+#define        CM_ICLKEN1_CORE         0x0a10
+#define        CM_ICLKEN1_CORE_MSK     0x7ffffed2
+#define        CM_ICLKEN2_CORE         0x0a14
+#define        CM_ICLKEN2_CORE_MSK     0x0000001f
+#define        CM_ICLKEN3_CORE         0x0a18
+#define        CM_ICLKEN3_CORE_MSK     0x00000004
+#define        CM_ICLKEN4_CORE         0x0a1C
+#define        CM_IDLEST1_CORE         0x0a20
+#define        CM_IDLEST2_CORE         0x0a24
+#define        CM_IDLEST4_CORE         0x0a2C
+#define        CM_AUTOIDLE1_CORE       0x0a30
+#define        CM_AUTOIDLE2_CORE       0x0a34
+#define        CM_AUTOIDLE3_CORE       0x0a38
+#define        CM_AUTOIDLE4_CORE       0x0a3C
+#define        CM_CLKSEL1_CORE         0x0a40
+#define        CM_CLKSEL2_CORE         0x0a44
+#define        CM_CLKSTCTRL_CORE       0x0a48
+#define        PM_WKEN1_CORE           0x0aA0
+#define        PM_WKEN2_CORE           0x0aA4
+#define        PM_WKST1_CORE           0x0aB0
+#define        PM_WKST2_CORE           0x0aB4
+#define        PM_WKDEP_CORE           0x0aC8
+#define        PM_PWSTCTRL_CORE        0x0aE0
+#define        PM_PWSTST_CORE          0x0aE4
+#define        CM_FCLKEN_GFX           0x0b00
+#define        CM_ICLKEN_GFX           0x0b10
+#define        CM_IDLEST_GFX           0x0b20
+#define        CM_CLKSEL_GFX           0x0b40
+#define        CM_CLKSTCTRL_GFX        0x0b48
+#define        RM_RSTCTRL_GFX          0x0b50
+#define        RM_RSTST_GFX            0x0b58
+#define        PM_WKDEP_GFX            0x0bC8
+#define        PM_PWSTCTRL_GFX         0x0bE0
+#define        PM_PWSTST_GFX           0x0bE4
+#define        CM_FCLKEN_WKUP          0x0c00
+#define CM_FCLKEN_WKUP_MSK     0x00000029
+#define        CM_ICLKEN_WKUP          0x0c10
+#define CM_ICLKEN_WKUP_MSK     0x0000002d
+#define        CM_IDLEST_WKUP          0x0c20
+#define        CM_AUTOIDLE_WKUP        0x0c30
+#define        CM_CLKSEL_WKUP          0x0c40
+#define        RM_RSTCTRL_WKUP         0x0c50
+#define        RM_RSTTIME_WKUP         0x0c54
+#define        RM_RSTST_WKUP           0x0c58
+#define        PM_WKEN_WKUP            0x0cA0
+#define        PM_WKST_WKUP            0x0cB0
+#define        CM_CLKEN_PLL            0x0d00
+#define        CM_CLKEN2_PLL           0x0d04
+#define        CM_IDLEST_CKGEN         0x0d20
+#define        CM_AUTOIDLE_PLL         0x0d30
+#define        CM_AUTOIDLE2_PLL        0x0d34
+#define        CM_CLKSEL1_PLL          0x0d40
+#define        CM_CLKSEL2_PLL          0x0d44
+#define        CM_CLKSEL3_PLL          0x0d48
+#define        CM_CLKSEL4_PLL          0x0d4C
+#define        CM_CLKSEL5_PLL          0x0d50
+#define        CM_FCLKEN_PER           0x1000
+#define CM_FCLKEN_PER_MSK      0x0003ffff
+#define        CM_ICLKEN_PER           0x1010
+#define CM_ICLKEN_PER_MSK      0x0003ffff
+#define        CM_IDLEST_PER           0x1020
+#define        CM_AUTOIDLE_PER         0x1030
+#define        CM_CLKSEL_PER           0x1040
+#define        CM_SLEEPDEP_PER         0x1044
+#define        CM_CLKSTCTRL_PER        0x1048
+#define        CM_CLKSTST_PER          0x104C
+#define        CM_CLKSEL1_EMU          0x1140
+#define        CM_CLKSTCTRL_EMU        0x1148
+#define        CM_CLKSTST_EMU          0x114C
+#define        CM_CLKSEL2_EMU          0x1150
+#define        CM_CLKSEL3_EMU          0x1154
+#define        CM_POLCTRL              0x129C
+#define        CM_IDLEST_NEON          0x1320
+#define        CM_CLKSTCTRL_NEON       0x1348
+#define        CM_FCLKEN_USBHOST       0x1400
+#define        CM_FCLKEN_USBHOST_MSK   0x00000003
+#define        CM_ICLKEN_USBHOST       0x1410
+#define        CM_ICLKEN_USBHOST_MSK   0x00000001
+#define        CM_IDLEST_USBHOST       0x1420
+#define        CM_AUTOIDLE_USBHOST     0x1430
+#define        CM_SLEEPDEP_USBHOST     0x1444
+#define        CM_CLKSTCTRL_USBHOST    0x1448
+#define        CM_CLKSTST_USBHOST      0x144C
+
+
+#define        PRCM_REG_CORE_CLK1      0
+#define        PRCM_REG_CORE_CLK1_FADDR        CM_FCLKEN1_CORE
+#define        PRCM_REG_CORE_CLK1_IADDR        CM_ICLKEN1_CORE
+#define        PRCM_REG_CORE_CLK1_FMASK        CM_FCLKEN1_CORE_MSK
+#define        PRCM_REG_CORE_CLK1_IMASK        CM_ICLKEN1_CORE_MSK
+#define        PRCM_REG_CORE_CLK1_BASE (PRCM_REG_CORE_CLK1*32)
+#define                PRCM_CLK_EN_MMC3        (PRCM_REG_CORE_CLK1_BASE + 30)
+#define                PRCM_CLK_EN_ICR         (PRCM_REG_CORE_CLK1_BASE + 29)
+#define                PRCM_CLK_EN_AES2        (PRCM_REG_CORE_CLK1_BASE + 28)
+#define                PRCM_CLK_EN_SHA12       (PRCM_REG_CORE_CLK1_BASE + 27)
+#define                PRCM_CLK_EN_DES2        (PRCM_REG_CORE_CLK1_BASE + 26)
+#define                PRCM_CLK_EN_MMC2        (PRCM_REG_CORE_CLK1_BASE + 25)
+#define                PRCM_CLK_EN_MMC1        (PRCM_REG_CORE_CLK1_BASE + 24)
+#define                PRCM_CLK_EN_MSPRO       (PRCM_REG_CORE_CLK1_BASE + 23)
+#define                PRCM_CLK_EN_HDQ         (PRCM_REG_CORE_CLK1_BASE + 22)
+#define                PRCM_CLK_EN_MCSPI4      (PRCM_REG_CORE_CLK1_BASE + 21)
+#define                PRCM_CLK_EN_MCSPI3      (PRCM_REG_CORE_CLK1_BASE + 20)
+#define                PRCM_CLK_EN_MCSPI2      (PRCM_REG_CORE_CLK1_BASE + 19)
+#define                PRCM_CLK_EN_MCSPI1      (PRCM_REG_CORE_CLK1_BASE + 18)
+#define                PRCM_CLK_EN_I2C3        (PRCM_REG_CORE_CLK1_BASE + 17)
+#define                PRCM_CLK_EN_I2C2        (PRCM_REG_CORE_CLK1_BASE + 16)
+#define                PRCM_CLK_EN_I2C1        (PRCM_REG_CORE_CLK1_BASE + 15)
+#define                PRCM_CLK_EN_UART2       (PRCM_REG_CORE_CLK1_BASE + 14)
+#define                PRCM_CLK_EN_UART1       (PRCM_REG_CORE_CLK1_BASE + 13)
+#define                PRCM_CLK_EN_GPT11       (PRCM_REG_CORE_CLK1_BASE + 12)
+#define                PRCM_CLK_EN_GPT10       (PRCM_REG_CORE_CLK1_BASE + 11)
+#define                PRCM_CLK_EN_MCBSP5      (PRCM_REG_CORE_CLK1_BASE + 10)
+#define                PRCM_CLK_EN_MCBSP1      (PRCM_REG_CORE_CLK1_BASE + 9)
+#define                PRCM_CLK_EN_MAILBOXES   (PRCM_REG_CORE_CLK1_BASE + 7)
+#define                PRCM_CLK_EN_OMAPCTRL    (PRCM_REG_CORE_CLK1_BASE + 6)
+#define                PRCM_CLK_EN_HSOTGUSB    (PRCM_REG_CORE_CLK1_BASE + 4)
+#define                PRCM_CLK_EN_SDRC        (PRCM_REG_CORE_CLK1_BASE + 1)
+
+#define        PRCM_REG_CORE_CLK2      1
+#define        PRCM_REG_CORE_CLK2_FADDR        CM_FCLKEN2_CORE
+#define        PRCM_REG_CORE_CLK2_IADDR        CM_ICLKEN2_CORE
+#define        PRCM_REG_CORE_CLK2_FMASK        CM_FCLKEN2_CORE_MSK
+#define        PRCM_REG_CORE_CLK2_IMASK        CM_ICLKEN2_CORE_MSK
+#define        PRCM_REG_CORE_CLK2_BASE (PRCM_REG_CORE_CLK2*32)
+
+#define        PRCM_REG_CORE_CLK3      2
+#define        PRCM_REG_CORE_CLK3_FADDR        CM_FCLKEN3_CORE
+#define        PRCM_REG_CORE_CLK3_IADDR        CM_ICLKEN3_CORE
+#define        PRCM_REG_CORE_CLK3_FMASK        CM_FCLKEN3_CORE_MSK
+#define        PRCM_REG_CORE_CLK3_IMASK        CM_ICLKEN3_CORE_MSK
+#define        PRCM_REG_CORE_CLK3_BASE (PRCM_REG_CORE_CLK3*32)
+#define                PRCM_CORE_EN_USBTLL     (PRCM_REG_CORE_CLK3_BASE + 2)
+#define                PRCM_CORE_EN_TS         (PRCM_REG_CORE_CLK3_BASE + 1)
+#define                PRCM_CORE_EN_CPEFUSE    (PRCM_REG_CORE_CLK3_BASE + 0)
+
+#define PRCM_REG_WKUP          3
+#define PRCM_REG_WKUP_FADDR            CM_FCLKEN_WKUP
+#define PRCM_REG_WKUP_IADDR            CM_ICLKEN_WKUP
+#define PRCM_REG_WKUP_FMASK            CM_FCLKEN_WKUP_MSK
+#define PRCM_REG_WKUP_IMASK            CM_ICLKEN_WKUP_MSK
+#define PRCM_REG_WKUP_BASE (PRCM_REG_WKUP*32)
+#define                PRCM_CLK_EN_MPU_WDT     (PRCM_REG_WKUP_BASE + 5)
+#define                PRCM_CLK_EN_GPIO1       (PRCM_REG_WKUP_BASE + 3)
+#define                PRCM_CLK_EN_32KSYNC     (PRCM_REG_WKUP_BASE + 2)
+#define                PRCM_CLK_EN_GPT1        (PRCM_REG_WKUP_BASE + 0)
+
+#define PRCM_REG_PER           4
+#define PRCM_REG_PER_FADDR             CM_FCLKEN_PER
+#define PRCM_REG_PER_IADDR             CM_ICLKEN_PER
+#define PRCM_REG_PER_FMASK             CM_FCLKEN_PER_MSK
+#define PRCM_REG_PER_IMASK             CM_ICLKEN_PER_MSK
+#define PRCM_REG_PER_BASE (PRCM_REG_PER*32)
+#define                PRCM_CLK_EN_GPIO6       (PRCM_REG_PER_BASE + 17)
+#define                PRCM_CLK_EN_GPIO5       (PRCM_REG_PER_BASE + 16)
+#define                PRCM_CLK_EN_GPIO4       (PRCM_REG_PER_BASE + 15)
+#define                PRCM_CLK_EN_GPIO3       (PRCM_REG_PER_BASE + 14)
+#define                PRCM_CLK_EN_GPIO2       (PRCM_REG_PER_BASE + 13)
+#define                PRCM_CLK_EN_WDT3        (PRCM_REG_PER_BASE + 12)
+#define                PRCM_CLK_EN_UART3       (PRCM_REG_PER_BASE + 11)
+#define                PRCM_CLK_EN_GPT9        (PRCM_REG_PER_BASE + 10)
+#define                PRCM_CLK_EN_GPT8        (PRCM_REG_PER_BASE + 9)
+#define                PRCM_CLK_EN_GPT7        (PRCM_REG_PER_BASE + 8)
+#define                PRCM_CLK_EN_GPT6        (PRCM_REG_PER_BASE + 7)
+#define                PRCM_CLK_EN_GPT5        (PRCM_REG_PER_BASE + 6)
+#define                PRCM_CLK_EN_GPT4        (PRCM_REG_PER_BASE + 5)
+#define                PRCM_CLK_EN_GPT3        (PRCM_REG_PER_BASE + 4)
+#define                PRCM_CLK_EN_GPT2        (PRCM_REG_PER_BASE + 3)
+#define                PRCM_CLK_EN_MCBSP4      (PRCM_REG_PER_BASE + 2)
+#define                PRCM_CLK_EN_MCBSP3      (PRCM_REG_PER_BASE + 1)
+#define                PRCM_CLK_EN_MCBSP2      (PRCM_REG_PER_BASE + 0)
+
+#define        PRCM_REG_USBHOST        5
+#define        PRCM_REG_USBHOST_FADDR  CM_FCLKEN_USBHOST
+#define        PRCM_REG_USBHOST_IADDR  CM_ICLKEN_USBHOST
+#define        PRCM_REG_USBHOST_FMASK  CM_FCLKEN_USBHOST_MSK
+#define        PRCM_REG_USBHOST_IMASK  CM_ICLKEN_USBHOST_MSK
+#define        PRCM_REG_USBHOST_BASE   (PRCM_REG_USBHOST*32)
+#define                PRCM_CLK_EN_USBHOST2    (PRCM_REG_USBHOST_BASE + 1)
+#define                PRCM_CLK_EN_USBHOST1    (PRCM_REG_USBHOST_BASE + 0)
+#define                PRCM_CLK_EN_USB         (PRCM_REG_USBHOST_BASE + 0)
diff --git a/omap4.c b/omap4.c
new file mode 100644 (file)
index 0000000..5cd1b81
--- /dev/null
+++ b/omap4.c
@@ -0,0 +1,200 @@
+/* $OpenBSD: omap4.c,v 1.3 2013/11/06 19:03:07 syl Exp $ */
+
+/*
+ * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <armv7/armv7/armv7var.h>
+
+#define OMAPID_ADDR    0x4a002000
+#define OMAPID_SIZE    0x1000
+
+#define WD_ADDR                0x4a314000
+#define WD_SIZE                0x80
+
+#define GPIOx_SIZE     0x1000
+#define GPIO1_ADDR     0x4a310000
+#define GPIO2_ADDR     0x48055000
+#define GPIO3_ADDR     0x48057000
+#define GPIO4_ADDR     0x48059000
+#define GPIO5_ADDR     0x4805b000
+#define GPIO6_ADDR     0x4805d000
+
+#define GPIO1_IRQ      29
+#define GPIO2_IRQ      30
+#define GPIO3_IRQ      31
+#define GPIO4_IRQ      32
+#define GPIO5_IRQ      33
+#define GPIO6_IRQ      34
+
+#define UARTx_SIZE     0x400
+#define UART1_ADDR     0x4806A000
+#define UART2_ADDR     0x4806C000
+#define UART3_ADDR     0x48020000
+#define UART4_ADDR     0x4806E000
+
+#define UART1_IRQ      72
+#define UART2_IRQ      73
+#define UART3_IRQ      74
+#define UART4_IRQ      70
+
+#define HSMMCx_SIZE    0x200
+#define HSMMC1_ADDR    0x4809c100
+#define HSMMC1_IRQ     83
+
+#define PRM_ADDR       0x4a306000
+#define PRM_SIZE       0x2000
+#define CM1_ADDR       0x4a004000
+#define CM1_SIZE       0x1000
+#define CM2_ADDR       0x4a008000
+#define CM2_SIZE       0x2000
+#define SCRM_ADDR      0x4a30a000
+#define SCRM_SIZE      0x1000
+#define PCNF1_ADDR     0x4a100000
+#define PCNF1_SIZE     0x1000
+#define PCNF2_ADDR     0x4a31e000
+#define PCNF2_SIZE     0x1000
+
+#define HSUSBHOST_ADDR 0x4a064000
+#define HSUSBHOST_SIZE 0x800
+#define USBEHCI_ADDR   0x4a064c00
+#define USBEHCI_SIZE   0x400
+#define USBOHCI_ADDR   0x4a064800
+#define USBOHCI_SIZE   0x400
+#define USBEHCI_IRQ    77
+
+struct armv7_dev omap4_devs[] = {
+
+       /*
+        * Power, Reset and Clock Manager
+        */
+
+       { .name = "prcm",
+         .unit = 0,
+         .mem = {
+           { PRM_ADDR, PRM_SIZE },
+           { CM1_ADDR, CM1_SIZE },
+           { CM2_ADDR, CM2_SIZE },
+         },
+       },
+
+       /*
+        * OMAP identification registers/fuses
+        */
+
+       { .name = "omapid",
+         .unit = 0,
+         .mem = { { OMAPID_ADDR, OMAPID_SIZE } },
+       },
+
+       /*
+        * GPIO
+        */
+
+       { .name = "omgpio",
+         .unit = 0,
+         .mem = { { GPIO1_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO1_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 1,
+         .mem = { { GPIO2_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO2_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 2,
+         .mem = { { GPIO3_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO3_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 3,
+         .mem = { { GPIO4_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO4_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 4,
+         .mem = { { GPIO5_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO5_IRQ }
+       },
+
+       { .name = "omgpio",
+         .unit = 5,
+         .mem = { { GPIO6_ADDR, GPIOx_SIZE } },
+         .irq = { GPIO6_IRQ }
+       },
+
+       /*
+        * Watchdog Timer
+        */
+
+       { .name = "omdog",
+         .unit = 0,
+         .mem = { { WD_ADDR, WD_SIZE } }
+       },
+
+       /*
+        * UART
+        */
+
+       { .name = "com",
+         .unit = 2,
+         .mem = { { UART3_ADDR, UARTx_SIZE } },
+         .irq = { UART3_IRQ }
+       },
+
+       /*
+        * MMC
+        */
+
+       { .name = "ommmc",
+         .unit = 0,
+         .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } },
+         .irq = { HSMMC1_IRQ }
+       },
+
+       /*
+        * USB
+        */
+
+       { .name = "ehci",
+         .unit = 0,
+         .mem = {
+                 { USBEHCI_ADDR, USBEHCI_SIZE },
+                 { HSUSBHOST_ADDR, HSUSBHOST_SIZE },
+         },
+         .irq = { USBEHCI_IRQ }
+       },
+
+       /* Terminator */
+       { .name = NULL,
+         .unit = 0,
+       }
+};
+
+void
+omap4_init(void)
+{
+       armv7_set_devs(omap4_devs);
+}
diff --git a/omap4_prcmreg.h b/omap4_prcmreg.h
new file mode 100644 (file)
index 0000000..9cff537
--- /dev/null
@@ -0,0 +1,27 @@
+/* $OpenBSD: omap4_prcmreg.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */
+/*
+ * Copyright (c) 2007, 2009, 2012 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define O4_L3INIT_CM2_OFFSET              0x00001300
+#define O4_CLKCTRL_MODULEMODE_MASK       0x00000003
+#define O4_CLKCTRL_MODULEMODE_DISABLE    0x00000000
+#define O4_CLKCTRL_MODULEMODE_AUTO       0x00000001
+#define O4_CLKCTRL_MODULEMODE_ENABLE     0x00000001
+
+#define O4_MAX_MODULE_ENABLE_WAIT    1000
+
+#define O4_CLKCTRL_IDLEST_MASK           0x00030000UL
+#define O4_CLKCTRL_IDLEST_ENABLED        0x00000000UL
diff --git a/omap_com.c b/omap_com.c
new file mode 100644 (file)
index 0000000..9a3a94c
--- /dev/null
@@ -0,0 +1,112 @@
+/* $OpenBSD: omap_com.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+
+/* pick up armv7_a4x_bs_tag */
+#include <arch/arm/armv7/armv7var.h>
+
+#include <armv7/armv7/armv7var.h>
+
+#define com_isr 8
+#define ISR_RECV       (ISR_RXPL | ISR_XMODE | ISR_RCVEIR)
+
+void   omapuart_attach(struct device *, struct device *, void *);
+int    omapuart_activate(struct device *, int);
+
+struct cfattach com_omap_ca = {
+       sizeof (struct com_softc), NULL, omapuart_attach, NULL,
+       omapuart_activate
+};
+
+void
+omapuart_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct com_softc *sc = (struct com_softc *)self;
+       struct armv7_attach_args *aa = aux;
+
+       sc->sc_iot = &armv7_a4x_bs_tag; /* XXX: This sucks */
+       sc->sc_iobase = aa->aa_dev->mem[0].addr;
+       sc->sc_frequency = 48000000;
+       sc->sc_uarttype = COM_UART_TI16750;
+
+       if (bus_space_map(sc->sc_iot, sc->sc_iobase,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) {
+               printf("%s: bus_space_map failed\n", __func__);
+               return;
+       }
+
+       com_attach_subr(sc);
+
+       (void)arm_intr_establish(aa->aa_dev->irq[0], IPL_TTY, comintr,
+           sc, sc->sc_dev.dv_xname);
+}
+
+int
+omapuart_activate(struct device *self, int act)
+{
+       struct com_softc *sc = (struct com_softc *)self;
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_ioh;
+       struct tty *tp = sc->sc_tty;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               break;
+       case DVACT_RESUME:
+               if (sc->enabled) {
+                       sc->sc_initialize = 1;
+                       comparam(tp, &tp->t_termios);
+                       bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
+
+                       if (ISSET(sc->sc_hwflags, COM_HW_SIR)) {
+                               bus_space_write_1(iot, ioh, com_isr,
+                                   ISR_RECV);
+                       }
+               }
+               break;
+       }
+       return 0;
+}
diff --git a/omap_machdep.c b/omap_machdep.c
new file mode 100644 (file)
index 0000000..4e29a3e
--- /dev/null
@@ -0,0 +1,137 @@
+/*     $OpenBSD: omap_machdep.c,v 1.6 2015/05/19 03:30:54 jsg Exp $    */
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/termios.h>
+
+#include <machine/bus.h>
+#include <machine/bootconfig.h>
+
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+
+#include <arm/cortex/smc.h>
+#include <arm/armv7/armv7var.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/armv7/armv7_machdep.h>
+
+extern void omap4_smc_call(uint32_t, uint32_t);
+extern void omdog_reset(void);
+extern char *omap_board_name(void);
+extern struct board_dev *omap_board_devs(void);
+extern void omap_board_init(void);
+extern int comcnspeed;
+extern int comcnmode;
+
+void
+omap_platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh,
+    bus_size_t off, uint32_t op, uint32_t val)
+{
+       switch (op) {
+       case 0x100:     /* PL310 DEBUG */
+       case 0x102:     /* PL310 CTL */
+               break;
+       default:
+               panic("platform_smc_write: invalid operation %d", op);
+       }
+
+       omap4_smc_call(op, val);
+}
+
+void
+omap_platform_init_cons(void)
+{
+       paddr_t paddr;
+
+       switch (board_id) {
+       case BOARD_ID_OMAP3_BEAGLE:
+       case BOARD_ID_OMAP3_OVERO:
+               paddr = 0x49020000;
+               break;
+       case BOARD_ID_AM335X_BEAGLEBONE:
+               paddr = 0x44e09000;
+               break;
+       case BOARD_ID_OMAP4_PANDA:
+               paddr = 0x48020000;
+               break;
+       }
+
+       comcnattach(&armv7_a4x_bs_tag, paddr, comcnspeed, 48000000, comcnmode);
+       comdefaultrate = comcnspeed;
+}
+
+void
+omap_platform_watchdog_reset(void)
+{
+       omdog_reset();
+}
+
+void
+omap_platform_powerdown(void)
+{
+
+}
+
+const char *
+omap_platform_board_name(void)
+{
+       return (omap_board_name());
+}
+
+void
+omap_platform_disable_l2_if_needed(void)
+{
+       switch (board_id) {
+       case BOARD_ID_OMAP4_PANDA:
+               /* disable external L2 cache */
+               omap4_smc_call(0x102, 0);
+               break;
+       }
+}
+
+void
+omap_platform_board_init(void)
+{
+       omap_board_init();
+}
+
+struct armv7_platform omap_platform = {
+       .boot_name = "OpenBSD/omap",
+       .board_name = omap_platform_board_name,
+       .board_init = omap_platform_board_init,
+       .smc_write = omap_platform_smc_write,
+       .init_cons = omap_platform_init_cons,
+       .watchdog_reset = omap_platform_watchdog_reset,
+       .powerdown = omap_platform_powerdown,
+       .disable_l2_if_needed = omap_platform_disable_l2_if_needed,
+};
+
+struct armv7_platform *
+omap_platform_match(void)
+{
+       struct board_dev *devs;
+
+       devs = omap_board_devs();
+       if (devs == NULL)
+               return (NULL);
+
+       omap_platform.devs = devs;
+       return (&omap_platform);
+}
diff --git a/omapid.c b/omapid.c
new file mode 100644 (file)
index 0000000..406c9d6
--- /dev/null
+++ b/omapid.c
@@ -0,0 +1,101 @@
+/* $OpenBSD: omapid.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
+/*
+ * Copyright (c) 2013 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <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 O4_ID_SIZE     0x1000
+#define O4_FUSE_ID0    0x200
+#define O4_ID_CODE     0x204
+#define O4_FUSE_ID1    0x208
+#define O4_FUSE_ID2    0x20C
+#define O4_FUSE_ID3    0x210
+#define O4_FUSE_PRODID0        0x214
+#define O4_FUSE_PRODID1        0x218
+
+
+struct omapid_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct omapid_softc *omapid_sc;
+
+
+void omapid_attach(struct device *parent, struct device *self, void *args);
+void omapid_wpending(int flags);
+
+struct cfattach        omapid_ca = {
+       sizeof (struct omapid_softc), NULL, omapid_attach
+};
+
+struct cfdriver omapid_cd = {
+       NULL, "omapid", DV_DULL
+};
+
+void amptimer_set_clockrate(int32_t new_frequency); /* XXX */
+
+void
+omapid_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct omapid_softc *sc = (struct omapid_softc *) self;
+       uint32_t rev;
+       uint32_t newclockrate = 0;
+       char *board;
+
+       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("omapid: bus_space_map failed!");
+
+       omapid_sc = sc;
+
+       board = "unknown";
+       switch (board_id) {
+       case BOARD_ID_OMAP4_PANDA:
+               rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, O4_ID_CODE);
+               switch ((rev >> 12) & 0xffff) {
+               case 0xB852:
+               case 0xB95C:
+                       board = "omap4430";
+                       newclockrate = 400 * 1000 * 1000;
+                       break;
+               case 0xB94E:
+                       board = "omap4460";
+                       newclockrate = 350 * 1000 * 1000;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       printf(": %s\n", board);
+       if (newclockrate != 0)
+               amptimer_set_clockrate(newclockrate);
+}
diff --git a/omdisplay.c b/omdisplay.c
new file mode 100644 (file)
index 0000000..7fe18c0
--- /dev/null
@@ -0,0 +1,1394 @@
+/* $OpenBSD: omdisplay.c,v 1.5 2014/07/12 18:44:41 tedu Exp $ */
+/*
+ * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <machine/bus.h>
+#include <armv7/omap/omgpiovar.h>
+
+#include <dev/cons.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/wscons/wscons_callbacks.h>
+
+#include <dev/rasops/rasops.h>
+
+#include "splash16.h"
+
+#define OMDISPLAY_SIZE                 0x1000
+/* registers */
+/* DSS */
+#define DSS_REVISIONNUMBER             0x00
+#define DSS_CONTROL                    0x40
+#define DSS_PSA_LCD_REG_1              0x50
+#define DSS_PSA_LCD_REG_2              0x54
+#define DSS_PSA_VIDEO_REG              0x58
+#define DSS_STATUS                     0x5C
+
+/* DCR */
+#define DISPC_REVISION                 0x0000
+#define DISPC_SYSCONFIG                        0x0010
+#define                DISPC_SYSCONFIG_AUTOIDLE                0x00000001
+#define                DISPC_SYSCONFIG_SOFTRESET               0x00000002
+#define                DISPC_SYSCONFIG_SIDLEMODE_FORCE         0x00000000
+#define                DISPC_SYSCONFIG_SIDLEMODE_NONE          0x00000008
+#define                DISPC_SYSCONFIG_SIDLEMODE_SMART         0x00000010
+#define                DISPC_SYSCONFIG_MIDLEMODE_FORCE         0x00000000
+#define                DISPC_SYSCONFIG_MIDLEMODE_NONE          0x00001000
+#define                DISPC_SYSCONFIG_MIDLEMODE_SMART         0x00002000
+#define DISPC_SYSSTATUS                        0x0014
+#define                DISPC_SYSTATUS_RESETDONE                0x00000001
+#define DISPC_IRQSTATUS                        0x0018
+#define                DISPC_IRQSTATUS_FRAMEDONE               0x00000001
+#define                DISPC_IRQSTATUS_VSYNC                   0x00000002
+#define                DISPC_IRQSTATUS_EVSYNCEVEN              0x00000004
+#define                DISPC_IRQSTATUS_EVSYNCODD               0x00000008
+#define                DISPC_IRQSTATUS_ACBIASCOUNT             0x00000010
+#define                DISPC_IRQSTATUS_PROGLINENUM             0x00000020
+#define                DISPC_IRQSTATUS_GFXFIFOUNDER            0x00000040
+#define                DISPC_IRQSTATUS_GFXENDWINDOW            0x00000080
+#define                DISPC_IRQSTATUS_PALGAMMA                0x00000100
+#define                DISPC_IRQSTATUS_OCPERROR                0x00000200
+#define                DISPC_IRQSTATUS_VID1FIFOUNDER           0x00000400
+#define                DISPC_IRQSTATUS_VID1ENDWIND             0x00000800
+#define                DISPC_IRQSTATUS_VID2FIFOUNDER           0x00001000
+#define                DISPC_IRQSTATUS_VID2ENDWIND             0x00002000
+#define                DISPC_IRQSTATUS_SYNCLOST                0x00004000
+#define DISPC_IRQENABLE                        0x001C
+#define                DISPC_IRQENABLE_FRAMEDONE               0x00000001
+#define                DISPC_IRQENABLE_VSYNC                   0x00000002
+#define                DISPC_IRQENABLE_EVSYNCEVEN              0x00000004
+#define                DISPC_IRQENABLE_EVSYNCODD               0x00000008
+#define                DISPC_IRQENABLE_ACBIASCOUNT             0x00000010
+#define                DISPC_IRQENABLE_PROGLINENUM             0x00000020
+#define                DISPC_IRQENABLE_GFXFIFOUNDER            0x00000040
+#define                DISPC_IRQENABLE_GFXENDWINDOW            0x00000080
+#define                DISPC_IRQENABLE_PALGAMMA                0x00000100
+#define                DISPC_IRQENABLE_OCPERROR                0x00000200
+#define                DISPC_IRQENABLE_VID1FIFOUNDER           0x00000400
+#define                DISPC_IRQENABLE_VID1ENDWIND             0x00000800
+#define                DISPC_IRQENABLE_VID2FIFOUNDER           0x00001000
+#define                DISPC_IRQENABLE_VID2ENDWIND             0x00002000
+#define                DISPC_IRQENABLE_SYNCLOST                0x00004000
+#define DISPC_CONTROL                  0x0040
+#define        DISPC_CONTROL_LCDENABLE                 0x00000001
+#define        DISPC_CONTROL_DIGITALENABLE             0x00000002
+#define        DISPC_CONTROL_MONOCOLOR                 0x00000004
+#define        DISPC_CONTROL_STNTFT                    0x00000008
+#define        DISPC_CONTROL_M8B                       0x00000010
+#define        DISPC_CONTROL_GOLCD                     0x00000020
+#define        DISPC_CONTROL_GODIGITAL                 0x00000040
+#define        DISPC_CONTROL_TFTDITHEREN               0x00000080
+#define        DISPC_CONTROL_TFTDATALINES_12           0x00000000
+#define        DISPC_CONTROL_TFTDATALINES_16           0x00000100
+#define        DISPC_CONTROL_TFTDATALINES_18           0x00000200
+#define        DISPC_CONTROL_TFTDATALINES_24           0x00000300
+#define        DISPC_CONTROL_SECURE                    0x00000400
+#define        DISPC_CONTROL_RFBIMODE                  0x00000800
+#define        DISPC_CONTROL_OVERLAYOPT                0x00001000
+#define        DISPC_CONTROL_GPIN0                     0x00002000
+#define        DISPC_CONTROL_GPIN1                     0x00004000
+#define        DISPC_CONTROL_GPOUT0                    0x00008000
+#define        DISPC_CONTROL_GPOUT1                    0x00010000
+#define        DISPC_CONTROL_HT                        0x00070000
+#define        DISPC_CONTROL_HT_s(x)                   ((x) << 17)
+#define        DISPC_CONTROL_TDMENABLE                 0x00100000
+#define        DISPC_CONTROL_TDMPARALLEL_8             0x00000000
+#define        DISPC_CONTROL_TDMPARALLEL_9             0x00200000
+#define        DISPC_CONTROL_TDMPARALLEL_12            0x00400000
+#define        DISPC_CONTROL_TDMPARALLEL_16            0x00600000
+#define        DISPC_CONTROL_TDMCYCLE_1                0x00000000
+#define        DISPC_CONTROL_TDMCYCLE_2                0x00800000
+#define        DISPC_CONTROL_TDMCYCLE_3                0x00000000
+#define        DISPC_CONTROL_TDMCYCLE_3_2              0x01800000
+#define        DISPC_CONTROL_TDMUNUSED_0               0x00000000
+#define        DISPC_CONTROL_TDMUNUSED_1               0x02000000
+#define        DISPC_CONTROL_TDMUNUSED_M               0x04000000
+#define DISPC_CONFIG                   0x0044
+#define        DISPC_CONFIG_PIXELGATED                 0x00000001
+#define        DISPC_CONFIG_LOADMODE_PGE               0x00000000
+#define        DISPC_CONFIG_LOADMODE_PG                0x00000002
+#define        DISPC_CONFIG_LOADMODE_DATA              0x00000004
+#define        DISPC_CONFIG_LOADMODE_DATA_PG           0x00000006
+#define        DISPC_CONFIG_PALETTEGAMMA               0x00000008
+#define        DISPC_CONFIG_PIXELDATAGATED             0x00000010
+#define        DISPC_CONFIG_PIXELCLOCKGATED            0x00000020
+#define        DISPC_CONFIG_HSYNCGATED                 0x00000040
+#define        DISPC_CONFIG_VSYNCGATED                 0x00000080
+#define        DISPC_CONFIG_ACBIAGATED                 0x00000100
+#define        DISPC_CONFIG_FUNCGATED                  0x00000200
+#define        DISPC_CONFIG_TCKLCDEN                   0x00000400
+#define        DISPC_CONFIG_TCKLCDSEL                  0x00000800
+#define        DISPC_CONFIG_TCKDIGEN                   0x00001000
+#define        DISPC_CONFIG_TCKDIGSEL                  0x00002000
+#define DISPC_CAPABLE                  0x0048
+#define DISPC_DEFAULT_COLOR0           0x004C
+#define DISPC_DEFAULT_COLOR1           0x0050
+#define DISPC_TRANS_COLOR0             0x0054
+#define DISPC_TRANS_COLOR1             0x0058
+#define DISPC_LINE_STATUS              0x005C
+#define DISPC_LINE_NUMBER              0x0060
+#define DISPC_TIMING_H                 0x0064
+#define                DISPC_TIMING_H_HSW_s(x) ((x) << 0)
+#define                DISPC_TIMING_H_HFP_s(x) ((x) << 8)
+#define                DISPC_TIMING_H_HBP_s(x) ((x) << 20)
+#define DISPC_TIMING_V                 0x0068
+#define                DISPC_TIMING_V_VSW_s(x) ((x) << 0)
+#define                DISPC_TIMING_V_VFP_s(x) ((x) << 8)
+#define                DISPC_TIMING_V_VBP_s(x) ((x) << 20)
+#define DISPC_POL_FREQ                 0x006C
+#define        DISPC_POL_FREQ_ACB_s(x) ((x) << 0)
+#define        DISPC_POL_FREQ_ACBI_s(x)        ((x) << 8)
+#define        DISPC_POL_FREQ_IVS      0x00001000
+#define        DISPC_POL_FREQ_IHS      0x00002000
+#define        DISPC_POL_FREQ_IPC      0x00004000
+#define        DISPC_POL_FREQ_IEO      0x00008000
+#define        DISPC_POL_FREQ_RF       0x00010000
+#define        DISPC_POL_FREQ_ONOFF    0x00020000
+#define DISPC_DIVISOR                  0x0070
+#define                DISPC_DIVISOR_PCD_s(x)  ((x) << 0)
+#define                DISPC_DIVISOR_LCD_s(x)  ((x) << 16)
+#define DISPC_SIZE_DIG                 0x0078
+#define                DISPC_SIZE_DIG_PPL_s(x) ((x) << 0)
+#define                DISPC_SIZE_DIG_LPP_s(x) ((x) << 16)
+#define DISPC_SIZE_LCD                 0x007C
+#define                DISPC_SIZE_LCD_PPL_s(x) ((x) << 0)
+#define                DISPC_SIZE_LCD_LPP_s(x) ((x) << 16)
+#define DISPC_GFX_BA0                  0x0080
+#define DISPC_GFX_BA1                  0x0084
+#define DISPC_GFX_POSITION             0x0088
+#define DISPC_GFX_SIZE                 0x008C
+#define                DISPC_GFX_SIZE_X_s(x)   ((x) << 0)
+#define                DISPC_GFX_SIZE_Y_s(x)   ((x) << 16)
+#define DISPC_GFX_ATTRIBUTES           0x00A0
+#define                DISPC_GFX_ATTRIBUTES_GFXENABLE          0x001
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_1           0x000
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_2           0x002
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_4           0x004
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_8           0x006
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_12          0x008
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_16          0x00c
+#define                DISPC_GFX_ATTRIBUTES_GFXFMT_24          0x010
+#define                DISPC_GFX_ATTRIBUTES_GFXREPLICATE       0x020
+#define                DISPC_GFX_ATTRIBUTES_BURST_4            0x000
+#define                DISPC_GFX_ATTRIBUTES_BURST_8            0x040
+#define                DISPC_GFX_ATTRIBUTES_BURST_16           0x080
+#define                DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT      0x100
+#define                DISPC_GFX_ATTRIBUTES_NIBBLEMODE         0x200
+#define                DISPC_GFX_ATTRIBUTES_ENDIAN             0x400
+#define DISPC_GFX_FIFO_THRESHOLD       0x00A4
+#define        DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT     16
+#define        DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT      0
+#define DISPC_GFX_FIFO_SIZE_STATUS     0x00A8
+#define DISPC_GFX_ROW_INC              0x00AC
+#define DISPC_GFX_PIXEL_INC            0x00B0
+#define DISPC_GFX_WINDOW_SKIP          0x00B4
+#define DISPC_GFX_TABLE_BA             0x00B8
+#define DISPC_VID1_BA0                 0x00BC
+#define DISPC_VID1_BA1                 0x00C0
+#define DISPC_VID1_POSITION            0x00C4
+#define DISPC_VID1_SIZE                        0x00C8
+#define DISPC_VID1_ATTRIBUTES          0x00CC
+#define DISPC_VID1_FIFO_THRESHOLD      0x00D0
+#define DISPC_VID1_FIFO_SIZE_STATUS    0x00D4
+#define DISPC_VID1_ROW_INC             0x00D8
+#define DISPC_VID1_PIXEL_INC           0x00DC
+#define DISPC_VID1_FIR                 0x00E0
+#define DISPC_VID1_PICTURE_SIZE                0x00E4
+#define DISPC_VID1_ACCU0               0x00E8
+#define DISPC_VID1_ACCU1               0x00EC
+#define DISPC_VID1_FIR_COEF_H0         0x00F0
+#define DISPC_VID1_FIR_COEF_H1         0x00F8
+#define DISPC_VID1_FIR_COEF_H2         0x0100
+#define DISPC_VID1_FIR_COEF_H3         0x0108
+#define DISPC_VID1_FIR_COEF_H4         0x0110
+#define DISPC_VID1_FIR_COEF_H5         0x0118
+#define DISPC_VID1_FIR_COEF_H6         0x0120
+#define DISPC_VID1_FIR_COEF_H7         0x0128
+#define DISPC_VID1_FIR_COEF_HV0                0x00F4
+#define DISPC_VID1_FIR_COEF_HV1                0x00FC
+#define DISPC_VID1_FIR_COEF_HV2                0x0104
+#define DISPC_VID1_FIR_COEF_HV3                0x010C
+#define DISPC_VID1_FIR_COEF_HV4                0x0114
+#define DISPC_VID1_FIR_COEF_HV5                0x011C
+#define DISPC_VID1_FIR_COEF_HV6                0x0124
+#define DISPC_VID1_FIR_COEF_HV7                0x012C
+#define DISPC_VID1_CONV_COEF0          0x0130
+#define DISPC_VID1_CONV_COEF1          0x0134
+#define DISPC_VID1_CONV_COEF2          0x0138
+#define DISPC_VID1_CONV_COEF3          0x013C
+#define DISPC_VID1_CONV_COEF4          0x0140
+#define DISPC_VID2_BA0                 0x014C
+#define DISPC_VID2_BA1                 0x0150
+#define DISPC_VID2_POSITION            0x0154
+#define DISPC_VID2_SIZE                        0x0158
+#define DISPC_VID2_ATTRIBUTES          0x015C
+#define DISPC_VID2_FIFO_THRESHOLD      0x0160
+#define DISPC_VID2_FIFO_SIZE_STATUS    0x0164
+#define DISPC_VID2_ROW_INC             0x0168
+#define DISPC_VID2_PIXEL_INC           0x016C
+#define DISPC_VID2_FIR                 0x0170
+#define DISPC_VID2_PICTURE_SIZE                0x0174
+#define DISPC_VID2_ACCU0               0x0178
+#define DISPC_VID2_ACCU1               0x017C
+#define DISPC_VID2_FIR_COEF_H0         0x0180
+#define DISPC_VID2_FIR_COEF_H1         0x0188
+#define DISPC_VID2_FIR_COEF_H2         0x0190
+#define DISPC_VID2_FIR_COEF_H3         0x0198
+#define DISPC_VID2_FIR_COEF_H4         0x01A0
+#define DISPC_VID2_FIR_COEF_H5         0x01A8
+#define DISPC_VID2_FIR_COEF_H6         0x01B0
+#define DISPC_VID2_FIR_COEF_H7         0x01B8
+#define DISPC_VID2_FIR_COEF_HV0                0x0184
+#define DISPC_VID2_FIR_COEF_HV1                0x018C
+#define DISPC_VID2_FIR_COEF_HV2                0x0194
+#define DISPC_VID2_FIR_COEF_HV3                0x019C
+#define DISPC_VID2_FIR_COEF_HV4                0x01A4
+#define DISPC_VID2_FIR_COEF_HV5                0x01AC
+#define DISPC_VID2_FIR_COEF_HV6                0x01B4
+#define DISPC_VID2_FIR_COEF_HV7                0x01BC
+#define DISPC_VID2_CONV_COEF0          0x01C0
+#define DISPC_VID2_CONV_COEF1          0x01C4
+#define DISPC_VID2_CONV_COEF2          0x01C8
+#define DISPC_VID2_CONV_COEF3          0x01CC
+#define DISPC_VID2_CONV_COEF4          0x01D0
+#define DISPC_DATA_CYCLE1              0x01D4
+#define DISPC_DATA_CYCLE2              0x01D8
+#define DISPC_DATA_CYCLE3              0x01DC
+#define DISPC_SIZE                     0x0200
+
+/* RFBI */
+#define RFBI_REVISION          0x0000
+#define RFBI_SYSCONFIG         0x0010
+#define RFBI_SYSSTATUS         0x0014
+#define RFBI_CONTROL           0x0040
+#define RFBI_PIXEL_CNT         0x0044
+#define RFBI_LINE_NUMBER       0x0048
+#define RFBI_CMD               0x004C
+#define RFBI_PARAM             0x0050
+#define RFBI_DATA              0x0054
+#define RFBI_READ              0x0058
+#define RFBI_STATUS            0x005C
+#define RFBI_CONFIG0           0x0060
+#define RFBI_CONFIG1           0x0078
+#define RFBI_ONOFF_TIME0       0x0064
+#define RFBI_ONOFF_TIME1       0x007C
+#define RFBI_CYCLE_TIME0       0x0068
+#define RFBI_CYCLE_TIME1       0x0080
+#define RFBI_DATA_CYCLE1_0     0x006C
+#define RFBI_DATA_CYCLE1_1     0x0084
+#define RFBI_DATA_CYCLE2_0     0x0070
+#define RFBI_DATA_CYCLE2_1     0x0088
+#define RFBI_DATA_CYCLE3_0     0x0074
+#define RFBI_DATA_CYCLE3_1     0x008C
+#define RFBI_VSYNC_WIDTH       0x0090
+#define RFBI_HSYNC_WIDTH       0x0094
+
+/* VENC1 */
+#define REV_ID                         0x0000
+#define STATUS                         0x0004
+#define F_CONTROL                      0x0008
+#define VIDOUT_CTRL                    0x0010
+#define SYNC_CTRL                      0x0014
+#define LLEN                           0x001C
+#define FLENS                          0x0020
+#define HFLTR_CTRL                     0x0024
+#define CC_CARR_WSS_CARR               0x0028
+#define C_PHASE                                0x002C
+#define GAIN_U                         0x0030
+#define GAIN_V                         0x0034
+#define GAIN_Y                         0x0038
+#define BLACK_LEVEL                    0x003C
+#define BLANK_LEVEL                    0x0040
+#define X_COLOR                                0x0044
+#define M_CONTROL                      0x0048
+#define BSTAMP_WSS_DATA                        0x004C
+#define S_CARR                         0x0050
+#define LINE21                         0x0054
+#define LN_SEL                         0x0058
+#define L21_WC_CTL                     0x005C
+#define HTRIGGER_VTRIGGER              0x0060
+#define SAVID_EAVID                    0x0064
+#define FLEN_FAL                       0x0068
+#define LAL_PHASE_RESET                        0x006C
+#define HS_INT_START_STOP_X                    0x0070
+#define HS_EXT_START_STOP_X                    0x0074
+#define VS_INT_START_X                         0x0078
+#define VS_INT_STOP_X_VS_INT_START_Y           0x007C
+#define VS_INT_STOP_Y_VS_EXT_START_X           0x0080
+#define VS_EXT_STOP_X_VS_EXT_START_Y           0x0084
+#define VS_EXT_STOP_Y                          0x0088
+#define AVID_START_STOP_X                      0x0090
+#define AVID_START_STOP_Y                      0x0094
+#define FID_INT_START_X_FID_INT_START_Y                0x00A0
+#define FID_INT_OFFSET_Y_FID_EXT_START_X       0x00A4
+#define FID_EXT_START_Y_FID_EXT_OFFSET_Y       0x00A8
+#define TVDETGP_INT_START_STOP_X       0x00B0
+#define TVDETGP_INT_START_STOP_Y       0x00B4
+#define GEN_CTRL                       0x00B8
+#define DAC_TST_DAC_A                  0x00C4
+#define DAC_B_DAC_C                    0x00C8
+
+
+/* NO CONSOLE SUPPORT */
+
+
+/* assumes 565 panel. */
+struct omdisplay_panel_data {
+       int width;
+       int height;
+       int horiz_sync_width;
+       int horiz_front_porch;
+       int horiz_back_porch;
+       int vert_sync_width;
+       int vert_front_porch;
+       int vert_back_porch;
+       int panel_flags;
+       int sync;
+       int depth;
+#define PANEL_SYNC_H_ACTIVE_HIGH 1
+#define PANEL_SYNC_V_ACTIVE_HIGH 2
+       int linebytes;
+};
+
+#define PIXELDEPTH     16
+#define PIXELWIDTH     2
+
+struct omdisplay_panel_data    default_panel = {
+       240,    /* Width */
+       322,    /* Height */
+       9, 9, 19,       /* horiz sync, fp, bp */
+       1, 2, 2,        /* vert  sync, fp, bp */
+       0,      /* flags */
+       0,      /* sync */
+       PIXELDEPTH,
+       240*PIXELWIDTH
+};
+
+struct omdisplay_screen {
+       LIST_ENTRY(omdisplay_screen) link;
+
+       /* Frame buffer */
+       bus_dmamap_t dma;
+       bus_dma_segment_t segs[1];
+       int     nsegs;
+       size_t  buf_size;
+       size_t  map_size;
+       void    *buf_va;
+       int     depth;
+
+       /* rasterop */
+       struct rasops_info rinfo;
+};
+
+struct omdisplay_softc {
+       struct device sc_dev;
+       bus_space_tag_t sc_iot;
+       bus_space_handle_t sc_dsioh;
+       bus_space_handle_t sc_dcioh;
+       bus_space_handle_t sc_rfbioh;
+       bus_space_handle_t sc_venioh;
+       bus_dma_tag_t           sc_dma_tag;
+
+       void *sc_ih;
+
+       int     sc_nscreens;
+       LIST_HEAD(,omdisplay_screen) sc_screens;
+
+       struct omdisplay_panel_data     *sc_geometry;
+       struct omdisplay_screen         *sc_active;
+};
+
+int omdisplay_match(struct device *parent, void *v, void *aux);
+void omdisplay_attach(struct device *parent, struct device *self, void *args);
+int omdisplay_activate(struct device *, int);
+int omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag,
+    struct proc *p);
+void omdisplay_burner(void *v, u_int on, u_int flags);
+int omdisplay_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg);
+int omdisplay_param(struct omdisplay_softc *sc, ulong cmd,
+    struct wsdisplay_param *dp);
+int omdisplay_max_brightness(void);
+int omdisplay_get_brightness(void);
+void omdisplay_set_brightness(int newval);
+void omdisplay_set_brightness_internal(int newval);
+int omdisplay_get_backlight(void);
+void omdisplay_set_backlight(int on);
+void omdisplay_blank(int blank);
+void omdisplay_suspend(struct omdisplay_softc *sc);
+void omdisplay_resume(struct omdisplay_softc *sc);
+void omdisplay_initialize(struct omdisplay_softc *sc,
+    struct omdisplay_panel_data *geom);
+void omdisplay_setup_rasops(struct omdisplay_softc *sc,
+    struct rasops_info *rinfo);
+int omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type,
+    void **cookiep, int *curxp, int *curyp, long *attrp);
+int omdisplay_new_screen(struct omdisplay_softc *sc,
+    struct omdisplay_screen *scr, int depth);
+paddr_t omdisplay_mmap(void *v, off_t offset, int prot);
+int omdisplay_load_font(void *, void *, struct wsdisplay_font *);
+int omdisplay_list_font(void *, struct wsdisplay_font *);
+void omdisplay_free_screen(void *v, void *cookie);
+void omdisplay_start(struct omdisplay_softc *sc);
+void omdisplay_stop(struct omdisplay_softc *sc);
+int omdisplay_intr(void *v);
+void omdisplay_dumpreg(struct omdisplay_softc *sc);
+
+struct cfattach        omdisplay_ca = {
+       sizeof (struct omdisplay_softc), omdisplay_match, omdisplay_attach,
+       NULL, omdisplay_activate
+};
+
+struct cfdriver omdisplay_cd = {
+       NULL, "omdisplay", DV_DULL
+};
+
+struct wsdisplay_accessops omdisplay_accessops = {
+       .ioctl = omdisplay_ioctl,
+       .mmap = omdisplay_mmap,
+       .alloc_screen = omdisplay_alloc_screen,
+       .free_screen = omdisplay_free_screen,
+       .show_screen = omdisplay_show_screen,
+       .load_font = omdisplay_load_font,
+       .list_font = omdisplay_list_font,
+       .burn_screen = omdisplay_burner
+
+};
+
+struct omdisplay_wsscreen_descr {
+       struct wsscreen_descr  c;       /* standard descriptor */
+       int depth;                      /* bits per pixel */
+       int flags;                      /* rasops flags */
+};
+
+struct omdisplay_wsscreen_descr omdisplay_screen = {
+       {
+               "std"
+       },
+       16,                     /* bits per pixel */
+       0 /* rotate */
+};
+
+const struct wsscreen_descr *omdisplay_scr_descr[] = {
+       &omdisplay_screen.c
+};
+
+/* XXX - what about flip phones with CLI */
+const struct wsscreen_list omdisplay_screen_list = {
+        sizeof omdisplay_scr_descr / sizeof omdisplay_scr_descr[0],
+       omdisplay_scr_descr
+};
+
+
+int
+omdisplay_match(struct device *parent, void *v, void *aux)
+{
+       /* XXX */
+       return (1);
+}
+
+void
+omdisplay_attach(struct device *parent, struct device *self, void *args)
+{
+       struct ahb_attach_args *aa = args;
+       struct omdisplay_softc *sc = (struct omdisplay_softc *) self;
+       struct wsemuldisplaydev_attach_args wsaa;
+
+
+       sc->sc_iot = aa->aa_iot;
+
+       if (bus_space_map(sc->sc_iot, aa->aa_addr, OMDISPLAY_SIZE, 0,
+           &sc->sc_dsioh))
+               panic("omdisplay_attach: bus_space_map failed!");
+
+       if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x400, 1024,
+           &sc->sc_dcioh))
+               panic("omdisplay_attach: bus_space_submap failed!");
+
+       if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x800, 1024,
+           &sc->sc_rfbioh))
+               panic("omdisplay_attach: bus_space_submap failed!");
+
+       if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0xc00, 1024,
+           &sc->sc_venioh))
+               panic("omdisplay_attach: bus_space_submap failed!");
+
+
+       sc->sc_nscreens = 0;
+       LIST_INIT(&sc->sc_screens);
+
+       sc->sc_dma_tag = aa->aa_dmat;
+
+       sc->sc_ih = arm_intr_establish(aa->aa_intr, IPL_BIO /* XXX */,
+           omdisplay_intr, sc, sc->sc_dev.dv_xname);
+
+       printf ("\n");
+
+       sc->sc_geometry = &default_panel;
+
+       {
+               /* XXX - dummy? */
+               struct rasops_info dummy;
+
+               omdisplay_initialize(sc, sc->sc_geometry);
+
+               /*
+                * Initialize a dummy rasops_info to compute fontsize and
+                * the screen size in chars.
+                */
+               bzero(&dummy, sizeof(dummy));
+               omdisplay_setup_rasops(sc, &dummy);
+       }
+
+       wsaa.console = 0;
+       wsaa.scrdata = &omdisplay_screen_list;
+       wsaa.accessops = &omdisplay_accessops;
+       wsaa.accesscookie = sc;
+       wsaa.defaultscreens = 0;
+
+       (void)config_found(self, &wsaa, wsemuldisplaydevprint);
+
+       /* backlight? */
+}
+
+
+int
+omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       struct omdisplay_softc *sc = v;
+       struct wsdisplay_fbinfo *wsdisp_info;
+       struct omdisplay_screen *scr = sc->sc_active;
+       int res = EINVAL;
+
+       switch (cmd) {
+       case WSDISPLAYIO_GETPARAM:
+       case WSDISPLAYIO_SETPARAM:
+               res = omdisplay_param(sc, cmd, (struct wsdisplay_param *)data);
+               break;
+       case WSDISPLAYIO_GTYPE:
+               *(u_int *)data = WSDISPLAY_TYPE_PXALCD; /* XXX */
+               break;
+
+       case WSDISPLAYIO_GINFO:
+               wsdisp_info = (struct wsdisplay_fbinfo *)data;
+
+               wsdisp_info->height = sc->sc_geometry->height;
+               wsdisp_info->width = sc->sc_geometry->width;
+               wsdisp_info->depth = 16; /* XXX */
+               wsdisp_info->cmsize = 0;
+               break;
+               
+       case WSDISPLAYIO_GETCMAP:
+       case WSDISPLAYIO_PUTCMAP:
+               return EINVAL;  /* XXX Colormap */
+
+       case WSDISPLAYIO_SVIDEO:
+       case WSDISPLAYIO_GVIDEO:
+               break;
+
+       case WSDISPLAYIO_GCURPOS:
+       case WSDISPLAYIO_SCURPOS:
+       case WSDISPLAYIO_GCURMAX:
+       case WSDISPLAYIO_GCURSOR:
+       case WSDISPLAYIO_SCURSOR:
+       default:
+               return -1;      /* not implemented */
+
+       case WSDISPLAYIO_LINEBYTES:
+               if (scr != NULL)
+                       *(u_int *)data = scr->rinfo.ri_stride;
+               else 
+                       *(u_int *)data = 0;
+               break;
+
+       }
+
+       if (res == EINVAL)
+               res = omdisplay_ioctl(v, cmd, data, flag, p);
+
+       return res;
+}
+
+void
+omdisplay_burner(void *v, u_int on, u_int flags)
+{
+
+        omdisplay_set_brightness(on ? omdisplay_get_brightness() : 0);
+
+       /* GPIO controls for appsliver */
+       if (on) {
+               omgpio_set_bit(93);                     /* 1 enable backlight */
+               omgpio_set_dir(93, OMGPIO_DIR_OUT);
+               omgpio_clear_bit(26);                   /* 0 enable LCD */
+               omgpio_set_dir(26, OMGPIO_DIR_OUT);
+       } else {
+               omgpio_clear_bit(93);                   /* 0 disable backlt */
+               omgpio_set_dir(93, OMGPIO_DIR_OUT);
+               omgpio_set_bit(26);                     /* 1 disable LCD */
+               omgpio_set_dir(26, OMGPIO_DIR_OUT);
+       }
+}
+
+int
+omdisplay_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg)  
+{
+       struct omdisplay_softc *sc = v;
+       struct rasops_info *ri = cookie;
+       struct omdisplay_screen *scr = ri->ri_hw, *old;
+
+       old = sc->sc_active;
+       if (old == scr)
+               return 0;
+  
+       if (old != NULL)
+               ; /* Stop old screen */
+
+       sc->sc_active = scr;
+       omdisplay_initialize(sc, sc->sc_geometry);
+       
+       /* Turn on LCD */
+       omdisplay_burner(v, 1, 0);
+
+       return (0);
+}
+
+
+
+/*
+ * wsdisplay I/O controls
+ */
+int
+omdisplay_param(struct omdisplay_softc *sc, ulong cmd,
+    struct wsdisplay_param *dp)
+{
+       int res = EINVAL;
+
+       switch (dp->param) {
+       case WSDISPLAYIO_PARAM_BACKLIGHT:
+               if (cmd == WSDISPLAYIO_GETPARAM) {
+                       dp->min = 0;
+                       dp->max = 1;
+                       dp->curval = omdisplay_get_backlight();
+                       res = 0;
+               } else if (cmd == WSDISPLAYIO_SETPARAM) {
+/* XXX */
+//                     omdisplay_set_backlight(dp->curval);
+                       res = 0;
+               }
+               break;
+
+       case WSDISPLAYIO_PARAM_CONTRAST:
+               /* unsupported */
+               res = ENOTTY;
+               break;
+
+       case WSDISPLAYIO_PARAM_BRIGHTNESS:
+               if (cmd == WSDISPLAYIO_GETPARAM) {
+                       dp->min = 1;
+                       dp->max = omdisplay_max_brightness();
+                       dp->curval = omdisplay_get_brightness();
+                       res = 0;
+               } else if (cmd == WSDISPLAYIO_SETPARAM) {
+/* XXX */
+//                     omdisplay_set_brightness(dp->curval);
+                       res = 0;
+               }
+               break;
+       }
+
+       return res;
+}
+
+
+/*
+ * LCD backlight
+ */
+
+static  int lcdbrightnesscurval = 1;
+static  int lcdislit = 1;
+static  int lcdisblank = 0;
+
+struct lcd_backlight {
+       int     duty;           /* LZ9JG18 DAC value */
+       int     cont;           /* BACKLIGHT_CONT signal */
+       int     on;             /* BACKLIGHT_ON signal */
+};
+
+const struct lcd_backlight lcd_bl[] = {
+       { 0x00, 0, 0 },         /* 0:     Off */
+       { 0x00, 0, 1 },         /* 1:      0% */
+       { 0x01, 0, 1 },         /* 2:     20% */
+       { 0x07, 0, 1 },         /* 3:     40% */
+       { 0x01, 1, 1 },         /* 4:     60% */
+       { 0x07, 1, 1 },         /* 5:     80% */
+       { 0x11, 1, 1 },         /* 6:    100% */
+       { -1, -1, -1 }          /* 7: Invalid */
+};
+#define CURRENT_BACKLIGHT lcd_bl
+
+int
+omdisplay_max_brightness(void)
+{
+       int i;
+
+       for (i = 0; CURRENT_BACKLIGHT[i].duty != -1; i++)
+               ;
+       return i - 1;
+}
+
+int
+omdisplay_get_brightness(void)
+{
+
+       return lcdbrightnesscurval;
+}
+
+void
+omdisplay_set_brightness(int newval)
+{
+       int max;
+
+       max = omdisplay_max_brightness();
+       if (newval < 0)
+               newval = 0;
+       else if (newval > max)
+               newval = max;
+
+       if (omdisplay_get_backlight() && !lcdisblank)
+               omdisplay_set_brightness_internal(newval);
+
+       if (newval > 0)
+               lcdbrightnesscurval = newval;
+}
+
+void
+omdisplay_set_brightness_internal(int newval)
+{
+       static int curval = 1;
+       int i;
+
+       /*
+        * It appears that the C3000 backlight can draw too much power if we
+        * switch it from a low to a high brightness.  Increasing brightness
+        * in steps avoids this issue.
+        */
+       if (newval > curval) {
+               for (i = curval + 1; i <= newval; i++) {
+/* atlas controls */
+                       /* CURRENT_BACKLIGHT[newval].duty); */
+               }
+       } else {
+/* atlas controls */
+               /* CURRENT_BACKLIGHT[newval].duty); */
+       }
+
+       curval = newval;
+}
+
+int
+omdisplay_get_backlight(void)
+{
+
+       return lcdislit;
+}
+
+void
+omdisplay_set_backlight(int on)
+{
+
+       if (!on) {
+               omdisplay_set_brightness(0);
+               lcdislit = 0;
+       } else {
+               lcdislit = 1;
+               omdisplay_set_brightness(omdisplay_get_brightness());
+       }
+}
+   
+void
+omdisplay_blank(int blank)
+{
+               
+       if (blank) {
+               omdisplay_set_brightness(0);
+               lcdisblank = 1;
+       } else {
+               lcdisblank = 0;
+               omdisplay_set_brightness(omdisplay_get_brightness());
+       }
+}
+
+void
+omdisplay_suspend(struct omdisplay_softc *sc)
+{
+       if (sc->sc_active != NULL) {
+               omdisplay_stop(sc);
+               /* XXX disable clocks */
+       }
+}
+
+void
+omdisplay_resume(struct omdisplay_softc *sc)
+{
+       if (sc->sc_active != NULL) {
+               /* XXX - clocks? */
+               omdisplay_initialize(sc, sc->sc_geometry);
+               omdisplay_start(sc);
+       }
+}
+
+void
+omdisplay_activate(struct device *self, int act)
+{
+       struct omdisplay_softc *sc = (struct omdisplay_softc *)self;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               omdisplay_set_brightness(0);
+               omdisplay_suspend(sc);
+               break;
+       case DVACT_RESUME:
+               omdisplay_resume(sc);
+               omdisplay_set_brightness(omdisplay_get_brightness());
+               break;
+       }
+       return 0;
+}
+
+void
+omdisplay_initialize(struct omdisplay_softc *sc,
+    struct omdisplay_panel_data *geom)
+{
+       struct omdisplay_screen *scr;
+       u_int32_t reg;
+       u_int32_t mode;
+#if 0
+       int den, nom; /* pixel rate */
+#endif
+
+
+       reg = bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL);
+
+       scr = sc->sc_active;
+
+       if (reg & (DISPC_CONTROL_LCDENABLE|DISPC_CONTROL_DIGITALENABLE)) {
+               omdisplay_stop(sc);
+       }
+
+       /* XXX - enable clocks */
+
+       /* disable all interrupts */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_IRQENABLE, 0);
+
+       /* GPIOs ? */
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONFIG,
+           DISPC_CONFIG_LOADMODE_PG|DISPC_CONFIG_LOADMODE_DATA);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_LINE_NUMBER, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE3, 0);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SYSCONFIG,
+           DISPC_SYSCONFIG_SIDLEMODE_NONE|
+           DISPC_SYSCONFIG_MIDLEMODE_NONE);
+               
+#if 0
+       if (geom->panel_flags & LCDPANEL_TDM) {
+               nom = tdmflags >>8 & 0x3;
+               den = tdmflags & 0x3;
+       } else {
+               nom = 1;
+               den = 1;
+       }
+       hsync = geom->width*den/nom + geom->horiz_sync_width +
+           geom->horiz_front_porch + geom->horiz_back_porch;
+#endif
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_H,
+           DISPC_TIMING_H_HSW_s(geom->horiz_sync_width) |
+           DISPC_TIMING_H_HFP_s(geom->horiz_front_porch) |
+           DISPC_TIMING_H_HBP_s(geom->horiz_back_porch));
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_V,
+           DISPC_TIMING_V_VSW_s(geom->vert_sync_width) |
+           DISPC_TIMING_V_VFP_s(geom->vert_front_porch) |
+           DISPC_TIMING_V_VBP_s(geom->vert_back_porch));
+
+       reg = 0;
+       if (geom->sync & PANEL_SYNC_H_ACTIVE_HIGH)
+               reg |= DISPC_POL_FREQ_IHS;
+       if (geom->sync & PANEL_SYNC_V_ACTIVE_HIGH)
+               reg |= DISPC_POL_FREQ_IVS;
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_POL_FREQ, reg);
+
+       
+       /* clkdiv = pixclock/period; */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_LCD,
+           DISPC_SIZE_LCD_PPL_s(geom->width-1) |
+           DISPC_SIZE_LCD_LPP_s(geom->height-1));
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_DIG,
+           DISPC_SIZE_LCD_PPL_s(geom->width-1) |
+           DISPC_SIZE_LCD_LPP_s(geom->height-1));
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_SIZE,
+               DISPC_GFX_SIZE_X_s(geom->width-1) |
+               DISPC_GFX_SIZE_Y_s(geom->height-1));
+
+
+       /* XXX!!! */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DIVISOR,
+               DISPC_DIVISOR_LCD_s(1) | DISPC_DIVISOR_PCD_s(6));
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA0,
+           scr->segs[0].ds_addr);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA1,
+           scr->segs[0].ds_addr);
+
+       /* non-rotated */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1);
+
+
+       /* XXX 24bit -> 32 pixels */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC,
+           1 + scr->rinfo.ri_stride -
+           (scr->rinfo.ri_width * scr->rinfo.ri_depth / 8));
+
+       switch (geom->depth) {
+       case 1:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_1;
+               break;
+       case 2:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_2;
+               break;
+       case 4:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_4;
+               break;
+       case 8:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_8;
+               break;
+       case 12:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_12;
+               break;
+       case 16:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_16;
+               break;
+       case 24:
+               mode = DISPC_GFX_ATTRIBUTES_GFXFMT_24;
+               break;
+       default:
+               panic("invalid depth %d", geom->depth);
+       }
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ATTRIBUTES,
+           DISPC_GFX_ATTRIBUTES_GFXENABLE | mode |
+           DISPC_GFX_ATTRIBUTES_BURST_8);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_POSITION, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_WINDOW_SKIP, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_FIFO_THRESHOLD,
+           (0xfc << DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT) |
+           (0xc0 << DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT));
+       
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1);
+
+       /* DISPC_CONFIG_PALETTEGAMMA not enabled */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_TABLE_BA,
+           scr->segs[0].ds_addr);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA1, 0); 
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_SIZE, 0); 
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ATTRIBUTES, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_THRESHOLD,
+           0xc00040); /* XXX */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_SIZE_STATUS,
+           0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ROW_INC, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PIXEL_INC, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PICTURE_SIZE, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H4, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H5, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H6, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H7, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV4, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV5, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV6, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV7, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF4, 0);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_SIZE, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ATTRIBUTES, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_THRESHOLD,
+           0xc00040); /* XXX */
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_SIZE_STATUS,
+           0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ROW_INC, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PIXEL_INC, 1);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PICTURE_SIZE, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H4, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H5, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H6, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H7, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV4, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV5, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV6, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV7, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF1, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF2, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF3, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF4, 0); 
+
+       omdisplay_start(sc);
+}
+
+void
+omdisplay_setup_rasops(struct omdisplay_softc *sc, struct rasops_info *rinfo)
+{
+       struct omdisplay_wsscreen_descr *descr;
+       struct omdisplay_panel_data *geom;
+
+       descr = &omdisplay_screen;
+       geom = sc->sc_geometry;
+
+       rinfo->ri_flg = descr->flags;
+       rinfo->ri_depth = descr->depth;
+       rinfo->ri_width = geom->width;
+       rinfo->ri_height = geom->height;
+       rinfo->ri_stride = geom->linebytes;
+
+       /* pixel position */
+       if (descr->depth == 16) {
+               rinfo->ri_rnum = 5;
+               rinfo->ri_rpos = 11;
+               rinfo->ri_gnum = 6;
+               rinfo->ri_gpos = 5;
+               rinfo->ri_bnum = 5;
+               rinfo->ri_bpos = 0;
+       }
+
+       if (descr->c.nrows == 0) {
+               /* get rasops to compute screen size the first time */
+               rasops_init(rinfo, 100, 100);
+       } else {
+               if (descr->flags != 0) /* rotate */
+                       rasops_init(rinfo, descr->c.ncols, descr->c.nrows);
+               else
+                       rasops_init(rinfo, descr->c.nrows, descr->c.ncols);
+       }
+
+       descr->c.nrows = rinfo->ri_rows;
+       descr->c.ncols = rinfo->ri_cols;
+       descr->c.capabilities = rinfo->ri_caps;
+       descr->c.textops = &rinfo->ri_ops;
+
+}
+
+
+int
+omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type,
+    void **cookiep, int *curxp, int *curyp, long *attrp)
+{
+       struct omdisplay_softc *sc = v;
+       struct omdisplay_screen *scr;
+       struct rasops_info *ri;
+       struct omdisplay_wsscreen_descr *type =
+           (struct omdisplay_wsscreen_descr *)_type;
+       int error;
+
+       scr = malloc(sizeof *scr, M_DEVBUF, (cold ? M_NOWAIT : M_WAITOK));
+       if (scr == NULL)
+               return (ENOMEM);
+
+       error = omdisplay_new_screen(sc, scr, type->depth);
+       if (error != 0) {
+               free(scr, M_DEVBUF, 0);
+               return (error);
+       }
+
+       /*
+        * initialize raster operation for this screen.
+        */
+       ri = &scr->rinfo;
+       ri->ri_hw = (void *)scr;
+       ri->ri_bits = scr->buf_va;
+       omdisplay_setup_rasops(sc, ri);
+
+       /* assumes 16 bpp */
+       ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
+
+       *cookiep = ri;
+       *curxp = 0;
+       *curyp = 0;
+
+       return 0;
+}
+
+/*
+ * Create and initialize a new screen buffer.
+ */
+int
+omdisplay_new_screen(struct omdisplay_softc *sc,
+    struct omdisplay_screen *scr, int depth)
+{
+       bus_space_tag_t iot;
+       bus_space_handle_t ioh;
+       bus_dma_tag_t dma_tag;
+       struct omdisplay_panel_data *geometry;
+       int width, height;
+       bus_size_t size;
+       int error, palette_size;
+       int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+
+       if (sc != NULL) {
+               iot = sc->sc_iot;
+               ioh = sc->sc_dcioh;
+               dma_tag = sc->sc_dma_tag;
+               geometry = sc->sc_geometry;
+       } else {
+               /* We are creating the console screen. */
+#if 0
+               iot = omdisplay_console.iot;
+               ioh = omdisplay_console.ioh;
+               dma_tag = omdisplay_console.dma_tag;
+               geometry = omdisplay_console.geometry;
+#endif
+       }
+
+       width = geometry->width;
+       height = geometry->height;
+       palette_size = 0;
+
+       switch (depth) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               palette_size = (1 << depth) * sizeof (uint16_t);
+               /* FALLTHROUGH */
+       case 16:
+       case 24:
+               size = geometry->height * geometry->linebytes;
+               break;
+       default:
+               printf("%s: Unknown depth (%d)\n",
+                   sc != NULL ? sc->sc_dev.dv_xname : "console", depth);
+               return (EINVAL);
+       }
+
+       bzero(scr, sizeof *scr);
+
+       scr->nsegs = 0;
+       scr->depth = depth;
+       scr->buf_size = size;
+       scr->buf_va = NULL;
+       size = roundup(size, 16);
+#if 0
+        + 3 * sizeof (struct lcd_dma_descriptor)
+           + palette_size;
+#endif
+
+       error = bus_dmamem_alloc(dma_tag, size, 0x100000, 0,
+           scr->segs, 1, &(scr->nsegs), busdma_flag);
+       if (error != 0 || scr->nsegs != 1) {
+               /* XXX: Actually we can handle nsegs > 1 case by means
+                  of multiple DMA descriptors for a panel.  It would
+                   make code here a bit hairy */
+               if (error == 0)
+                       error = E2BIG;
+               goto bad;
+       }
+
+       error = bus_dmamem_map(dma_tag, scr->segs, scr->nsegs,
+           size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT);
+       if (error != 0)
+               goto bad;
+
+       memset(scr->buf_va, 0, scr->buf_size);
+       bcopy(splash, scr->buf_va,
+           sizeof (splash) > scr->buf_size ? scr->buf_size : sizeof (splash));
+
+       /* map memory for DMA */
+       if (bus_dmamap_create(dma_tag, 1024 * 1024 * 2, 1, 
+           1024 * 1024 * 2, 0,  busdma_flag, &scr->dma))
+               goto bad;
+       error = bus_dmamap_load(dma_tag, scr->dma,
+           scr->buf_va, size, NULL, busdma_flag);
+       if (error != 0) {
+               goto bad;
+       }
+
+       scr->map_size = size;           /* used when unmap this. */
+
+       if (sc != NULL) {
+               LIST_INSERT_HEAD(&(sc->sc_screens), scr, link);
+               sc->sc_nscreens++;
+       }
+
+       omdisplay_initialize(sc, geometry);
+       
+       return (0);
+
+ bad:
+       if (scr->buf_va)
+               bus_dmamem_unmap(dma_tag, scr->buf_va, size);
+       if (scr->nsegs)
+               bus_dmamem_free(dma_tag, scr->segs, scr->nsegs);
+       return (error);
+}
+paddr_t
+omdisplay_mmap(void *v, off_t offset, int prot)
+{
+       struct omdisplay_softc *sc = v;
+       struct omdisplay_screen *screen = sc->sc_active;  /* ??? */
+
+       if ((offset & PAGE_MASK) != 0)
+               return (-1);
+
+       if (screen == NULL)
+               return (-1);
+
+       if (offset < 0 ||
+           offset >= screen->rinfo.ri_stride * screen->rinfo.ri_height)
+               return (-1);
+
+       return (bus_dmamem_mmap(sc->sc_dma_tag, screen->segs, screen->nsegs,
+           offset, prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT));
+}
+
+void
+omdisplay_free_screen(void *v, void *cookie)
+{
+       struct omdisplay_softc *sc = v;
+       struct rasops_info *ri = cookie;
+       struct omdisplay_screen *scr = ri->ri_hw;
+
+       LIST_REMOVE(scr, link);
+       sc->sc_nscreens--;
+       if (scr == sc->sc_active) {
+               /* at first, we need to stop LCD DMA */
+               sc->sc_active = NULL;
+
+#ifdef DEBUG
+               printf("lcd_free on active screen\n");
+#endif
+
+               omdisplay_stop(sc);
+       }
+
+       if (scr->buf_va)
+               bus_dmamem_unmap(sc->sc_dma_tag, scr->buf_va, scr->map_size);
+
+       if (scr->nsegs > 0)
+               bus_dmamem_free(sc->sc_dma_tag, scr->segs, scr->nsegs);
+
+       free(scr, M_DEVBUF, 0);
+}
+
+int
+omdisplay_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
+{
+       struct omdisplay_softc *sc = v;
+       struct omdisplay_screen *scr = sc->sc_active;
+
+       if (scr == NULL)
+               return ENXIO;
+
+       return rasops_load_font(scr->rinfo, emulcookie, font);
+}
+
+int
+omdisplay_list_font(void *v, struct wsdisplay_font *font)
+{
+       struct omdisplay_softc *sc = v;
+       struct omdisplay_screen *scr = sc->sc_active;
+
+       if (scr == NULL)
+               return ENXIO;
+
+       return rasops_list_font(scr->rinfo, font);
+}
+
+void
+omdisplay_start(struct omdisplay_softc *sc)
+{
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL,
+           DISPC_CONTROL_GPOUT0 | DISPC_CONTROL_GPOUT1 |
+           DISPC_CONTROL_TFTDATALINES_18 /*XXX 18? */ |
+           DISPC_CONTROL_STNTFT |
+           DISPC_CONTROL_GOLCD |
+           DISPC_CONTROL_LCDENABLE);
+}
+
+void
+omdisplay_stop(struct omdisplay_softc *sc)
+{
+       bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL,
+           bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL) &
+           ~(DISPC_CONTROL_DIGITALENABLE|DISPC_CONTROL_LCDENABLE));
+
+       /* XXX - wait for end of frame? */
+}
+
+int
+omdisplay_intr(void *v)
+{
+       /* XXX */
+       return 1;
+}
+
diff --git a/omdog.c b/omdog.c
new file mode 100644 (file)
index 0000000..d3d54a5
--- /dev/null
+++ b/omdog.c
@@ -0,0 +1,190 @@
+/*     $OpenBSD: omdog.c,v 1.5 2014/12/10 12:27:56 mikeb Exp $ */
+/*
+ * Copyright (c) 2013 Federico G. Schwindt <fgsch@openbsd.org>
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/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>
+
+#define WIDR           0x00                    /* Identification Register */
+#define WCLR           0x24                    /* Control Register */
+#define  WCLR_PRE              (1 << 5)
+#define  WCLR_PTV              (0 << 2)
+#define WCRR           0x28                    /* Counter Register */
+#define WLDR           0x2c                    /* Load Register */
+#define WTGR           0x30                    /* Trigger Register */
+#define WWPS           0x34                    /* Write Posting Bits Reg. */
+#define  WWPS_WSPR             (1 << 4)
+#define  WWPS_WTGR             (1 << 3)
+#define  WWPS_WLDR             (1 << 2)
+#define  WWPS_WCRR             (1 << 1)
+#define  WWPS_WCLR             (1 << 0)
+#define WSPR           0x48                    /* Start/Stop Register */
+
+#define OMDOG_VAL(secs)        (0xffffffff - ((secs) * (32768 / (1 << 0))) + 1)
+
+
+struct omdog_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+
+       int                     sc_period;
+};
+
+struct omdog_softc *omdog_sc;
+
+void   omdog_attach(struct device *, struct device *, void *);
+int    omdog_activate(struct device *, int);
+void   omdog_start(struct omdog_softc *);
+void   omdog_stop(struct omdog_softc *);
+void   omdog_sync(struct omdog_softc *);
+int    omdog_cb(void *, int);
+void   omdog_reset(void);
+
+struct cfattach        omdog_ca = {
+       sizeof (struct omdog_softc), NULL, omdog_attach, NULL, omdog_activate
+};
+
+struct cfdriver omdog_cd = {
+       NULL, "omdog", DV_DULL
+};
+
+void
+omdog_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct omdog_softc *sc = (struct omdog_softc *) self;
+       u_int32_t rev;
+
+       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("%s: bus_space_map failed!", __func__);
+
+       rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR);
+
+       printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+       omdog_sc = sc;
+
+       omdog_stop(sc);
+
+#ifndef SMALL_KERNEL
+       wdog_register(omdog_cb, sc);
+#endif
+}
+
+int
+omdog_activate(struct device *self, int act)
+{
+       switch (act) {
+       case DVACT_POWERDOWN:
+#ifndef SMALL_KERNEL
+               wdog_shutdown(self);
+#endif
+               break;
+       }
+
+       return (0);
+}
+
+void
+omdog_start(struct omdog_softc *sc)
+{
+       /* Write the enable sequence data BBBBh followed by 4444h */
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
+       omdog_sync(sc);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
+       omdog_sync(sc);
+}
+
+void
+omdog_stop(struct omdog_softc *sc)
+{
+       /* Write the disable sequence data AAAAh followed by 5555h */
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
+       omdog_sync(sc);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
+       omdog_sync(sc);
+}
+
+void
+omdog_sync(struct omdog_softc *sc)
+{
+       while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
+           (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
+               delay(10);
+}
+
+int
+omdog_cb(void *self, int period)
+{
+       struct omdog_softc *sc = self;
+
+       if (sc->sc_period != 0 && sc->sc_period != period)
+               omdog_stop(sc);
+
+       if (period != 0) {
+               if (sc->sc_period != period) {
+                       /* Set the prescaler */
+                       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
+                           (WCLR_PRE|WCLR_PTV));
+
+                       /* Set the reload counter */
+                       bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
+                           OMDOG_VAL(period));
+               }
+
+               omdog_sync(sc);
+
+               /* Trigger the reload */
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
+                   ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));
+
+               if (sc->sc_period != period)
+                       omdog_start(sc);
+       }
+
+       sc->sc_period = period;
+
+       return (period);
+}
+
+void
+omdog_reset(void)
+{
+       if (omdog_sc == NULL)
+               return;
+
+       if (omdog_sc->sc_period != 0)
+               omdog_stop(omdog_sc);
+
+       bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
+           0xffffff80);
+
+       omdog_start(omdog_sc);
+
+       delay(100000);
+}
diff --git a/omehci.c b/omehci.c
new file mode 100644 (file)
index 0000000..1ee3a06
--- /dev/null
+++ b/omehci.c
@@ -0,0 +1,486 @@
+/*     $OpenBSD: omehci.c,v 1.3 2014/05/19 13:11:31 mpi Exp $ */
+
+/*
+ * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*-
+ * Copyright (c) 2011
+ *     Ben Gray <ben.r.gray@gmail.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/rwlock.h>
+#include <sys/timeout.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+#include <armv7/omap/omgpiovar.h>
+#include <armv7/omap/omehcivar.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+void   omehci_attach(struct device *, struct device *, void *);
+int    omehci_detach(struct device *, int);
+int    omehci_activate(struct device *, int);
+
+struct omehci_softc {
+       struct ehci_softc        sc;
+       void                    *sc_ih;
+       bus_space_handle_t       uhh_ioh;
+       bus_space_handle_t       tll_ioh;
+
+       uint32_t                 ehci_rev;
+       uint32_t                 tll_avail;
+
+       uint32_t                 port_mode[OMAP_HS_USB_PORTS];
+       uint32_t                 phy_reset[OMAP_HS_USB_PORTS];
+       uint32_t                 reset_gpio_pin[OMAP_HS_USB_PORTS];
+
+       void                     (*early_init)(void);
+};
+
+int omehci_init(struct omehci_softc *);
+void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port);
+void omehci_enable(struct omehci_softc *);
+void omehci_disable(struct omehci_softc *);
+void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask);
+void misc_setup(struct omehci_softc *sc);
+void omehci_phy_reset(uint32_t on, uint32_t _delay);
+void omehci_uhh_init(struct omehci_softc *sc);
+void omehci_v4_early_init(void);
+
+struct cfattach omehci_ca = {
+       sizeof (struct omehci_softc), NULL, omehci_attach,
+       omehci_detach, omehci_activate
+};
+
+void
+omehci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct omehci_softc     *sc = (struct omehci_softc *)self;
+       struct armv7_attach_args *aa = aux;
+       usbd_status              r;
+       char                    *devname = sc->sc.sc_bus.bdev.dv_xname;
+       uint32_t                 i;
+
+       sc->sc.iot = aa->aa_iot;
+       sc->sc.sc_bus.dmatag = aa->aa_dmat;
+       sc->sc.sc_size = aa->aa_dev->mem[0].size;
+
+       /* set defaults */
+       for (i = 0; i < 3; i++) {
+               sc->phy_reset[i] = 0;
+               sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
+               sc->reset_gpio_pin[i] = -1;
+       }
+
+       switch (board_id)
+       {
+       case BOARD_ID_OMAP4_PANDA:
+               sc->tll_avail = 0;
+               sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY;
+               sc->early_init = omehci_v4_early_init;
+               break;
+       default:
+               break;
+       }
+
+       /* Map I/O space */
+       if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[0].addr,
+               aa->aa_dev->mem[0].size, 0, &sc->sc.ioh)) {
+               printf(": cannot map mem space\n");
+               goto out;
+       }
+
+       if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[1].addr,
+               aa->aa_dev->mem[1].size, 0, &sc->uhh_ioh)) {
+               printf(": cannot map mem space\n");
+               goto mem0;
+       }
+
+       if (sc->tll_avail &&
+           bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
+               aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) {
+               printf(": cannot map mem space\n");
+               goto mem1;
+       }
+
+       printf("\n");
+
+       if (sc->early_init)
+               sc->early_init();
+
+       if (omehci_init(sc))
+               return;
+
+       /* Disable interrupts, so we don't get any spurious ones. */
+       sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
+       EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
+
+       sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_USB,
+           ehci_intr, &sc->sc, devname);
+       if (sc->sc_ih == NULL) {
+               printf(": unable to establish interrupt\n");
+               printf("XXX - disable ehci and prcm");
+               goto mem2;
+       }
+
+       strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor));
+       r = ehci_init(&sc->sc);
+       if (r != USBD_NORMAL_COMPLETION) {
+               printf("%s: init failed, error=%d\n", devname, r);
+               printf("XXX - disable ehci and prcm");
+               goto intr;
+       }
+
+       config_found(self, &sc->sc.sc_bus, usbctlprint);
+
+       goto out;
+
+intr:
+       arm_intr_disestablish(sc->sc_ih);
+       sc->sc_ih = NULL;
+mem2:
+       bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size);
+mem1:
+       bus_space_unmap(sc->sc.iot, sc->uhh_ioh, aa->aa_dev->mem[1].size);
+mem0:
+       bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+       sc->sc.sc_size = 0;
+out:
+       return;
+}
+
+int
+omehci_init(struct omehci_softc *sc)
+{
+       uint32_t i = 0, reg;
+       uint32_t reset_performed = 0;
+       uint32_t timeout = 0;
+       uint32_t tll_ch_mask = 0;
+
+       /* enable high speed usb host clock */
+       prcm_enablemodule(PRCM_USB);
+
+       /* Hold the PHY in reset while configuring */
+       for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
+               if (sc->phy_reset[i]) {
+                       /* Configure the GPIO to drive low (hold in reset) */
+                       if (sc->reset_gpio_pin[i] != -1) {
+                               omgpio_set_dir(sc->reset_gpio_pin[i],
+                                   OMGPIO_DIR_OUT);
+                               omgpio_clear_bit(sc->reset_gpio_pin[i]);
+                               reset_performed = 1;
+                       }
+               }
+       }
+
+       /* Hold the PHY in RESET for enough time till DIR is high */
+       if (reset_performed)
+               delay(10);
+
+       /* Read the UHH revision */
+       sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
+           OMAP_USBHOST_UHH_REVISION);
+
+       /* Initilise the low level interface module(s) */
+       if (sc->ehci_rev == OMAP_EHCI_REV1) {
+               /* Enable the USB TLL */
+               prcm_enablemodule(PRCM_USBTLL);
+
+               /* Perform TLL soft reset, and wait until reset is complete */
+               bus_space_write_4(sc->sc.iot, sc->tll_ioh,
+                   OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
+
+               /* Set the timeout to 100ms*/
+               timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+
+               /* Wait for TLL reset to complete */
+               while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh,
+                   OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE)
+                   == 0x00) {
+
+                       /* Sleep for a tick */
+                       delay(10);
+
+                       if (timeout-- == 0) {
+                               return 1;
+                       }
+               }
+
+               bus_space_write_4(sc->sc.iot, sc->tll_ioh,
+                   OMAP_USBTLL_SYSCONFIG,
+                   TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE |
+                   TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY);
+       } else if (sc->ehci_rev == OMAP_EHCI_REV2) {
+               /* For OMAP44xx devices you have to enable the per-port clocks:
+                *  PHY_MODE  - External ULPI clock
+                *  TTL_MODE  - Internal UTMI clock
+                *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
+                */
+               if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
+                       //ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
+                       prcm_enablemodule(PRCM_USBP1_PHY);
+               } else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+                       prcm_enablemodule(PRCM_USBP1_UTMI);
+               else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+                       prcm_enablemodule(PRCM_USBP1_HSIC);
+
+               if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
+                       //ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
+                       prcm_enablemodule(PRCM_USBP2_PHY);
+               } else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+                       prcm_enablemodule(PRCM_USBP2_UTMI);
+               else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+                       prcm_enablemodule(PRCM_USBP2_HSIC);
+       }
+
+       /* Put UHH in SmartIdle/SmartStandby mode */
+       reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
+           OMAP_USBHOST_UHH_SYSCONFIG);
+       if (sc->ehci_rev == OMAP_EHCI_REV1) {
+               reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
+                        UHH_SYSCONFIG_MIDLEMODE_MASK);
+               reg |= (UHH_SYSCONFIG_ENAWAKEUP |
+                       UHH_SYSCONFIG_AUTOIDLE |
+                       UHH_SYSCONFIG_CLOCKACTIVITY |
+                       UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
+                       UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
+       } else if (sc->ehci_rev == OMAP_EHCI_REV2) {
+               reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
+               reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
+               reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
+               reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
+       }
+       bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG,
+           reg);
+
+       reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
+           OMAP_USBHOST_UHH_HOSTCONFIG);
+
+       /* Setup ULPI bypass and burst configurations */
+       reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
+               UHH_HOSTCONFIG_ENA_INCR8 |
+               UHH_HOSTCONFIG_ENA_INCR16);
+       reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
+
+       if (sc->ehci_rev == OMAP_EHCI_REV1) {
+               if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+                       reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+               if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+                       reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+               if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+                       reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+
+               /* Bypass the TLL module for PHY mode operation */
+               if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
+                   (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
+                   (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
+                       reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+               else
+                       reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+       } else if (sc->ehci_rev == OMAP_EHCI_REV2) {
+               reg |=  UHH_HOSTCONFIG_APP_START_CLK;
+               
+               /* Clear port mode fields for PHY mode*/
+               reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
+               reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
+
+               if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+                       reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
+               else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+                       reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
+
+               if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+                       reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
+               else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+                       reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
+       }
+
+       bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
+
+       /* If any of the ports are configured in TLL mode, enable them */
+       for (i = 0; i < OMAP_HS_USB_PORTS; i++)
+               if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
+                       tll_ch_mask |= 1 << i;
+
+       /* Enable UTMI mode for required TLL channels */
+#ifdef notyet
+       if (tll_ch_mask)
+               omap_ehci_utmi_init(sc, tll_ch_mask);
+#endif
+
+       /* Release the PHY reset signal now we have configured everything */
+       if (reset_performed) {
+               /* Delay for 10ms */
+               delay(10000);
+
+               /* Release reset */
+               for (i = 0; i < 3; i++) {
+                       if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1))
+                               omgpio_set_bit(sc->reset_gpio_pin[i]);
+               }
+       }
+
+       /* Set the interrupt threshold control, it controls the maximum rate at
+        * which the host controller issues interrupts.  We set it to 1 microframe
+        * at startup - the default is 8 mircoframes (equates to 1ms).
+        */
+       reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD);
+       reg &= 0xff00ffff;
+       reg |= (1 << 16);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg);
+
+       /* Soft reset the PHY using PHY reset command over ULPI */
+       for (i = 0; i < OMAP_HS_USB_PORTS; i++)
+               if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
+                       omehci_soft_phy_reset(sc, i);
+
+       return(0);
+}
+
+void
+omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port)
+{
+       unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+       uint32_t reg;
+
+       reg = ULPI_FUNC_CTRL_RESET
+               /* FUNCTION_CTRL_SET register */
+               | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
+               /* Write */
+               | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
+               /* PORTn */
+               | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
+               /* start ULPI access*/
+               | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
+
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg);
+
+       timeout += 1000000;
+       /* Wait for ULPI access completion */
+       while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI)
+                       & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
+
+               /* Sleep for a tick */
+               delay(10);
+
+               if (timeout-- == 0) {
+                       printf("PHY reset operation timed out\n");
+                       break;
+               }
+       }
+}
+
+int
+omehci_detach(struct device *self, int flags)
+{
+       struct omehci_softc             *sc = (struct omehci_softc *)self;
+       int                             rv;
+
+       rv = ehci_detach(self, flags);
+       if (rv)
+               return (rv);
+
+       if (sc->sc_ih != NULL) {
+               arm_intr_disestablish(sc->sc_ih);
+               sc->sc_ih = NULL;
+       }
+
+       if (sc->sc.sc_size) {
+               bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+               sc->sc.sc_size = 0;
+       }
+
+       /* XXX: stop clock */
+
+       return (0);
+}
+
+int
+omehci_activate(struct device *self, int act)
+{
+       struct omehci_softc *sc = (struct omehci_softc *)self;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               sc->sc.sc_bus.use_polling++;
+               /* FIXME */
+               sc->sc.sc_bus.use_polling--;
+               break;
+       case DVACT_RESUME:
+               sc->sc.sc_bus.use_polling++;
+               /* FIXME */
+               sc->sc.sc_bus.use_polling--;
+               break;
+       case DVACT_POWERDOWN:
+               ehci_reset(&sc->sc);
+               break;
+       }
+       return 0;
+}
+
+void
+omehci_v4_early_init()
+{
+       omgpio_set_dir(1, OMGPIO_DIR_OUT);
+       omgpio_clear_bit(1);
+       omgpio_set_dir(62, OMGPIO_DIR_OUT);
+       omgpio_clear_bit(62);
+
+       /* wait for power down */
+       delay(1000);
+
+       omgpio_set_bit(1);
+       omgpio_set_bit(62);
+
+       /* wait until powered up */
+       delay(1000);
+}
diff --git a/omehcivar.h b/omehcivar.h
new file mode 100644 (file)
index 0000000..8eed72d
--- /dev/null
@@ -0,0 +1,232 @@
+/* $OpenBSD: omehcivar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */
+
+/*
+ * Misc
+ */
+#define OMAP_HS_USB_PORTS                           3
+
+/*
+ * USB TTL Module
+ */
+#define        OMAP_USBTLL_REVISION                        0x0000
+#define        OMAP_USBTLL_SYSCONFIG                       0x0010
+#define        OMAP_USBTLL_SYSSTATUS                       0x0014
+#define        OMAP_USBTLL_IRQSTATUS                       0x0018
+#define        OMAP_USBTLL_IRQENABLE                       0x001C
+#define        OMAP_USBTLL_TLL_SHARED_CONF                 0x0030
+#define        OMAP_USBTLL_TLL_CHANNEL_CONF(i)             (0x0040 + (0x04 * (i)))
+#define        OMAP_USBTLL_SAR_CNTX(i)                     (0x0400 + (0x04 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_ID_LO(i)            (0x0800 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_ID_HI(i)            (0x0801 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i)           (0x0802 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i)           (0x0803 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_FUNCTION_CTRL(i)           (0x0804 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i)       (0x0805 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i)       (0x0806 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_INTERFACE_CTRL(i)          (0x0807 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i)      (0x0808 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i)      (0x0809 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_OTG_CTRL(i)                (0x080A + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_OTG_CTRL_SET(i)            (0x080B + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i)            (0x080C + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i)         (0x080D + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i)     (0x080E + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i)     (0x080F + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i)         (0x0810 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i)     (0x0811 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i)     (0x0812 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_STATUS(i)          (0x0813 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_LATCH(i)           (0x0814 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_DEBUG(i)                   (0x0815 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i)        (0x0816 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i)    (0x0817 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i)    (0x0818 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i)     (0x082F + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i)        (0x0830 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i)    (0x0831 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i)    (0x0832 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i)    (0x0833 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i)     (0x0834 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VSTATUS(i)            (0x0835 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i)        (0x0836 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i)        (0x0837 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i)     (0x0838 + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_INT_EN(i)           (0x083B + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i)       (0x083C + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i)       (0x083D + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i)       (0x083E + (0x100 * (i)))
+#define        OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i)        (0x083F + (0x100 * (i)))
+
+
+/*
+ * USB Host Module
+ */
+
+/* UHH */
+#define        OMAP_USBHOST_UHH_REVISION                   0x0000
+#define        OMAP_USBHOST_UHH_SYSCONFIG                  0x0010
+#define        OMAP_USBHOST_UHH_SYSSTATUS                  0x0014
+#define        OMAP_USBHOST_UHH_HOSTCONFIG                 0x0040
+#define        OMAP_USBHOST_UHH_DEBUG_CSR                  0x0044
+
+/* EHCI */
+#define        OMAP_USBHOST_HCCAPBASE                      0x0000
+#define        OMAP_USBHOST_HCSPARAMS                      0x0004
+#define        OMAP_USBHOST_HCCPARAMS                      0x0008
+#define        OMAP_USBHOST_USBCMD                         0x0010
+#define        OMAP_USBHOST_USBSTS                         0x0014
+#define        OMAP_USBHOST_USBINTR                        0x0018
+#define        OMAP_USBHOST_FRINDEX                        0x001C
+#define        OMAP_USBHOST_CTRLDSSEGMENT                  0x0020
+#define        OMAP_USBHOST_PERIODICLISTBASE               0x0024
+#define        OMAP_USBHOST_ASYNCLISTADDR                  0x0028
+#define        OMAP_USBHOST_CONFIGFLAG                     0x0050
+#define        OMAP_USBHOST_PORTSC(i)                      (0x0054 + (0x04 * (i)))
+#define        OMAP_USBHOST_INSNREG00                      0x0090
+#define        OMAP_USBHOST_INSNREG01                      0x0094
+#define        OMAP_USBHOST_INSNREG02                      0x0098
+#define        OMAP_USBHOST_INSNREG03                      0x009C
+#define        OMAP_USBHOST_INSNREG04                      0x00A0
+#define        OMAP_USBHOST_INSNREG05_UTMI                 0x00A4
+#define        OMAP_USBHOST_INSNREG05_ULPI                 0x00A4
+#define        OMAP_USBHOST_INSNREG06                      0x00A8
+#define        OMAP_USBHOST_INSNREG07                      0x00AC
+#define        OMAP_USBHOST_INSNREG08                      0x00B0
+
+#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND   (1 << 5)
+
+#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT   31
+#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT   24
+#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT     22
+#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT    16
+#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8
+#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT    0
+
+
+
+
+
+/* TLL Register Set */
+#define        TLL_SYSCONFIG_CACTIVITY                 (1UL << 8)
+#define        TLL_SYSCONFIG_SIDLE_SMART_IDLE          (2UL << 3)
+#define        TLL_SYSCONFIG_SIDLE_NO_IDLE             (1UL << 3)
+#define        TLL_SYSCONFIG_SIDLE_FORCED_IDLE         (0UL << 3)
+#define        TLL_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
+#define        TLL_SYSCONFIG_SOFTRESET                 (1UL << 1)
+#define        TLL_SYSCONFIG_AUTOIDLE                  (1UL << 0)
+
+#define        TLL_SYSSTATUS_RESETDONE                 (1UL << 0)
+
+#define TLL_SHARED_CONF_USB_90D_DDR_EN          (1UL << 6)
+#define TLL_SHARED_CONF_USB_180D_SDR_EN         (1UL << 5)
+#define TLL_SHARED_CONF_USB_DIVRATIO_MASK       (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_128        (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_64         (6UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_32         (5UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_16         (4UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_8          (3UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_4          (2UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_2          (1UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_1          (0UL << 2)
+#define TLL_SHARED_CONF_FCLK_REQ                (1UL << 1)
+#define TLL_SHARED_CONF_FCLK_IS_ON              (1UL << 0)
+
+#define TLL_CHANNEL_CONF_DRVVBUS                (1UL << 16)
+#define TLL_CHANNEL_CONF_CHRGVBUS               (1UL << 15)
+#define TLL_CHANNEL_CONF_ULPINOBITSTUFF         (1UL << 11)
+#define TLL_CHANNEL_CONF_ULPIAUTOIDLE           (1UL << 10)
+#define TLL_CHANNEL_CONF_UTMIAUTOIDLE           (1UL << 9)
+#define TLL_CHANNEL_CONF_ULPIDDRMODE            (1UL << 8)
+#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE         (1UL << 7)
+#define TLL_CHANNEL_CONF_TLLFULLSPEED           (1UL << 6)
+#define TLL_CHANNEL_CONF_TLLCONNECT             (1UL << 5)
+#define TLL_CHANNEL_CONF_TLLATTACH              (1UL << 4)
+#define TLL_CHANNEL_CONF_UTMIISADEV             (1UL << 3)
+#define TLL_CHANNEL_CONF_CHANEN                 (1UL << 0)
+
+
+/* UHH Register Set */
+#define UHH_SYSCONFIG_MIDLEMODE_MASK            (3UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY    (2UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY       (1UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY    (0UL << 12)
+#define UHH_SYSCONFIG_CLOCKACTIVITY             (1UL << 8)
+#define UHH_SYSCONFIG_SIDLEMODE_MASK            (3UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE       (2UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE          (1UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE       (0UL << 3)
+#define UHH_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
+#define UHH_SYSCONFIG_SOFTRESET                 (1UL << 1)
+#define UHH_SYSCONFIG_AUTOIDLE                  (1UL << 0)
+
+#define UHH_HOSTCONFIG_APP_START_CLK            (1UL << 31)
+#define UHH_HOSTCONFIG_P3_CONNECT_STATUS        (1UL << 10)
+#define UHH_HOSTCONFIG_P2_CONNECT_STATUS        (1UL << 9)
+#define UHH_HOSTCONFIG_P1_CONNECT_STATUS        (1UL << 8)
+#define UHH_HOSTCONFIG_ENA_INCR_ALIGN           (1UL << 5)
+#define UHH_HOSTCONFIG_ENA_INCR16               (1UL << 4)
+#define UHH_HOSTCONFIG_ENA_INCR8                (1UL << 3)
+#define UHH_HOSTCONFIG_ENA_INCR4                (1UL << 2)
+#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN    (1UL << 1)
+#define UHH_HOSTCONFIG_P1_ULPI_BYPASS           (1UL << 0)
+
+/* The following are on rev2 (OMAP44xx) of the EHCI only */ 
+#define UHH_SYSCONFIG_IDLEMODE_MASK             (3UL << 2)
+#define UHH_SYSCONFIG_IDLEMODE_NOIDLE           (1UL << 2)
+#define UHH_SYSCONFIG_STANDBYMODE_MASK          (3UL << 4)
+#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY       (1UL << 4)
+
+#define UHH_HOSTCONFIG_P1_MODE_MASK             (3UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY         (0UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY         (1UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_HSIC             (3UL << 16)
+#define UHH_HOSTCONFIG_P2_MODE_MASK             (3UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY         (0UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY         (1UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_HSIC             (3UL << 18)
+
+#define ULPI_FUNC_CTRL_RESET                    (1 << 5)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Macros for Set and Clear
+ * See ULPI 1.1 specification to find the registers with Set and Clear offsets
+ */
+#define ULPI_SET(a)                             (a + 1)
+#define ULPI_CLR(a)                             (a + 2)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Register Map
+ */
+#define ULPI_VENDOR_ID_LOW                      0x00
+#define ULPI_VENDOR_ID_HIGH                     0x01
+#define ULPI_PRODUCT_ID_LOW                     0x02
+#define ULPI_PRODUCT_ID_HIGH                    0x03
+#define ULPI_FUNC_CTRL                          0x04
+#define ULPI_IFC_CTRL                           0x07
+#define ULPI_OTG_CTRL                           0x0a
+#define ULPI_USB_INT_EN_RISE                    0x0d
+#define ULPI_USB_INT_EN_FALL                    0x10
+#define ULPI_USB_INT_STS                        0x13
+#define ULPI_USB_INT_LATCH                      0x14
+#define ULPI_DEBUG                              0x15
+#define ULPI_SCRATCH                            0x16
+
+/* 
+ * Values of UHH_REVISION - Note: these are not given in the TRM but taken
+ * from the linux OMAP EHCI driver (thanks guys).  It has been verified on
+ * a Panda and Beagle board.
+ */
+#define OMAP_EHCI_REV1  0x00000010      /* OMAP3 */
+#define OMAP_EHCI_REV2  0x50700100      /* OMAP4 */
+
+#define EHCI_VENDORID_OMAP3     0x42fa05
+#define OMAP_EHCI_HC_DEVSTR    "TI OMAP USB 2.0 controller"
+
+#define EHCI_HCD_OMAP_MODE_UNKNOWN  0
+#define EHCI_HCD_OMAP_MODE_PHY      1
+#define EHCI_HCD_OMAP_MODE_TLL      2
+#define EHCI_HCD_OMAP_MODE_HSIC     3
diff --git a/omgpio.c b/omgpio.c
new file mode 100644 (file)
index 0000000..5df65bd
--- /dev/null
+++ b/omgpio.c
@@ -0,0 +1,763 @@
+/* $OpenBSD: omgpio.c,v 1.6 2016/01/31 00:14:50 jsg Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/evcount.h>
+#include <sys/gpio.h>
+
+#include <arm/cpufunc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/gpio/gpiovar.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+#include <armv7/omap/sitara_cm.h>
+#include <armv7/omap/omgpiovar.h>
+
+#include "gpio.h"
+
+/* OMAP3 registers */
+#define        GPIO3_REVISION          0x00
+#define        GPIO3_SYSCONFIG         0x10
+#define        GPIO3_SYSSTATUS         0x14
+#define        GPIO3_IRQSTATUS1        0x18
+#define        GPIO3_IRQENABLE1        0x1C
+#define        GPIO3_WAKEUPENABLE      0x20
+#define        GPIO3_IRQSTATUS2        0x28
+#define        GPIO3_IRQENABLE2        0x2C
+#define        GPIO3_CTRL              0x30
+#define        GPIO3_OE                0x34
+#define        GPIO3_DATAIN            0x38
+#define        GPIO3_DATAOUT           0x3C
+#define        GPIO3_LEVELDETECT0      0x40
+#define        GPIO3_LEVELDETECT1      0x44
+#define        GPIO3_RISINGDETECT      0x48
+#define        GPIO3_FALLINGDETECT     0x4C
+#define        GPIO3_DEBOUNCENABLE     0x50
+#define        GPIO3_DEBOUNCINGTIME    0x54
+#define        GPIO3_CLEARIRQENABLE1   0x60
+#define        GPIO3_SETIRQENABLE1     0x64
+#define        GPIO3_CLEARIRQENABLE2   0x70
+#define        GPIO3_SETIRQENABLE2     0x74
+#define        GPIO3_CLEARWKUENA       0x80
+#define        GPIO3_SETWKUENA         0x84
+#define        GPIO3_CLEARDATAOUT      0x90
+#define        GPIO3_SETDATAOUT        0x94
+
+/* OMAP4 registers */
+#define GPIO4_REVISION         0x00
+#define GPIO4_SYSCONFIG                0x10
+#define GPIO4_IRQSTATUS_RAW_0  0x24
+#define GPIO4_IRQSTATUS_RAW_1  0x28
+#define GPIO4_IRQSTATUS_0      0x2C
+#define GPIO4_IRQSTATUS_1      0x30
+#define GPIO4_IRQSTATUS_SET_0  0x34
+#define GPIO4_IRQSTATUS_SET_1  0x38
+#define GPIO4_IRQSTATUS_CLR_0  0x3C
+#define GPIO4_IRQSTATUS_CLR_1  0x40
+#define GPIO4_IRQWAKEN_0       0x44
+#define GPIO4_IRQWAKEN_1       0x48
+#define GPIO4_SYSSTATUS                0x114
+#define GPIO4_WAKEUPENABLE     0x120
+#define GPIO4_CTRL             0x130
+#define GPIO4_OE               0x134
+#define GPIO4_DATAIN           0x138
+#define GPIO4_DATAOUT          0x13C
+#define GPIO4_LEVELDETECT0     0x140
+#define GPIO4_LEVELDETECT1     0x144
+#define GPIO4_RISINGDETECT     0x148
+#define GPIO4_FALLINGDETECT    0x14C
+#define GPIO4_DEBOUNCENABLE    0x150
+#define GPIO4_DEBOUNCINGTIME   0x154
+#define GPIO4_CLEARWKUPENA     0x180
+#define GPIO4_SETWKUENA                0x184
+#define GPIO4_CLEARDATAOUT     0x190
+#define GPIO4_SETDATAOUT       0x194
+
+/* AM335X registers */
+#define GPIO_AM335X_REVISION           0x00
+#define GPIO_AM335X_SYSCONFIG          0x10
+#define GPIO_AM335X_IRQSTATUS_RAW_0    0x24
+#define GPIO_AM335X_IRQSTATUS_RAW_1    0x28
+#define GPIO_AM335X_IRQSTATUS_0                0x2C
+#define GPIO_AM335X_IRQSTATUS_1                0x30
+#define GPIO_AM335X_IRQSTATUS_SET_0    0x34
+#define GPIO_AM335X_IRQSTATUS_SET_1    0x38
+#define GPIO_AM335X_IRQSTATUS_CLR_0    0x3c
+#define GPIO_AM335X_IRQSTATUS_CLR_1    0x40
+#define GPIO_AM335X_IRQWAKEN_0         0x44
+#define GPIO_AM335X_IRQWAKEN_1         0x48
+#define GPIO_AM335X_SYSSTATUS          0x114
+#define GPIO_AM335X_CTRL               0x130
+#define GPIO_AM335X_OE                 0x134
+#define GPIO_AM335X_DATAIN             0x138
+#define GPIO_AM335X_DATAOUT            0x13C
+#define GPIO_AM335X_LEVELDETECT0       0x140
+#define GPIO_AM335X_LEVELDETECT1       0x144
+#define GPIO_AM335X_RISINGDETECT       0x148
+#define GPIO_AM335X_FALLINGDETECT      0x14C
+#define GPIO_AM335X_DEBOUNCENABLE      0x150
+#define GPIO_AM335X_DEBOUNCINGTIME     0x154
+#define GPIO_AM335X_CLEARDATAOUT       0x190
+#define GPIO_AM335X_SETDATAOUT         0x194
+
+#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 omgpio_regs {
+       u_int32_t       revision;
+       u_int32_t       sysconfig;
+       u_int32_t       irqstatus_raw0;         /* omap4/am335x only */
+       u_int32_t       irqstatus_raw1;         /* omap4/am335x only */
+       u_int32_t       irqstatus0;
+       u_int32_t       irqstatus1;
+       u_int32_t       irqstatus_set0;
+       u_int32_t       irqstatus_set1;
+       u_int32_t       irqstatus_clear0;
+       u_int32_t       irqstatus_clear1;
+       u_int32_t       irqwaken0;
+       u_int32_t       irqwaken1;
+       u_int32_t       sysstatus;
+       u_int32_t       wakeupenable;           /* omap3/omap4 only */
+       u_int32_t       ctrl;
+       u_int32_t       oe;
+       u_int32_t       datain;
+       u_int32_t       dataout;
+       u_int32_t       leveldetect0;
+       u_int32_t       leveldetect1;
+       u_int32_t       risingdetect;
+       u_int32_t       fallingdetect;
+       u_int32_t       debounceenable;
+       u_int32_t       debouncingtime;
+       u_int32_t       clearwkupena;           /* omap3/omap4 only */
+       u_int32_t       setwkupena;             /* omap3/omap4 only */
+       u_int32_t       cleardataout;
+       u_int32_t       setdataout;
+};
+
+struct omgpio_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];
+       int                     sc_omap_ver;
+       struct gpio_chipset_tag sc_gpio_gc;
+       gpio_pin_t              sc_gpio_pins[GPIO_NUM_PINS];
+       struct omgpio_regs      sc_regs;
+};
+
+#define GPIO_PIN_TO_INST(x)    ((x) >> 5)
+#define GPIO_PIN_TO_OFFSET(x)  ((x) & 0x1f)
+#define DEVNAME(sc)    ((sc)->sc_dev.dv_xname)
+#define READ4(sc, reg)         omgpio_read4(sc, reg)
+#define WRITE4(sc, reg, val)   omgpio_write4(sc, reg, val)
+
+u_int32_t omgpio_read4(struct omgpio_softc *, u_int32_t);
+void omgpio_write4(struct omgpio_softc *, u_int32_t, u_int32_t);
+int omgpio_match(struct device *, void *, void *);
+void omgpio_attach(struct device *, struct device *, void *);
+void omgpio_recalc_interrupts(struct omgpio_softc *);
+int omgpio_irq(void *);
+int omgpio_irq_dummy(void *);
+int omgpio_pin_dir_read(struct omgpio_softc *, unsigned int);
+void omgpio_pin_dir_write(struct omgpio_softc *, unsigned int, unsigned int);
+
+struct cfattach omgpio_ca = {
+       sizeof (struct omgpio_softc), omgpio_match, omgpio_attach
+};
+
+struct cfdriver omgpio_cd = {
+       NULL, "omgpio", DV_DULL
+};
+
+u_int32_t
+omgpio_read4(struct omgpio_softc *sc, u_int32_t reg)
+{
+       if(reg == -1)
+               panic("%s: Invalid register address", DEVNAME(sc));
+
+       return bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg));
+}
+
+void
+omgpio_write4(struct omgpio_softc *sc, u_int32_t reg, u_int32_t val)
+{
+       if(reg == -1)
+               panic("%s: Invalid register address", DEVNAME(sc));
+
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val));
+}
+
+int
+omgpio_match(struct device *parent, void *v, void *aux)
+{
+       switch (board_id) {
+       case BOARD_ID_OMAP3_BEAGLE:
+       case BOARD_ID_OMAP3_OVERO:
+       case BOARD_ID_AM335X_BEAGLEBONE:
+       case BOARD_ID_OMAP4_PANDA:
+               break; /* continue trying */
+       default:
+               return 0; /* unknown */
+       }
+       return (1);
+}
+
+void
+omgpio_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct omgpio_softc *sc = (struct omgpio_softc *) self;
+       struct gpiobus_attach_args gba;
+       u_int32_t       rev;
+       int             i;
+
+       prcm_enablemodule(PRCM_GPIO0 + 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("%s: bus_space_map failed!", DEVNAME(sc));
+
+       switch (board_id) {
+       case BOARD_ID_OMAP3_BEAGLE:
+       case BOARD_ID_OMAP3_OVERO:
+               sc->sc_regs.revision = GPIO3_REVISION;
+               sc->sc_regs.sysconfig = GPIO3_SYSCONFIG;
+               sc->sc_regs.irqstatus_raw0 = -1;
+               sc->sc_regs.irqstatus_raw1 = -1;
+               sc->sc_regs.irqstatus0 = GPIO3_IRQSTATUS1;
+               sc->sc_regs.irqstatus1 = GPIO3_IRQSTATUS2;
+               sc->sc_regs.irqstatus_set0 = GPIO3_SETIRQENABLE1;
+               sc->sc_regs.irqstatus_set1 = GPIO3_SETIRQENABLE2;
+               sc->sc_regs.irqstatus_clear0 = GPIO3_CLEARIRQENABLE1;
+               sc->sc_regs.irqstatus_clear1 = GPIO3_CLEARIRQENABLE2;
+               sc->sc_regs.irqwaken0 = -1;
+               sc->sc_regs.irqwaken1 = -1;
+               sc->sc_regs.sysstatus = GPIO3_SYSSTATUS;
+               sc->sc_regs.wakeupenable = GPIO3_WAKEUPENABLE;
+               sc->sc_regs.ctrl = GPIO3_CTRL;
+               sc->sc_regs.oe = GPIO3_OE;
+               sc->sc_regs.datain = GPIO3_DATAIN;
+               sc->sc_regs.dataout = GPIO3_DATAOUT;
+               sc->sc_regs.leveldetect0 = GPIO3_LEVELDETECT0;
+               sc->sc_regs.leveldetect1 = GPIO3_LEVELDETECT1;
+               sc->sc_regs.risingdetect = GPIO3_RISINGDETECT;
+               sc->sc_regs.fallingdetect = GPIO3_FALLINGDETECT;
+               sc->sc_regs.debounceenable = GPIO3_DEBOUNCENABLE;
+               sc->sc_regs.debouncingtime = GPIO3_DEBOUNCINGTIME;
+               sc->sc_regs.clearwkupena = GPIO3_CLEARWKUENA;
+               sc->sc_regs.setwkupena = GPIO3_SETWKUENA;
+               sc->sc_regs.cleardataout = GPIO3_CLEARDATAOUT;
+               sc->sc_regs.setdataout = GPIO3_SETDATAOUT;
+               break;
+       case BOARD_ID_OMAP4_PANDA:
+               sc->sc_regs.revision = GPIO4_REVISION;
+               sc->sc_regs.sysconfig = GPIO4_SYSCONFIG;
+               sc->sc_regs.irqstatus_raw0 = GPIO4_IRQSTATUS_RAW_0;
+               sc->sc_regs.irqstatus_raw1 = GPIO4_IRQSTATUS_RAW_1;
+               sc->sc_regs.irqstatus0 = GPIO4_IRQSTATUS_0;
+               sc->sc_regs.irqstatus1 = GPIO4_IRQSTATUS_1;
+               sc->sc_regs.irqstatus_set0 = GPIO4_IRQSTATUS_SET_0;
+               sc->sc_regs.irqstatus_set1 = GPIO4_IRQSTATUS_SET_1;
+               sc->sc_regs.irqstatus_clear0 = GPIO4_IRQSTATUS_CLR_0;
+               sc->sc_regs.irqstatus_clear1 = GPIO4_IRQSTATUS_CLR_1;
+               sc->sc_regs.irqwaken0 = GPIO4_IRQWAKEN_0;
+               sc->sc_regs.irqwaken1 = GPIO4_IRQWAKEN_1;
+               sc->sc_regs.sysstatus = GPIO4_SYSSTATUS;
+               sc->sc_regs.wakeupenable = GPIO4_WAKEUPENABLE;
+               sc->sc_regs.ctrl = GPIO4_CTRL;
+               sc->sc_regs.oe = GPIO4_OE;
+               sc->sc_regs.datain = GPIO4_DATAIN;
+               sc->sc_regs.dataout = GPIO4_DATAOUT;
+               sc->sc_regs.leveldetect0 = GPIO4_LEVELDETECT0;
+               sc->sc_regs.leveldetect1 = GPIO4_LEVELDETECT1;
+               sc->sc_regs.risingdetect = GPIO4_RISINGDETECT;
+               sc->sc_regs.fallingdetect = GPIO4_FALLINGDETECT;
+               sc->sc_regs.debounceenable = GPIO4_DEBOUNCENABLE;
+               sc->sc_regs.debouncingtime = GPIO4_DEBOUNCINGTIME;
+               sc->sc_regs.clearwkupena = GPIO4_CLEARWKUPENA;
+               sc->sc_regs.setwkupena = GPIO4_SETWKUENA;
+               sc->sc_regs.cleardataout = GPIO4_CLEARDATAOUT;
+               sc->sc_regs.setdataout = GPIO4_SETDATAOUT;
+               break;
+       case BOARD_ID_AM335X_BEAGLEBONE:
+               sc->sc_regs.revision = GPIO_AM335X_REVISION;
+               sc->sc_regs.sysconfig = GPIO_AM335X_SYSCONFIG;
+               sc->sc_regs.irqstatus_raw0 = GPIO_AM335X_IRQSTATUS_RAW_0;
+               sc->sc_regs.irqstatus_raw1 = GPIO_AM335X_IRQSTATUS_RAW_1;
+               sc->sc_regs.irqstatus0 = GPIO_AM335X_IRQSTATUS_0;
+               sc->sc_regs.irqstatus1 = GPIO_AM335X_IRQSTATUS_1;
+               sc->sc_regs.irqstatus_set0 = GPIO_AM335X_IRQSTATUS_SET_0;
+               sc->sc_regs.irqstatus_set1 = GPIO_AM335X_IRQSTATUS_SET_1;
+               sc->sc_regs.irqstatus_clear0 = GPIO_AM335X_IRQSTATUS_CLR_0;
+               sc->sc_regs.irqstatus_clear1 = GPIO_AM335X_IRQSTATUS_CLR_1;
+               sc->sc_regs.irqwaken0 = GPIO_AM335X_IRQWAKEN_0;
+               sc->sc_regs.irqwaken1 = GPIO_AM335X_IRQWAKEN_1;
+               sc->sc_regs.sysstatus = GPIO_AM335X_SYSSTATUS;
+               sc->sc_regs.wakeupenable = -1;
+               sc->sc_regs.ctrl = GPIO_AM335X_CTRL;
+               sc->sc_regs.oe = GPIO_AM335X_OE;
+               sc->sc_regs.datain = GPIO_AM335X_DATAIN;
+               sc->sc_regs.dataout = GPIO_AM335X_DATAOUT;
+               sc->sc_regs.leveldetect0 = GPIO_AM335X_LEVELDETECT0;
+               sc->sc_regs.leveldetect1 = GPIO_AM335X_LEVELDETECT1;
+               sc->sc_regs.risingdetect = GPIO_AM335X_RISINGDETECT;
+               sc->sc_regs.fallingdetect = GPIO_AM335X_FALLINGDETECT;
+               sc->sc_regs.debounceenable = GPIO_AM335X_DEBOUNCENABLE;
+               sc->sc_regs.debouncingtime = GPIO_AM335X_DEBOUNCINGTIME;
+               sc->sc_regs.clearwkupena = -1;
+               sc->sc_regs.setwkupena = -1;
+               sc->sc_regs.cleardataout = GPIO_AM335X_CLEARDATAOUT;
+               sc->sc_regs.setdataout = GPIO_AM335X_SETDATAOUT;
+               break;
+       }
+
+       rev = READ4(sc, sc->sc_regs.revision);
+
+       printf(": rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+
+       sc->sc_irq = aa->aa_dev->irq[0];
+
+       WRITE4(sc, sc->sc_regs.irqstatus_clear0, ~0);
+       WRITE4(sc, sc->sc_regs.irqstatus_clear1, ~0);
+
+       /* XXX - SYSCONFIG */
+       /* XXX - CTRL */
+       /* XXX - DEBOUNCE */
+
+       for (i = 0; i < GPIO_NUM_PINS; i++) {
+               sc->sc_gpio_pins[i].pin_num = i;
+               sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
+                   GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
+               sc->sc_gpio_pins[i].pin_state = omgpio_pin_read(sc, i) ?
+                   GPIO_PIN_HIGH : GPIO_PIN_LOW;
+               sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_SET;
+       }
+
+       sc->sc_gpio_gc.gp_cookie = sc;
+       sc->sc_gpio_gc.gp_pin_read = omgpio_pin_read;
+       sc->sc_gpio_gc.gp_pin_write = omgpio_pin_write;
+       sc->sc_gpio_gc.gp_pin_ctl = omgpio_pin_ctl;
+
+       gba.gba_name = "gpio";
+       gba.gba_gc = &sc->sc_gpio_gc;
+       gba.gba_pins = sc->sc_gpio_pins;
+       gba.gba_npins = GPIO_NUM_PINS;
+
+#if NGPIO > 0
+       config_found(&sc->sc_dev, &gba, gpiobus_print);
+#endif
+}
+
+/* XXX - This assumes MCU INTERRUPTS are IRQ1, and DSP are IRQ2 */
+
+#if 0
+/* XXX - FIND THESE REGISTERS !!! */
+unsigned int
+omgpio_get_function(unsigned int gpio, unsigned int fn)
+{
+       return 0;
+}
+
+void
+omgpio_set_function(unsigned int gpio, unsigned int fn)
+{
+}
+#endif
+
+unsigned int
+omgpio_get_bit(unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       return omgpio_pin_read(sc, GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_set_bit(unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_HIGH);
+}
+
+void
+omgpio_clear_bit(unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_LOW);
+}
+
+void
+omgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       omgpio_pin_dir_write(sc, GPIO_PIN_TO_OFFSET(gpio), dir);
+}
+
+int
+omgpio_pin_read(void *arg, int pin)
+{
+       struct omgpio_softc *sc = arg;
+       u_int32_t reg;
+
+       if(omgpio_pin_dir_read(sc, pin) == OMGPIO_DIR_IN)
+               reg = READ4(sc, sc->sc_regs.datain);
+       else
+               reg = READ4(sc, sc->sc_regs.dataout);
+       return (reg >> GPIO_PIN_TO_OFFSET(pin)) & 0x1;
+}
+
+void
+omgpio_pin_write(void *arg, int pin, int value)
+{
+       struct omgpio_softc *sc = arg;
+
+       if (value)
+               WRITE4(sc, sc->sc_regs.setdataout,
+                   1 << GPIO_PIN_TO_OFFSET(pin));
+       else
+               WRITE4(sc, sc->sc_regs.cleardataout,
+                   1 << GPIO_PIN_TO_OFFSET(pin));
+}
+
+void
+omgpio_pin_ctl(void *arg, int pin, int flags)
+{
+       struct omgpio_softc *sc = arg;
+
+       if (flags & GPIO_PIN_INPUT)
+               omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_IN);
+       else if (flags & GPIO_PIN_OUTPUT)
+               omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_OUT);
+
+       if (board_id == BOARD_ID_AM335X_BEAGLEBONE)
+               sitara_cm_padconf_set_gpioflags(
+                   sc->sc_dev.dv_unit * GPIO_NUM_PINS + pin, flags);
+}
+
+void
+omgpio_pin_dir_write(struct omgpio_softc *sc, unsigned int gpio,
+    unsigned int dir)
+{
+       int s;
+       u_int32_t reg;
+
+       s = splhigh();
+
+       reg = READ4(sc, sc->sc_regs.oe);
+       if (dir == OMGPIO_DIR_IN)
+               reg |= 1 << GPIO_PIN_TO_OFFSET(gpio);
+       else
+               reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
+       WRITE4(sc, sc->sc_regs.oe, reg);
+
+       splx(s);
+}
+
+int
+omgpio_pin_dir_read(struct omgpio_softc *sc, unsigned int gpio)
+{
+       u_int32_t reg;
+       reg = READ4(sc, sc->sc_regs.oe);
+       if (reg & (1 << GPIO_PIN_TO_OFFSET(gpio)))
+               return OMGPIO_DIR_IN;
+       else
+               return OMGPIO_DIR_OUT;
+}
+
+#if 0
+void
+omgpio_clear_intr(struct omgpio_softc *sc, unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       WRITE4(sc, sc->sc_regs.irqstatus0, 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_intr_mask(struct omgpio_softc *sc, unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       WRITE4(sc, sc->sc_regs.irqstatus_clear0, 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_intr_unmask(struct omgpio_softc *sc, unsigned int gpio)
+{
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       WRITE4(sc, sc->sc_regs.irqstatus_set0, 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_intr_level(struct omgpio_softc *sc, unsigned int gpio, unsigned int level)
+{
+       u_int32_t fe, re, l0, l1, bit;
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+       int s;
+
+       s = splhigh();
+
+       fe = READ4(sc, sc->sc_regs.fallingdetect);
+       re = READ4(sc, sc->sc_regs.risingdetect);
+       l0 = READ4(sc, sc->sc_regs.leveldetect0);
+       l1 = READ4(sc, sc->sc_regs.leveldetect1);
+
+       bit = 1 << GPIO_PIN_TO_OFFSET(gpio);
+
+       switch (level) {
+       case IST_NONE:
+               fe &= ~bit;
+               re &= ~bit;
+               l0 &= ~bit;
+               l1 &= ~bit;
+               break;
+       case IST_EDGE_FALLING:
+               fe |= bit;
+               re &= ~bit;
+               l0 &= ~bit;
+               l1 &= ~bit;
+               break;
+       case IST_EDGE_RISING:
+               fe &= ~bit;
+               re |= bit;
+               l0 &= ~bit;
+               l1 &= ~bit;
+               break;
+       case IST_PULSE: /* XXX */
+               /* FALLTHRU */
+       case IST_EDGE_BOTH:
+               fe |= bit;
+               re |= bit;
+               l0 &= ~bit;
+               l1 &= ~bit;
+               break;
+       case IST_LEVEL_LOW:
+               fe &= ~bit;
+               re &= ~bit;
+               l0 |= bit;
+               l1 &= ~bit;
+               break;
+       case IST_LEVEL_HIGH:
+               fe &= ~bit;
+               re &= ~bit;
+               l0 &= ~bit;
+               l1 |= bit;
+               break;
+       default:
+               panic("omgpio_intr_level: bad level: %d", level);
+               break;
+       }
+
+       WRITE4(sc, sc->sc_regs.fallingdetect, fe);
+       WRITE4(sc, sc->sc_regs.risingdetect, re);
+       WRITE4(sc, sc->sc_regs.leveldetect0, l0);
+       WRITE4(sc, sc->sc_regs.leveldetect1, l1);
+
+       splx(s);
+}
+
+void *
+omgpio_intr_establish(struct omgpio_softc *sc, unsigned int gpio, int level, int spl,
+    int (*func)(void *), void *arg, char *name)
+{
+       int psw;
+       struct intrhand *ih;
+       struct omgpio_softc *sc;
+
+       /*
+        * XXX - is gpio here the pin or the interrupt number
+        * which is 96 + gpio pin?
+        */
+
+       if (GPIO_PIN_TO_INST(gpio) > omgpio_cd.cd_ndevs)
+               panic("omgpio_intr_establish: bogus irqnumber %d: %s",
+                   gpio, name);
+
+       sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+       if (sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] != NULL)
+               panic("omgpio_intr_establish: gpio pin busy %d old %s new %s",
+                   gpio, sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]->ih_name,
+                   name);
+
+       psw = disable_interrupts(PSR_I);
+
+       /* no point in sleeping unless someone can free memory. */
+       ih = (struct intrhand *)malloc( sizeof *ih, M_DEVBUF,
+           cold ? M_NOWAIT : M_WAITOK);
+       if (ih == NULL)
+               panic("intr_establish: can't malloc handler info");
+       ih->ih_func = func;
+       ih->ih_arg = arg;
+       ih->ih_ipl = level;
+       ih->ih_gpio = gpio;
+       ih->ih_irq = gpio + 512;
+       ih->ih_name = name;
+
+       sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = ih;
+
+       evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+       omgpio_intr_level(gpio, level);
+       omgpio_intr_unmask(gpio);
+
+       omgpio_recalc_interrupts(sc);
+
+       restore_interrupts(psw);
+
+       return (ih);
+}
+
+void
+omgpio_intr_disestablish(struct omgpio_softc *sc, void *cookie)
+{
+       int psw;
+       struct intrhand *ih = cookie;
+       struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(ih->ih_gpio)];
+       int gpio = ih->ih_gpio;
+       psw = disable_interrupts(PSR_I);
+
+       ih = sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)];
+       sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = NULL;
+
+       evcount_detach(&ih->ih_count);
+
+       free(ih, M_DEVBUF, 0);
+
+       omgpio_intr_level(gpio, IST_NONE);
+       omgpio_intr_mask(gpio);
+       omgpio_clear_intr(gpio); /* Just in case */
+
+       omgpio_recalc_interrupts(sc);
+
+       restore_interrupts(psw);
+}
+
+int
+omgpio_irq(void *v)
+{
+       struct omgpio_softc *sc = v;
+       u_int32_t pending;
+       struct intrhand *ih;
+       int bit;
+
+       pending = READ4(sc, omgpio.irqstatus0);
+
+       while (pending != 0) {
+               bit = ffs(pending) - 1;
+               ih = sc->sc_handlers[bit];
+
+               if (ih != NULL) {
+                       if (ih->ih_func(ih->ih_arg))
+                               ih->ih_count.ec_count++;
+                       omgpio_clear_intr(ih->ih_gpio);
+               } else {
+                       panic("omgpio: irq fired no handler, gpio %x %x %x",
+                               sc->sc_dev.dv_unit * 32 + bit, pending,
+       READ4(sc, omgpio.irqstatus0)
+
+                               );
+               }
+               pending &= ~(1 << bit);
+       }
+       return 1;
+}
+
+int
+omgpio_irq_dummy(void *v)
+{
+       return 0;
+}
+
+void
+omgpio_recalc_interrupts(struct omgpio_softc *sc)
+{
+       struct intrhand *ih;
+       int max = IPL_NONE;
+       int min = IPL_HIGH;
+       int i;
+
+       for (i = 0; i < GPIO_NUM_PINS; i++) {
+               ih = sc->sc_handlers[i];
+               if (ih != NULL) {
+                       if (ih->ih_ipl > max)
+                               max = ih->ih_ipl;
+
+                       if (ih->ih_ipl < min)
+                               min = ih->ih_ipl;
+               }
+       }
+       if (max == IPL_NONE)
+               min = IPL_NONE;
+
+#if 0
+       if ((max == IPL_NONE || max != sc->sc_max_il) && sc->sc_ih_h != NULL)
+               arm_intr_disestablish(sc->sc_ih_h);
+
+       if (max != IPL_NONE && max != sc->sc_max_il) {
+               sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq,
+                   sc, NULL);
+       }
+#else
+       if (sc->sc_ih_h != NULL)
+               arm_intr_disestablish(sc->sc_ih_h);
+
+       if (max != IPL_NONE) {
+               sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq,
+                   sc, NULL);
+       }
+#endif
+
+       sc->sc_max_il = max;
+
+       if (sc->sc_ih_l != NULL)
+               arm_intr_disestablish(sc->sc_ih_l);
+
+       if (max != min) {
+               sc->sc_ih_h = arm_intr_establish(sc->sc_irq, min,
+                   omgpio_irq_dummy, sc, NULL);
+       }
+       sc->sc_min_il = min;
+}
+#endif
diff --git a/omgpiovar.h b/omgpiovar.h
new file mode 100644 (file)
index 0000000..1c69f1b
--- /dev/null
@@ -0,0 +1,44 @@
+/* $OpenBSD: omgpiovar.h,v 1.2 2013/11/20 13:32:40 rapha Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef OMGPIOVAR_H
+#define OMGPIOVAR_H
+
+#define OMGPIO_DIR_IN  0
+#define OMGPIO_DIR_OUT 1
+
+unsigned int omgpio_get_function(unsigned int gpio, unsigned int fn);
+void omgpio_set_function(unsigned int gpio, unsigned int fn);
+unsigned int omgpio_get_bit(unsigned int gpio);
+void omgpio_set_bit(unsigned int gpio);
+void omgpio_clear_bit(unsigned int gpio);
+void omgpio_set_dir(unsigned int gpio, unsigned int dir);
+
+int omgpio_pin_read(void *arg, int pin);
+void omgpio_pin_write(void *arg, int pin, int value);
+void omgpio_pin_ctl(void *arg, int pin, int flags);
+
+/* interrupts */
+void omgpio_clear_intr(unsigned int gpio);
+void omgpio_intr_mask(unsigned int gpio);
+void omgpio_intr_unmask(unsigned int gpio);
+void omgpio_intr_level(unsigned int gpio, unsigned int level);
+void *omgpio_intr_establish(unsigned int gpio, int level, int spl,
+    int (*func)(void *), void *arg, char *name);
+void omgpio_intr_disestablish(void *cookie);
+
+#endif /* OMGPIOVAR_H */
diff --git a/ommmc.c b/ommmc.c
new file mode 100644 (file)
index 0000000..92a585b
--- /dev/null
+++ b/ommmc.c
@@ -0,0 +1,1153 @@
+/*     $OpenBSD: ommmc.c,v 1.18 2016/05/02 07:38:34 jsg Exp $  */
+
+/*
+ * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Omap 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/omap/prcmvar.h>
+
+/*
+ * NOTE: on OMAP4430/AM335x these registers skew by 0x100
+ * this is handled by mapping at base address + 0x100
+ */
+/* registers */
+#define MMCHS_SYSCONFIG        0x010
+#define MMCHS_SYSSTATUS        0x014
+#define MMCHS_CSRE     0x024
+#define MMCHS_SYSTEST  0x028
+#define  MMCHS_SYSTEST_SDCD    (1 << 15)
+#define MMCHS_CON      0x02C
+#define  MMCHS_CON_INIT        (1<<1)
+#define  MMCHS_CON_DW8 (1<<5)
+#define  MMCHS_CON_OD  (1<<0)
+#define MMCHS_PWCNT    0x030
+#define MMCHS_BLK      0x104
+#define  MMCHS_BLK_NBLK_MAX    0xffff
+#define  MMCHS_BLK_NBLK_SHIFT  16
+#define  MMCHS_BLK_NBLK_MASK   (MMCHS_BLK_NBLK_MAX<<MMCHS_BLK_NBLK_SHIFT)
+#define  MMCHS_BLK_BLEN_MAX    0x400
+#define  MMCHS_BLK_BLEN_SHIFT  0
+#define  MMCHS_BLK_BLEN_MASK   (MMCHS_BLK_BLEN_MAX<<MMCHS_BLK_BLEN_SHIFT)
+#define MMCHS_ARG      0x108
+#define MMCHS_CMD      0x10C
+#define  MMCHS_CMD_INDX_SHIFT          24
+#define  MMCHS_CMD_INDX_SHIFT_MASK     (0x3f << MMCHS_CMD_INDX_SHIFT)
+#define         MMCHS_CMD_CMD_TYPE_SHIFT       22
+#define         MMCHS_CMD_DP_SHIFT             21
+#define         MMCHS_CMD_DP                   (1 << MMCHS_CMD_DP_SHIFT)
+#define         MMCHS_CMD_CICE_SHIFT           20
+#define         MMCHS_CMD_CICE                 (1 << MMCHS_CMD_CICE_SHIFT)
+#define         MMCHS_CMD_CCCE_SHIFT           19
+#define         MMCHS_CMD_CCCE                 (1 << MMCHS_CMD_CCCE_SHIFT)
+#define         MMCHS_CMD_RSP_TYPE_SHIFT       16
+#define  MMCHS_CMD_RESP_NONE           (0x0 << MMCHS_CMD_RSP_TYPE_SHIFT)
+#define  MMCHS_CMD_RESP136             (0x1 << MMCHS_CMD_RSP_TYPE_SHIFT)
+#define  MMCHS_CMD_RESP48              (0x2 << MMCHS_CMD_RSP_TYPE_SHIFT)
+#define  MMCHS_CMD_RESP48B             (0x3 << MMCHS_CMD_RSP_TYPE_SHIFT)
+#define  MMCHS_CMD_MSBS                        (1 << 5)
+#define  MMCHS_CMD_DDIR                        (1 << 4)
+#define  MMCHS_CMD_ACEN                        (1 << 2)
+#define  MMCHS_CMD_BCE                 (1 << 1)
+#define  MMCHS_CMD_DE                  (1 << 0)
+#define MMCHS_RSP10    0x110
+#define MMCHS_RSP32    0x114
+#define MMCHS_RSP54    0x118
+#define MMCHS_RSP76    0x11C
+#define MMCHS_DATA     0x120
+#define MMCHS_PSTATE   0x124
+#define  MMCHS_PSTATE_CLEV     (1<<24)
+#define  MMCHS_PSTATE_DLEV_SH  20
+#define  MMCHS_PSTATE_DLEV_M   (0xf << MMCHS_PSTATE_DLEV_SH)
+#define  MMCHS_PSTATE_BRE      (1<<11)
+#define  MMCHS_PSTATE_BWE      (1<<10)
+#define  MMCHS_PSTATE_RTA      (1<<9)
+#define  MMCHS_PSTATE_WTA      (1<<8)
+#define  MMCHS_PSTATE_DLA      (1<<2)
+#define  MMCHS_PSTATE_DATI     (1<<1)
+#define  MMCHS_PSTATE_CMDI     (1<<0)
+#define  MMCHS_PSTATE_FMT "\20" \
+    "\x098_CLEV" \
+    "\x08b_BRE" \
+    "\x08a_BWE" \
+    "\x089_RTA" \
+    "\x088_WTA" \
+    "\x082_DLA" \
+    "\x081_DATI" \
+    "\x080_CMDI"
+#define MMCHS_HCTL     0x128
+#define  MMCHS_HCTL_SDVS_SHIFT 9
+#define  MMCHS_HCTL_SDVS_MASK  (0x7<<MMCHS_HCTL_SDVS_SHIFT)
+#define  MMCHS_HCTL_SDVS_V18   (0x5<<MMCHS_HCTL_SDVS_SHIFT)
+#define  MMCHS_HCTL_SDVS_V30   (0x6<<MMCHS_HCTL_SDVS_SHIFT)
+#define  MMCHS_HCTL_SDVS_V33   (0x7<<MMCHS_HCTL_SDVS_SHIFT)
+#define  MMCHS_HCTL_SDBP       (1<<8)
+#define  MMCHS_HCTL_HSPE       (1<<2)
+#define  MMCHS_HCTL_DTW                (1<<1)
+#define MMCHS_SYSCTL   0x12C
+#define  MMCHS_SYSCTL_SRD      (1<<26)
+#define  MMCHS_SYSCTL_SRC      (1<<25)
+#define  MMCHS_SYSCTL_SRA      (1<<24)
+#define  MMCHS_SYSCTL_DTO_SH   16
+#define  MMCHS_SYSCTL_DTO_MASK 0x000f0000
+#define  MMCHS_SYSCTL_CLKD_SH  6
+#define  MMCHS_SYSCTL_CLKD_MASK        0x0000ffc0
+#define  MMCHS_SYSCTL_CEN      (1<<2)
+#define  MMCHS_SYSCTL_ICS      (1<<1)
+#define  MMCHS_SYSCTL_ICE      (1<<0)
+#define MMCHS_STAT     0x130
+#define  MMCHS_STAT_BADA       (1<<29)
+#define  MMCHS_STAT_CERR       (1<<28)
+#define  MMCHS_STAT_ACE                (1<<24)
+#define  MMCHS_STAT_DEB                (1<<22)
+#define  MMCHS_STAT_DCRC       (1<<21)
+#define  MMCHS_STAT_DTO                (1<<20)
+#define  MMCHS_STAT_CIE                (1<<19)
+#define  MMCHS_STAT_CEB                (1<<18)
+#define  MMCHS_STAT_CCRC       (1<<17)
+#define  MMCHS_STAT_CTO                (1<<16)
+#define  MMCHS_STAT_ERRI       (1<<15)
+#define  MMCHS_STAT_OBI                (1<<9)
+#define  MMCHS_STAT_CIRQ       (1<<8)
+#define  MMCHS_STAT_BRR                (1<<5)
+#define  MMCHS_STAT_BWR                (1<<4)
+#define  MMCHS_STAT_BGE                (1<<2)
+#define  MMCHS_STAT_TC         (1<<1)
+#define  MMCHS_STAT_CC         (1<<0)
+#define  MMCHS_STAT_FMT "\20" \
+    "\x09d_BADA" \
+    "\x09c_CERR" \
+    "\x098_ACE" \
+    "\x096_DEB" \
+    "\x095_DCRC" \
+    "\x094_DTO" \
+    "\x093_CIE" \
+    "\x092_CEB" \
+    "\x091_CCRC" \
+    "\x090_CTO" \
+    "\x08f_ERRI" \
+    "\x089_OBI" \
+    "\x088_CIRQ" \
+    "\x085_BRR" \
+    "\x084_BWR" \
+    "\x082_BGE" \
+    "\x081_TC" \
+    "\x080_CC"
+#define MMCHS_IE       0x134
+#define MMCHS_ISE      0x138
+#define MMCHS_AC12     0x13C
+#define MMCHS_CAPA     0x140
+#define  MMCHS_CAPA_VS18       (1 << 26)
+#define  MMCHS_CAPA_VS30       (1 << 25)
+#define  MMCHS_CAPA_VS33       (1 << 24)
+#define  MMCHS_CAPA_SRS                (1 << 23)
+#define  MMCHS_CAPA_DS         (1 << 22)
+#define  MMCHS_CAPA_HSS                (1 << 21)
+#define  MMCHS_CAPA_MBL_SHIFT  16
+#define  MMCHS_CAPA_MBL_MASK   (3 << MMCHS_CAPA_MBL_SHIFT)
+#define MMCHS_CUR_CAPA 0x148
+#define MMCHS_REV      0x1fc
+
+#define SDHC_COMMAND_TIMEOUT   hz
+#define SDHC_BUFFER_TIMEOUT    hz
+#define SDHC_TRANSFER_TIMEOUT  hz
+
+void ommmc_attach(struct device *parent, struct device *self, void *args);
+
+struct ommmc_softc {
+       struct device sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       void                    *sc_ih; /* Interrupt handler */
+       uint32_t                sc_flags;
+
+       struct device *sdmmc;           /* generic SD/MMC device */
+       int clockbit;                   /* clock control bit */
+       uint32_t clkbase;               /* base clock frequency in KHz */
+       int maxblklen;                  /* maximum block length */
+       int flags;                      /* flags for this host */
+       uint32_t ocr;                   /* OCR value from capabilities */
+       uint32_t intr_status;           /* soft interrupt status */
+       uint32_t intr_error_status;     /*  */
+};
+
+
+/* Host controller functions called by the attachment driver. */
+int    ommmc_host_found(struct ommmc_softc *, bus_space_tag_t,
+           bus_space_handle_t, bus_size_t, int);
+void   ommmc_power(int, void *);
+void   ommmc_shutdown(void *);
+int    ommmc_intr(void *);
+
+/* RESET MODES */
+#define MMC_RESET_DAT  1
+#define MMC_RESET_CMD  2
+#define MMC_RESET_ALL  (MMC_RESET_CMD|MMC_RESET_DAT)
+
+/* flag values */
+#define SHF_USE_DMA            0x0001
+
+#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    ommmc_host_reset(sdmmc_chipset_handle_t);
+uint32_t ommmc_host_ocr(sdmmc_chipset_handle_t);
+int    ommmc_host_maxblklen(sdmmc_chipset_handle_t);
+int    ommmc_card_detect(sdmmc_chipset_handle_t);
+int    ommmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
+int    ommmc_bus_clock(sdmmc_chipset_handle_t, int);
+int    ommmc_bus_width(sdmmc_chipset_handle_t, int);
+void   ommmc_card_intr_mask(sdmmc_chipset_handle_t, int);
+void   ommmc_card_intr_ack(sdmmc_chipset_handle_t);
+void   ommmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
+int    ommmc_start_command(struct ommmc_softc *, struct sdmmc_command *);
+int    ommmc_wait_state(struct ommmc_softc *, uint32_t, uint32_t);
+int    ommmc_soft_reset(struct ommmc_softc *, int);
+int    ommmc_wait_intr(struct ommmc_softc *, int, int);
+void   ommmc_transfer_data(struct ommmc_softc *, struct sdmmc_command *);
+void   ommmc_read_data(struct ommmc_softc *, uint8_t *, int);
+void   ommmc_write_data(struct ommmc_softc *, uint8_t *, int);
+
+/* #define SDHC_DEBUG */
+#ifdef SDHC_DEBUG
+int ommmcdebug = 20;
+#define DPRINTF(n,s)   do { if ((n) <= ommmcdebug) printf s; } while (0)
+void   ommmc_dump_regs(struct ommmc_softc *);
+#else
+#define DPRINTF(n,s)   do {} while(0)
+#endif
+
+struct sdmmc_chip_functions ommmc_functions = {
+       /* host controller reset */
+       ommmc_host_reset,
+       /* host controller capabilities */
+       ommmc_host_ocr,
+       ommmc_host_maxblklen,
+       /* card detection */
+       ommmc_card_detect,
+       /* bus power and clock frequency */
+       ommmc_bus_power,
+       ommmc_bus_clock,
+       ommmc_bus_width,
+       /* command execution */
+       ommmc_exec_command,
+       /* card interrupt */
+       ommmc_card_intr_mask,
+       ommmc_card_intr_ack
+};
+
+struct cfdriver ommmc_cd = {
+       NULL, "ommmc", DV_DULL
+};
+
+struct cfattach ommmc_ca = {
+       sizeof(struct ommmc_softc), NULL, ommmc_attach
+};
+
+void
+ommmc_attach(struct device *parent, struct device *self, void *args)
+{
+       struct ommmc_softc              *sc = (struct ommmc_softc *) self;
+       struct armv7_attach_args        *aa = args;
+       struct sdmmcbus_attach_args      saa;
+       uint32_t                         caps;
+
+       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("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+       /* Enable ICLKEN, FCLKEN? */
+       prcm_enablemodule(PRCM_MMC0 + aa->aa_dev->unit);
+
+       sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_SDMMC,
+           ommmc_intr, sc, DEVNAME(sc));
+       if (sc->sc_ih == NULL) {
+               printf("%s: cannot map interrupt\n", DEVNAME(sc));
+               goto err;
+       }
+
+       /* Controller Voltage Capabilities Initialization */
+       HSET4(sc, MMCHS_CAPA, MMCHS_CAPA_VS18 | MMCHS_CAPA_VS30);
+
+#ifdef SDHC_DEBUG
+       ommmc_dump_regs(sc);
+#endif
+
+       /*
+        * Reset the host controller and enable interrupts.
+        */
+       ommmc_host_reset(sc);
+
+       /* Determine host capabilities. */
+       caps = HREAD4(sc, MMCHS_CAPA);
+
+#if 0
+       /* we want this !! */
+       /* Use DMA if the host system and the controller support it. */
+       if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
+               SET(sc->flags, SHF_USE_DMA);
+#endif
+
+       /*
+        * Determine the base clock frequency. (2.2.24)
+        */
+
+       sc->clkbase = 96 * 1000;
+#if 0
+       if (SDHC_BASE_FREQ_KHZ(caps) != 0)
+               sc->clkbase = SDHC_BASE_FREQ_KHZ(caps);
+               sc->clkbase = SDHC_BASE_FREQ_KHZ(caps);
+#endif
+       if (sc->clkbase == 0) {
+               /* The attachment driver must tell us. */
+               printf("%s: base clock frequency unknown\n", DEVNAME(sc));
+               goto err;
+       } else if (sc->clkbase < 10000 || sc->clkbase > 96000) {
+               /* SDHC 1.0 supports only 10-63 MHz. */
+               printf("%s: base clock frequency out of range: %u MHz\n",
+                   DEVNAME(sc), sc->clkbase / 1000);
+               goto err;
+       }
+
+       /*
+        * XXX Set the data timeout counter value according to
+        * capabilities. (2.2.15)
+        */
+
+
+       /*
+        * Determine SD bus voltage levels supported by the controller.
+        */
+       if (caps & MMCHS_CAPA_VS18)
+               SET(sc->ocr, MMC_OCR_1_65V_1_95V);
+       if (caps & MMCHS_CAPA_VS30)
+               SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
+       if (caps & MMCHS_CAPA_VS33)
+               SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
+
+       /*
+        * Omap max block size is fixed (single buffer), could limit
+        * this to 512 for double buffering, but dont see the point.
+        */
+       switch ((caps & MMCHS_CAPA_MBL_MASK) >> MMCHS_CAPA_MBL_SHIFT) {
+       case 0:
+               sc->maxblklen = 512;
+               break;
+       case 1:
+               sc->maxblklen = 1024;
+               break;
+       case 2:
+               sc->maxblklen = 2048;
+               break;
+       default:
+               sc->maxblklen = 512;
+               printf("invalid capability blocksize in capa %08x,"
+                   " trying 512\n", HREAD4(sc, MMCHS_CAPA));
+       }
+       /*
+        * MMC does not support blksize > 512 yet
+        */
+       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 = &ommmc_functions;
+       saa.sch = sc;
+       saa.caps = SMC_CAPS_4BIT_MODE;
+       if (caps & MMCHS_CAPA_HSS)
+               saa.caps |= SMC_CAPS_MMC_HIGHSPEED;
+
+       sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
+       if (sc->sdmmc == NULL) {
+               printf("%s: can't attach sdmmc\n", DEVNAME(sc));
+               goto err;
+       }
+
+       return;
+err:
+       if (sc->sc_ih != NULL)
+               arm_intr_disestablish(sc->sc_ih);
+       bus_space_unmap(sc->sc_iot, sc->sc_ioh, aa->aa_dev->mem[0].size);
+}
+
+
+/*
+ * Power hook established by or called from attachment driver.
+ */
+void
+ommmc_power(int why, void *arg)
+{
+#if 0
+       struct ommmc_softc *sc = arg;
+       int n, i;
+#endif
+
+       switch(why) {
+       case DVACT_SUSPEND:
+               /* XXX poll for command completion or suspend command
+                * in progress */
+
+               /* Save the host controller state. */
+#if 0
+               for (i = 0; i < sizeof sc->regs; i++)
+                       sc->regs[i] = HREAD1(sc, i);
+#endif
+               break;
+
+       case DVACT_RESUME:
+               /* Restore the host controller state. */
+#if 0
+               (void)ommmc_host_reset(sc);
+               for (i = 0; i < sizeof sc->regs; i++)
+                       HWRITE1(sc, i, sc->regs[i]);
+#endif
+               break;
+       }
+}
+
+/*
+ * Shutdown hook established by or called from attachment driver.
+ */
+void
+ommmc_shutdown(void *arg)
+{
+       struct ommmc_softc *sc = arg;
+
+       /* XXX chip locks up if we don't disable it before reboot. */
+       (void)ommmc_host_reset(sc);
+}
+
+/*
+ * Reset the host controller.  Called during initialization, when
+ * cards are removed, upon resume, and during error recovery.
+ */
+int
+ommmc_host_reset(sdmmc_chipset_handle_t sch)
+{
+       struct ommmc_softc *sc = sch;
+       uint32_t imask;
+       int error;
+       int s;
+
+       s = splsdmmc();
+
+       /* Disable all interrupts. */
+       HWRITE4(sc, MMCHS_IE, 0);
+       HWRITE4(sc, MMCHS_ISE, 0);
+
+       /*
+        * Reset the entire host controller and wait up to 100ms for
+        * the controller to clear the reset bit.
+        */
+       if ((error = ommmc_soft_reset(sc, MMCHS_SYSCTL_SRA)) != 0) {
+               splx(s);
+               return (error);
+       }
+
+#if 0
+       HSET4(sc, MMCHS_CON, MMCHS_CON_INIT);
+       HWRITE4(sc, MMCHS_CMD, 0);
+       delay(100); /* should delay 1ms */
+
+       HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CC);
+       HCLR4(sc, MMCHS_CON, MMCHS_CON_INIT);
+       HWRITE4(sc, MMCHS_STAT, ~0);
+#endif
+
+
+       /* Set data timeout counter value to max for now. */
+       HSET4(sc, MMCHS_SYSCTL, 0xe << MMCHS_SYSCTL_DTO_SH);
+
+       /* Enable interrupts. */
+       imask = MMCHS_STAT_BRR | MMCHS_STAT_BWR | MMCHS_STAT_BGE |
+           MMCHS_STAT_TC | MMCHS_STAT_CC;
+
+       imask |= MMCHS_STAT_BADA | MMCHS_STAT_CERR | MMCHS_STAT_DEB |
+           MMCHS_STAT_DCRC | MMCHS_STAT_DTO | MMCHS_STAT_CIE |
+           MMCHS_STAT_CEB | MMCHS_STAT_CCRC | MMCHS_STAT_CTO;
+
+       HWRITE4(sc, MMCHS_IE, imask);
+       HWRITE4(sc, MMCHS_ISE, imask);
+
+       splx(s);
+       return (0);
+}
+
+uint32_t
+ommmc_host_ocr(sdmmc_chipset_handle_t sch)
+{
+       struct ommmc_softc *sc = sch;
+       return (sc->ocr);
+}
+
+int
+ommmc_host_maxblklen(sdmmc_chipset_handle_t sch)
+{
+       struct ommmc_softc *sc = sch;
+       return (sc->maxblklen);
+}
+
+/*
+ * Return non-zero if the card is currently inserted.
+ */
+int
+ommmc_card_detect(sdmmc_chipset_handle_t sch)
+{
+       struct ommmc_softc *sc = sch;
+       return !ISSET(HREAD4(sc, MMCHS_SYSTEST), MMCHS_SYSTEST_SDCD) ?
+           1 : 0;
+}
+
+/*
+ * Set or change SD bus voltage and enable or disable SD bus power.
+ * Return zero on success.
+ */
+int
+ommmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+       struct ommmc_softc *sc = sch;
+       uint32_t vdd;
+       uint32_t reg;
+       int s;
+
+       s = splsdmmc();
+
+       /*
+        * Disable bus power before voltage change.
+        */
+       HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP);
+
+       /* If power is disabled, reset the host and return now. */
+       if (ocr == 0) {
+               splx(s);
+               (void)ommmc_host_reset(sc);
+               return (0);
+       }
+
+       /*
+        * Select the maximum voltage according to capabilities.
+        */
+       ocr &= sc->ocr;
+
+       if (ISSET(ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V))
+               vdd = MMCHS_HCTL_SDVS_V33;
+       else if (ISSET(ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V))
+               vdd = MMCHS_HCTL_SDVS_V30;
+       else if (ISSET(ocr, MMC_OCR_1_65V_1_95V))
+               vdd = MMCHS_HCTL_SDVS_V18;
+       else {
+               /* Unsupported voltage level requested. */
+               splx(s);
+               return (EINVAL);
+       }
+
+       /*
+        * Enable bus power.  Wait at least 1 ms (or 74 clocks) plus
+        * voltage ramp until power rises.
+        */
+       reg = HREAD4(sc, MMCHS_HCTL);
+       reg &= ~MMCHS_HCTL_SDVS_MASK;
+       reg |= vdd;
+       HWRITE4(sc, MMCHS_HCTL, reg);
+
+       HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP);
+       delay(10000); /* XXX */
+
+       /*
+        * The host system may not power the bus due to battery low,
+        * etc.  In that case, the host controller should clear the
+        * bus power bit.
+        */
+       if (!ISSET(HREAD4(sc, MMCHS_HCTL), MMCHS_HCTL_SDBP)) {
+               splx(s);
+               return (ENXIO);
+       }
+
+       splx(s);
+       return (0);
+}
+
+/*
+ * Return the smallest possible base clock frequency divisor value
+ * for the CLOCK_CTL register to produce `freq' (KHz).
+ */
+static int
+ommmc_clock_divisor(struct ommmc_softc *sc, uint32_t freq)
+{
+       int div;
+       uint32_t maxclk = MMCHS_SYSCTL_CLKD_MASK>>MMCHS_SYSCTL_CLKD_SH;
+
+       for (div = 1; div <= maxclk; div++)
+               if ((sc->clkbase / div) <= freq) {
+                       return (div);
+               }
+
+       printf("divisor failure\n");
+       /* No divisor found. */
+       return (-1);
+}
+
+/*
+ * Set or change SDCLK frequency or disable the SD clock.
+ * Return zero on success.
+ */
+int
+ommmc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
+{
+       int error = 0;
+       struct ommmc_softc *sc = sch;
+       uint32_t reg;
+       int s;
+       int div;
+       int timo;
+
+       s = splsdmmc();
+
+       /* Must not stop the clock if commands are in progress. */
+       for (timo = 1000; timo > 0; timo--) {
+               if (!ISSET(HREAD4(sc, MMCHS_PSTATE),
+                   MMCHS_PSTATE_CMDI|MMCHS_PSTATE_DATI))
+                       break;
+               delay(10);
+       }
+       if (timo == 0) {
+               error = ETIMEDOUT;
+               goto ret;
+       }
+
+       /*
+        * Stop SD clock before changing the frequency.
+        */
+       HCLR4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN);
+       if (freq == SDMMC_SDCLK_OFF)
+               goto ret;
+
+       /*
+        * Set the minimum base clock frequency divisor.
+        */
+       if ((div = ommmc_clock_divisor(sc, freq)) < 0) {
+               /* Invalid base clock frequency or `freq' value. */
+               error = EINVAL;
+               goto ret;
+       }
+       reg = HREAD4(sc, MMCHS_SYSCTL);
+       reg &= ~MMCHS_SYSCTL_CLKD_MASK;
+       reg |= div << MMCHS_SYSCTL_CLKD_SH;
+       HWRITE4(sc, MMCHS_SYSCTL, reg);
+
+       /*
+        * Start internal clock.  Wait 10ms for stabilization.
+        */
+       HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_ICE);
+       for (timo = 1000; timo > 0; timo--) {
+               if (ISSET(HREAD4(sc, MMCHS_SYSCTL), MMCHS_SYSCTL_ICS))
+                       break;
+               delay(10);
+       }
+       if (timo == 0) {
+               error = ETIMEDOUT;
+               goto ret;
+       }
+
+       /*
+        * Enable SD clock.
+        */
+       HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN);
+ret:
+       splx(s);
+       return (error);
+}
+
+int
+ommmc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+       struct ommmc_softc *sc = sch;
+       int s;
+
+       if (width != 1 && width != 4 && width != 8)
+               return (1);
+
+       s = splsdmmc();
+
+       if (width == 8)
+               HSET4(sc, MMCHS_CON, MMCHS_CON_DW8);
+       else
+               HCLR4(sc, MMCHS_CON, MMCHS_CON_DW8);
+
+       if (width == 4)
+               HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
+       else if (width == 1)
+               HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
+
+       splx(s);
+
+       return (0);
+}
+
+void
+ommmc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
+{
+       /* - this is SDIO card interrupt */
+       struct ommmc_softc *sc = sch;
+
+       if (enable) {
+               HSET4(sc, MMCHS_IE, MMCHS_STAT_CIRQ);
+               HSET4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ);
+       } else {
+               HCLR4(sc, MMCHS_IE, MMCHS_STAT_CIRQ);
+               HCLR4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ);
+       }
+}
+
+void
+ommmc_card_intr_ack(sdmmc_chipset_handle_t sch)
+{
+       struct ommmc_softc *sc = sch;
+
+       HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ);
+}
+
+int
+ommmc_wait_state(struct ommmc_softc *sc, uint32_t mask, uint32_t value)
+{
+       uint32_t state;
+       int timeout;
+
+       state = HREAD4(sc, MMCHS_PSTATE);
+       DPRINTF(3,("%s: wait_state %x %x %x(state=%b)\n", DEVNAME(sc),
+           mask, value, state, state, MMCHS_PSTATE_FMT));
+       for (timeout = 1000; timeout > 0; timeout--) {
+               if (((state = HREAD4(sc, MMCHS_PSTATE)) & mask) == value)
+                       return (0);
+               delay(10);
+       }
+       DPRINTF(0,("%s: timeout waiting for %x (state=%b)\n", DEVNAME(sc),
+           value, state, MMCHS_PSTATE_FMT));
+       return (ETIMEDOUT);
+}
+
+void
+ommmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
+{
+       struct ommmc_softc *sc = sch;
+       int error;
+
+       /*
+        * Start the MMC command, or mark `cmd' as failed and return.
+        */
+       error = ommmc_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 (!ommmc_wait_intr(sc, MMCHS_STAT_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)) {
+                       uint32_t v0,v1,v2,v3;
+                       v0 = HREAD4(sc, MMCHS_RSP10);
+                       v1 = HREAD4(sc, MMCHS_RSP32);
+                       v2 = HREAD4(sc, MMCHS_RSP54);
+                       v3 = HREAD4(sc, MMCHS_RSP76);
+
+                       cmd->c_resp[0] = (v0 >> 8) | ((v1 & 0xff)  << 24);
+                       cmd->c_resp[1] = (v1 >> 8) | ((v2 & 0xff)  << 24);
+                       cmd->c_resp[2] = (v2 >> 8) | ((v3 & 0xff)  << 24);
+                       cmd->c_resp[3] = v3 >> 8;
+#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, MMCHS_RSP10);
+#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 != NULL)
+               ommmc_transfer_data(sc, cmd);
+
+#if 0
+       /* Turn off the LED. */
+       HCLR1(sc, SDHC_HOST_CTL, SDHC_LED_ON);
+#endif
+
+       DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
+           DEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error));
+       SET(cmd->c_flags, SCF_ITSDONE);
+}
+
+int
+ommmc_start_command(struct ommmc_softc *sc, struct sdmmc_command *cmd)
+{
+       uint32_t blksize = 0;
+       uint32_t blkcount = 0;
+       uint32_t command;
+       int error;
+       int s;
+
+       DPRINTF(1,("%s: start cmd %u arg=%#x data=%p dlen=%d flags=%#x "
+           "proc=\"%s\"\n", DEVNAME(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",
+                           DEVNAME(sc), blksize);
+                       return (EINVAL);
+               }
+       }
+
+       /* Check limit imposed by 9-bit block count. (1.7.2) */
+       if (blkcount > MMCHS_BLK_NBLK_MAX) {
+               printf("%s: too much data\n", DEVNAME(sc));
+               return (EINVAL);
+       }
+
+       /* Prepare transfer mode register value. (2.2.5) */
+       command = 0;
+       if (ISSET(cmd->c_flags, SCF_CMD_READ))
+               command |= MMCHS_CMD_DDIR;
+       if (blkcount > 0) {
+               command |= MMCHS_CMD_BCE;
+               if (blkcount > 1) {
+                       command |= MMCHS_CMD_MSBS;
+                       /* XXX only for memory commands? */
+                       command |= MMCHS_CMD_ACEN;
+               }
+       }
+#ifdef notyet
+       if (ISSET(sc->flags, SHF_USE_DMA))
+               command |= MMCHS_CMD_DE;
+#endif
+
+       /*
+        * Prepare command register value. (2.2.6)
+        */
+       command |= (cmd->c_opcode << MMCHS_CMD_INDX_SHIFT) &
+          MMCHS_CMD_INDX_SHIFT_MASK;
+
+       if (ISSET(cmd->c_flags, SCF_RSP_CRC))
+               command |= MMCHS_CMD_CCCE;
+       if (ISSET(cmd->c_flags, SCF_RSP_IDX))
+               command |= MMCHS_CMD_CICE;
+       if (cmd->c_data != NULL)
+               command |= MMCHS_CMD_DP;
+
+       if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
+               command |= MMCHS_CMD_RESP_NONE;
+       else if (ISSET(cmd->c_flags, SCF_RSP_136))
+               command |= MMCHS_CMD_RESP136;
+       else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
+               command |= MMCHS_CMD_RESP48B;
+       else
+               command |= MMCHS_CMD_RESP48;
+
+       /* Wait until command and data inhibit bits are clear. (1.5) */
+       if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_CMDI, 0)) != 0)
+               return (error);
+
+       s = splsdmmc();
+
+#if 0
+       /* Alert the user not to remove the card. */
+       HSET1(sc, SDHC_HOST_CTL, SDHC_LED_ON);
+#endif
+
+       /* XXX: Set DMA start address if SHF_USE_DMA is set. */
+
+       DPRINTF(1,("%s: cmd=%#x blksize=%d blkcount=%d\n",
+           DEVNAME(sc), command, blksize, blkcount));
+
+       /*
+        * Start a CPU data transfer.  Writing to the high order byte
+        * of the SDHC_COMMAND register triggers the SD command. (1.5)
+        */
+       HWRITE4(sc, MMCHS_BLK, (blkcount << MMCHS_BLK_NBLK_SHIFT) |
+           (blksize << MMCHS_BLK_BLEN_SHIFT));
+       HWRITE4(sc, MMCHS_ARG, cmd->c_arg);
+       HWRITE4(sc, MMCHS_CMD, command);
+
+       splx(s);
+       return (0);
+}
+
+void
+ommmc_transfer_data(struct ommmc_softc *sc, struct sdmmc_command *cmd)
+{
+       uint8_t *datap = cmd->c_data;
+       int i, datalen;
+       int mask;
+       int error;
+
+       mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
+           MMCHS_PSTATE_BRE : MMCHS_PSTATE_BWE;
+       error = 0;
+       datalen = cmd->c_datalen;
+
+       DPRINTF(1,("%s: resp=%#x datalen=%d\n", DEVNAME(sc),
+           MMC_R1(cmd->c_resp), datalen));
+
+       while (datalen > 0) {
+               if (!ommmc_wait_intr(sc, MMCHS_STAT_BRR| MMCHS_STAT_BWR,
+                   SDHC_BUFFER_TIMEOUT)) {
+                       error = ETIMEDOUT;
+                       break;
+               }
+
+               if ((error = ommmc_wait_state(sc, mask, mask)) != 0)
+                       break;
+
+               i = MIN(datalen, cmd->c_blklen);
+               if (ISSET(cmd->c_flags, SCF_CMD_READ))
+                       ommmc_read_data(sc, datap, i);
+               else
+                       ommmc_write_data(sc, datap, i);
+
+               datap += i;
+               datalen -= i;
+       }
+
+       if (error == 0 && !ommmc_wait_intr(sc, MMCHS_STAT_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",
+           DEVNAME(sc), cmd->c_error));
+}
+
+void
+ommmc_read_data(struct ommmc_softc *sc, uint8_t *datap, int datalen)
+{
+       while (datalen > 3) {
+               *(uint32_t *)datap = HREAD4(sc, MMCHS_DATA);
+               datap += 4;
+               datalen -= 4;
+       }
+       if (datalen > 0) {
+               uint32_t rv = HREAD4(sc, MMCHS_DATA);
+               do {
+                       *datap++ = rv & 0xff;
+                       rv = rv >> 8;
+               } while (--datalen > 0);
+       }
+}
+
+void
+ommmc_write_data(struct ommmc_softc *sc, uint8_t *datap, int datalen)
+{
+       while (datalen > 3) {
+               DPRINTF(3,("%08x\n", *(uint32_t *)datap));
+               HWRITE4(sc, MMCHS_DATA, *((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, MMCHS_DATA, rv);
+       }
+}
+
+/* Prepare for another command. */
+int
+ommmc_soft_reset(struct ommmc_softc *sc, int mask)
+{
+
+       int timo;
+
+       DPRINTF(1,("%s: software reset reg=%#x\n", DEVNAME(sc), mask));
+
+       HSET4(sc, MMCHS_SYSCTL, mask);
+       delay(10);
+       for (timo = 1000; timo > 0; timo--) {
+               if (!ISSET(HREAD4(sc, MMCHS_SYSCTL), mask))
+                       break;
+               delay(10);
+       }
+       if (timo == 0) {
+               DPRINTF(1,("%s: timeout reg=%#x\n", DEVNAME(sc),
+                   HREAD4(sc, MMCHS_SYSCTL)));
+               return (ETIMEDOUT);
+       }
+
+       return (0);
+}
+
+int
+ommmc_wait_intr(struct ommmc_softc *sc, int mask, int timo)
+{
+       int status;
+       int s;
+
+       mask |= MMCHS_STAT_ERRI;
+
+       s = splsdmmc();
+       status = sc->intr_status & mask;
+       while (status == 0) {
+               if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+                   == EWOULDBLOCK) {
+                       status |= MMCHS_STAT_ERRI;
+                       break;
+               }
+               status = sc->intr_status & mask;
+       }
+       sc->intr_status &= ~status;
+
+       DPRINTF(2,("%s: intr status %#x error %#x\n", DEVNAME(sc), status,
+           sc->intr_error_status));
+
+       /* Command timeout has higher priority than command complete. */
+       if (ISSET(status, MMCHS_STAT_ERRI)) {
+               sc->intr_error_status = 0;
+               (void)ommmc_soft_reset(sc, MMCHS_SYSCTL_SRC|MMCHS_SYSCTL_SRD);
+               status = 0;
+       }
+
+       splx(s);
+       return (status);
+}
+
+/*
+ * Established by attachment driver at interrupt priority IPL_SDMMC.
+ */
+int
+ommmc_intr(void *arg)
+{
+       struct ommmc_softc *sc = arg;
+
+       uint32_t status;
+
+       /* Find out which interrupts are pending. */
+       status = HREAD4(sc, MMCHS_STAT);
+
+       /* Acknowledge the interrupts we are about to handle. */
+       HWRITE4(sc, MMCHS_STAT, status);
+       DPRINTF(2,("%s: interrupt status=%b\n", DEVNAME(sc),
+           status, MMCHS_STAT_FMT));
+
+       /*
+        * Service error interrupts.
+        */
+       if (ISSET(status, MMCHS_STAT_ERRI)) {
+               if (ISSET(status, MMCHS_STAT_CTO|
+                   MMCHS_STAT_DTO)) {
+                       sc->intr_status |= status;
+                       sc->intr_error_status |= status & 0xffff0000;
+                       wakeup(&sc->intr_status);
+               }
+       }
+
+#if 0
+       /*
+        * Wake up the sdmmc event thread to scan for cards.
+        */
+       if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION))
+               ommmc_needs_discover(sc->sdmmc);
+#endif
+
+       /*
+        * Wake up the blocking process to service command
+        * related interrupt(s).
+        */
+       if (ISSET(status, MMCHS_STAT_BRR|
+           MMCHS_STAT_BWR|MMCHS_STAT_TC|
+           MMCHS_STAT_CC)) {
+               sc->intr_status |= status;
+               wakeup(&sc->intr_status);
+       }
+
+       /*
+        * Service SD card interrupts.
+        */
+       if (ISSET(status, MMCHS_STAT_CIRQ)) {
+               DPRINTF(0,("%s: card interrupt\n", DEVNAME(sc)));
+               HCLR4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ);
+               sdmmc_card_intr(sc->sdmmc);
+       }
+       return 1;
+}
+
+#ifdef SDHC_DEBUG
+void
+ommmc_dump_regs(struct ommmc_softc *sc)
+{
+}
+#endif
diff --git a/omohci.c b/omohci.c
new file mode 100644 (file)
index 0000000..b4e1a8a
--- /dev/null
+++ b/omohci.c
@@ -0,0 +1,351 @@
+/*     $OpenBSD: omohci.c,v 1.3 2014/05/19 13:11:31 mpi Exp $ */
+
+/*
+ * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/timeout.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dev/usb/ohcireg.h>
+#include <dev/usb/ohcivar.h>
+#include <armv7/omap/prcmvar.h>
+
+#define HOSTUEADDR             0x0E0
+#define HOSTUESTATUS           0x0E4
+#define HOSTTIMEOUTCTRL                0x0E8
+#define HOSTREVISION           0x0EC
+#define WHM_REVID_REGISTER     0x0F4
+#define WHM_TEST_OBSV          0x0F8
+#define WHM_TEST_CTL           0x0FC
+#define HHC_TEST_CFG           0x100
+#define HHC_TEST_CTL           0x104
+#define HHC_TEST_OBSV          0x108
+#define REVDEV                 0x200 /* 16 bit */
+#define EP_NUM                 0x204 /* 16 bit */
+#define DATA                   0x208 /* 16 bit */
+#define CTRL                   0x20C /* 16 bit */
+#define STAT_FLG               0x210 /* 16 bit */
+#define RXFSTAT                        0x214 /* 16 bit */
+#define SYSCON1                        0x218 /* 16 bit */
+#define SYSCON2                        0x21C /* 16 bit */
+#define DEVSTAT                        0x220 /* 16 bit */
+#define SOFREG                 0x224 /* 16 bit */
+#define IRQ_EN                 0x228 /* 16 bit */
+#define DMA_IRQ_EN             0x22C /* 16 bit */
+#define IRQ_SRC                        0x230 /* 16 bit */
+#define EPN_STAT               0x234 /* 16 bit */
+#define DMAN_STAT              0x238 /* 16 bit */
+#define RXDMA_CFG              0x240 /* 16 bit */
+#define TXDMA_CFG              0x244 /* 16 bit */
+
+#define TXDMA0                 0x250
+#define TXDMA1         0x254
+#define TXDMA2         0x258
+#define RXDMA0         0x260
+#define RXDMA1         0x264
+#define RXDMA2         0x268
+
+#define EP0            0x280
+#define EP_RX(x)       0x280 + (x * 4)
+#define EP_TX(x)       0x2C0 + (x * 4)
+
+#define OTG_REV                0x300
+#define OTG_SYSCON_1   0x304
+#define OTG_SYSCON_2   0x308
+#define                OTG_SYSCON2_OTG_EN              0x80000000
+#define                OTG_SYSCON2_UHOST_EN            0x00000100
+#define                OTG_SYSCON2_MODE_DISABLED       0x00000000
+#define                OTG_SYSCON2_MODE_CLIENT         0x00000001
+#define                OTG_SYSCON2_MODE_HOST           0x00000004
+#define OTG_CTRL       0x30C
+#if 0
+#define OTG_IRQ_EN     0x310 /* 16 bit */
+#define OTG_IRQ_SRC    0x314 /* 16 bit */
+#define OTG_OUTCTRL    0x318 /* 16 bit */
+#define OTG_TEST       0x320 /* 16 bit */
+#endif
+#define OTG_VC         0x3FC
+
+
+int    omohci_match(struct device *, void *, void *);
+void   omohci_attach(struct device *, struct device *, void *);
+int    omohci_detach(struct device *, int);
+int    omohci_activate(struct device *, int);
+
+struct omohci_softc {
+       struct ohci_softc       sc;
+       void                    *sc_ihc0;
+       void                    *sc_ihc1;
+       void                    *sc_ihc2;
+       void                    *sc_ih0;
+       void                    *sc_ih1;
+       void                    *sc_ihotg;
+};
+
+void   omohci_enable(struct omohci_softc *);
+void   omohci_disable(struct omohci_softc *);
+
+struct cfattach omohci_ca = {
+        sizeof (struct omohci_softc), omohci_match, omohci_attach,
+       omohci_detach, omohci_detach
+};
+
+int
+omohci_match(struct device *parent, void *match, void *aux)
+{
+#if 0
+       if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
+               return (0);
+#endif
+
+       return (1);
+}
+
+void
+omohci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct omohci_softc     *sc = (struct omohci_softc *)self;
+        struct ahb_attach_args *aa = aux;
+       usbd_status             r;
+
+       sc->sc.iot = aa->aa_iot;
+       sc->sc.sc_bus.dmatag = aa->aa_dmat;
+       sc->sc_ih0 = NULL;
+       sc->sc_ih1 = NULL;
+       sc->sc_ihc0 = NULL;
+       sc->sc_ihc1 = NULL;
+       sc->sc_ihc2 = NULL;
+       sc->sc_ihotg = NULL;
+       sc->sc.sc_size = 0;
+
+       /* Map I/O space */
+       if (bus_space_map(sc->sc.iot, aa->aa_addr, aa->aa_size, 0,
+           &sc->sc.ioh)) {
+               printf(": cannot map mem space\n");
+               return;
+       }
+       sc->sc.sc_size = aa->aa_size;
+
+       /* XXX copied from ohci_pci.c. needed? */
+       bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size,
+           BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+
+#if 0
+       /* start the usb clock */
+       pxa2x0_clkman_config(CKEN_USBHC, 1);
+#endif
+       omohci_enable(sc);
+
+       /* Disable interrupts, so we don't get any spurious ones. */
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
+           OHCI_MIE);
+
+       sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       sc->sc_ihc1 = arm_intr_establish(aa->aa_intr+1, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       sc->sc_ihc2 = arm_intr_establish(aa->aa_intr+2, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       sc->sc_ih0 = arm_intr_establish(aa->aa_intr+3, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       sc->sc_ih1 = arm_intr_establish(aa->aa_intr+4, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       sc->sc_ihotg = arm_intr_establish(aa->aa_intr+5, IPL_USB,
+           ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+       if (sc->sc_ih0 == NULL ||
+           sc->sc_ih1 == NULL ||
+           sc->sc_ihc0 == NULL ||
+           sc->sc_ihc1 == NULL ||
+           sc->sc_ihc2 == NULL ||
+           sc->sc_ihotg == NULL) {
+               printf(": unable to establish interrupt\n");
+               omohci_disable(sc);
+#if 0
+               pxa2x0_clkman_config(CKEN_USBHC, 0);
+#endif
+               bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+               sc->sc.sc_size = 0;
+               return;
+       }
+
+       prcm_enablemodule(PRCM_USB);
+
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, OTG_SYSCON_2,
+           OTG_SYSCON2_UHOST_EN | OTG_SYSCON2_MODE_HOST);
+
+       strlcpy(sc->sc.sc_vendor, "OMAP24xx", sizeof(sc->sc.sc_vendor));
+       r = ohci_init(&sc->sc);
+       if (r != USBD_NORMAL_COMPLETION) {
+               printf("%s: init failed, error=%d\n",
+                   sc->sc.sc_bus.bdev.dv_xname, r);
+               arm_intr_disestablish(sc->sc_ih0);
+               arm_intr_disestablish(sc->sc_ih1);
+               arm_intr_disestablish(sc->sc_ihc0);
+               arm_intr_disestablish(sc->sc_ihc1);
+               arm_intr_disestablish(sc->sc_ihc2);
+               arm_intr_disestablish(sc->sc_ihotg);
+               sc->sc_ih0 = NULL;
+               sc->sc_ih1 = NULL;
+               sc->sc_ihc0 = NULL;
+               sc->sc_ihc1 = NULL;
+               sc->sc_ihc2 = NULL;
+               sc->sc_ihotg = NULL;
+               omohci_disable(sc);
+#if 0
+               pxa2x0_clkman_config(CKEN_USBHC, 0);
+#endif
+               bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+               sc->sc.sc_size = 0;
+               return;
+       }
+
+       config_found(self, &sc->sc.sc_bus, usbctlprint);
+}
+
+int
+omohci_detach(struct device *self, int flags)
+{
+       struct omohci_softc             *sc = (struct omohci_softc *)self;
+       int                             rv;
+
+       rv = ohci_detach(self, flags);
+       if (rv)
+               return (rv);
+
+       if (sc->sc_ih0 != NULL) {
+               arm_intr_disestablish(sc->sc_ih0);
+               arm_intr_disestablish(sc->sc_ih1);
+               arm_intr_disestablish(sc->sc_ihc0);
+               arm_intr_disestablish(sc->sc_ihc1);
+               arm_intr_disestablish(sc->sc_ihc2);
+               arm_intr_disestablish(sc->sc_ihotg);
+               sc->sc_ih0 = NULL;
+               sc->sc_ih1 = NULL;
+               sc->sc_ihc0 = NULL;
+               sc->sc_ihc1 = NULL;
+               sc->sc_ihc2 = NULL;
+               sc->sc_ihotg = NULL;
+       }
+
+       omohci_disable(sc);
+
+       /* stop clock */
+#if 0
+       pxa2x0_clkman_config(CKEN_USBHC, 0);
+#endif
+
+       if (sc->sc.sc_size) {
+               bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+               sc->sc.sc_size = 0;
+       }
+
+       return (0);
+}
+
+
+int
+omohci_activate(struct device *self, int act)
+{
+       struct omohci_softc *sc = (struct omohci_softc *)self;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               sc->sc.sc_bus.use_polling++;
+               ohci_power(why, &sc->sc);
+#if 0
+               pxa2x0_clkman_config(CKEN_USBHC, 0);
+#endif
+               sc->sc.sc_bus.use_polling--;
+               break;
+
+       case DVACT_RESUME:
+               sc->sc.sc_bus.use_polling++;
+#if 0
+               pxa2x0_clkman_config(CKEN_USBHC, 1);
+#endif
+               omohci_enable(sc);
+               ohci_power(why, &sc->sc);
+               sc->sc.sc_bus.use_polling--;
+               break;
+       }
+       return 0;
+}
+
+void
+omohci_enable(struct omohci_softc *sc)
+{
+#if 0
+       u_int32_t                       hr;
+
+       /* Full host reset */
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) | USBHC_HR_FHR);
+
+       DELAY(USBHC_RST_WAIT);
+
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
+
+       /* Force system bus interface reset */
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR);
+
+       while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \
+           USBHC_HR_FSBIR)
+               DELAY(3);
+
+       /* Enable the ports (physically only one, only enable that one?) */
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE));
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2));
+#endif
+}
+
+void
+omohci_disable(struct omohci_softc *sc)
+{
+#if 0
+       u_int32_t                       hr;
+
+       /* Full host reset */
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) | USBHC_HR_FHR);
+
+       DELAY(USBHC_RST_WAIT);
+
+       hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
+       bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
+           (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
+#endif
+}
diff --git a/omusbtll.c b/omusbtll.c
new file mode 100644 (file)
index 0000000..3ab7553
--- /dev/null
@@ -0,0 +1,175 @@
+/* $OpenBSD: omusbtll.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
+/*
+ * Copyright (c) 2010 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/evcount.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+
+/* registers */
+#define USBTLL_REVISION                        0x0000
+#define USBTLL_SYSCONFIG               0x0010
+#define USBTLL_SYSSTATUS               0x0014
+#define USBTLL_IRQSTATUS               0x0018
+#define USBTLL_IRQENABLE               0x001C
+#define USBTLL_SHARED_CONF                     0x0030
+#define  USBTLL_SHARED_CONF_USB_90D_DDR_EN     (1<<6)
+#define  USBTLL_SHARED_CONF_USB_180D_SDR_EN    (1<<5)
+#define  USBTLL_SHARED_CONF_USB_DIVRATIO_SH    2
+#define  USBTLL_SHARED_CONF_FCLK_REQ           (1<<1)
+#define  USBTLL_SHARED_CONF_FCLK_IS_ON         (1<<0)
+
+#define USBTLL_CHANNEL_CONF_(i)                (0x0040 + (0x04 * (i)))
+#define  USBTLL_CHANNEL_CONF_FSLSLINESTATE_SH          28
+#define  USBTLL_CHANNEL_CONF_FSLSMODE_SH               24
+#define  USBTLL_CHANNEL_CONF_TESTTXSE0                 (1<<20)
+#define  USBTLL_CHANNEL_CONF_TESTTXDAT                 (1<<19)
+#define  USBTLL_CHANNEL_CONF_TESTTXEN                  (1<<18)
+#define  USBTLL_CHANNEL_CONF_TESTEN                    (1<<17)
+#define  USBTLL_CHANNEL_CONF_DRVVBUS                           (1<<16)
+#define  USBTLL_CHANNEL_CONF_CHRGVBUS                  (1<<15)
+#define  USBTLL_CHANNEL_CONF_ULPINOBITSTUFF            (1<<11)
+#define  USBTLL_CHANNEL_CONF_ULPIAUTOIDLE              (1<<10)
+#define  USBTLL_CHANNEL_CONF_UTMIAUTOIDLE              (1<<9)
+#define  USBTLL_CHANNEL_CONF_ULPIDDRMODE               (1<<8)
+#define  USBTLL_CHANNEL_CONF_LPIOUTCLKMODE             (1<<7)
+#define  USBTLL_CHANNEL_CONF_TLLFULLSPEED              (1<<6)
+#define  USBTLL_CHANNEL_CONF_TLLCONNECT                (1<<5)
+#define  USBTLL_CHANNEL_CONF_TLLATTACH                 (1<<4)
+#define  USBTLL_CHANNEL_CONF_UTMIISADEV                (1<<3)
+#define  USBTLL_CHANNEL_CONF_CHANMODE_SH               1
+#define  USBTLL_CHANNEL_CONF_CHANEN                    (1<<0)
+
+/* 
+ULPI_VENDOR_ID_LO_(i)          (0x0800 + (0x100 * (i)))
+ULPI_VENDOR_ID_HI_(i)          (0x0801 + (0x100 * (i)))
+ULPI_PRODUCT_ID_LO_(i)         (0x0802 + (0x100 * (i)))
+ULPI_PRODUCT_ID_HI_(i)         (0x0803 + (0x100 * (i)))
+ULPI_FUNCTION_CTRL_(i)         (0x0804 + (0x100 * (i)))
+ULPI_FUNCTION_CTRL_SET_(i)     (0x0805 + (0x100 * (i)))
+ULPI_FUNCTION_CTRL_CLR_(i)     (0x0806 + (0x100 * (i)))
+ULPI_INTERFACE_CTRL_(i)                (0x0807 + (0x100 * (i)))
+ULPI_INTERFACE_CTRL_SET_(i)    (0x0808 + (0x100 * (i)))
+ULPI_INTERFACE_CTRL_CLR_(i)    (0x0809 + (0x100 * (i)))
+ULPI_OTG_CTRL_(i)              (0x080A + (0x100 * (i)))
+ULPI_OTG_CTRL_SET_(i)          (0x080B + (0x100 * (i)))
+ULPI_OTG_CTRL_CLR_(i)          (0x080C + (0x100 * (i)))
+ULPI_USB_INT_EN_RISE_(i)       (0x080D + (0x100 * (i)))
+ULPI_USB_INT_EN_RISE_SET_(i)   (0x080E + (0x100 * (i)))
+ULPI_USB_INT_EN_RISE_CLR_(i)   (0x080F + (0x100 * (i)))
+ULPI_USB_INT_EN_FALL_(i)       (0x0810 + (0x100 * (i)))
+ULPI_USB_INT_EN_FALL_SET_(i)   (0x0811 + (0x100 * (i)))
+ULPI_USB_INT_EN_FALL_CLR_(i)   (0x0812 + (0x100 * (i)))
+ULPI_USB_INT_STATUS_(i)                (0x0813 + (0x100 * (i)))
+ULPI_USB_INT_LATCH_(i)         (0x0814 + (0x100 * (i)))
+*/
+
+struct omusbtll_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+void omusbtll_attach(struct device *parent, struct device *self, void *args);
+void omusbtll_init(uint32_t channel_mask);
+
+struct cfattach        omusbtll_ca = {
+       sizeof (struct omusbtll_softc), NULL, omusbtll_attach
+};
+
+struct cfdriver omusbtll_cd = {
+       NULL, "omusbtll", DV_DULL
+};
+
+struct omusbtll_softc *omusbtll_sc;
+void
+omusbtll_attach(struct device *parent, struct device *self, void *args)
+{
+       struct omusbtll_softc *sc = (struct omusbtll_softc *) self;
+       struct armv7_attach_args *aa = args;
+       u_int32_t rev;
+
+       sc->sc_iot = aa->aa_iot;
+       if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) {
+               printf("%s: bus_space_map failed!\n", __func__);
+               return;
+       }
+
+#if 0
+       prcm_enablemodule(PRCM_USBHOST1);
+       prcm_enablemodule(PRCM_USBHOST2);
+#endif
+       prcm_enablemodule(PRCM_USBTLL);
+
+       delay(10000);
+
+       //return;
+#if 1
+       rev = bus_space_read_1(sc->sc_iot, sc->sc_ioh, USBTLL_SYSCONFIG);
+
+       printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
+#endif
+
+       omusbtll_sc = sc;
+
+       omusbtll_init(0x3);
+}
+
+
+void omusbtll_init(uint32_t channel_mask)
+{
+       int i;
+       uint32_t val;
+       /* global reacharound */
+       struct omusbtll_softc *sc = omusbtll_sc;
+
+       for(i = 0; i < 3; i++) {
+               val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   USBTLL_CHANNEL_CONF_(i));
+               val &= ~(USBTLL_CHANNEL_CONF_ULPINOBITSTUFF |
+                   USBTLL_CHANNEL_CONF_ULPIAUTOIDLE |
+                   USBTLL_CHANNEL_CONF_ULPIDDRMODE);
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+                   USBTLL_CHANNEL_CONF_(i), val);
+       }
+
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBTLL_SHARED_CONF);
+       val |= (USBTLL_SHARED_CONF_USB_180D_SDR_EN |
+           (1 << USBTLL_SHARED_CONF_USB_DIVRATIO_SH) |
+           USBTLL_SHARED_CONF_FCLK_IS_ON);
+       val &= ~(USBTLL_SHARED_CONF_USB_90D_DDR_EN);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBTLL_SHARED_CONF, val);
+
+       for (i = 0; i < 3; i++) {
+               if (channel_mask & (1<<i)) {
+                       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                           USBTLL_CHANNEL_CONF_(i));
+
+                       val |= USBTLL_CHANNEL_CONF_CHANEN;
+                       bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+                           USBTLL_CHANNEL_CONF_(i), val);
+               printf("usbtll enabling %d\n", i);
+               }
+       }
+}
diff --git a/prcm.c b/prcm.c
new file mode 100644 (file)
index 0000000..52b39c4
--- /dev/null
+++ b/prcm.c
@@ -0,0 +1,542 @@
+/* $OpenBSD: prcm.c,v 1.9 2014/05/08 21:17:01 miod Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*-
+ * Copyright (c) 2011
+ *     Ben Gray <ben.r.gray@gmail.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the 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 BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/*
+ * Driver for the Power, Reset and Clock Management Module (PRCM).
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+
+#include <armv7/omap/am335x_prcmreg.h>
+#include <armv7/omap/omap3_prcmreg.h>
+#include <armv7/omap/omap4_prcmreg.h>
+
+#define PRCM_REVISION          0x0800
+#define PRCM_SYSCONFIG         0x0810
+
+uint32_t prcm_imask_mask[PRCM_REG_MAX];
+uint32_t prcm_fmask_mask[PRCM_REG_MAX];
+uint32_t prcm_imask_addr[PRCM_REG_MAX];
+uint32_t prcm_fmask_addr[PRCM_REG_MAX];
+
+#define SYS_CLK                13 /* SYS_CLK speed in MHz */
+
+struct prcm_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_prcm;
+       bus_space_handle_t      sc_cm1;
+       bus_space_handle_t      sc_cm2;
+       void (*sc_setup)(struct prcm_softc *sc);
+       void (*sc_enablemodule)(struct prcm_softc *sc, int mod);
+       void (*sc_setclock)(struct prcm_softc *sc,
+           int clock, int speed);
+       uint32_t                cm1_avail;
+       uint32_t                cm2_avail;
+};
+
+int    prcm_match(struct device *, void *, void *);
+void   prcm_attach(struct device *, struct device *, void *);
+int    prcm_setup_dpll5(struct prcm_softc *);
+uint32_t prcm_v3_bit(int mod);
+uint32_t prcm_am335x_clkctrl(int mod);
+
+void prcm_am335x_enablemodule(struct prcm_softc *, int);
+void prcm_am335x_setclock(struct prcm_softc *, int, int);
+
+void prcm_v3_setup(struct prcm_softc *);
+void prcm_v3_enablemodule(struct prcm_softc *, int);
+void prcm_v3_setclock(struct prcm_softc *, int, int);
+
+void prcm_v4_enablemodule(struct prcm_softc *, int);
+int prcm_v4_hsusbhost_activate(int);
+int prcm_v4_hsusbhost_set_source(int, int);
+
+struct cfattach        prcm_ca = {
+       sizeof (struct prcm_softc), NULL, prcm_attach
+};
+
+struct cfdriver prcm_cd = {
+       NULL, "prcm", DV_DULL
+};
+
+void
+prcm_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct prcm_softc *sc = (struct prcm_softc *) self;
+       u_int32_t reg;
+
+       sc->sc_iot = aa->aa_iot;
+
+       switch (board_id) {
+       case BOARD_ID_AM335X_BEAGLEBONE:
+               sc->sc_setup = NULL;
+               sc->sc_enablemodule = prcm_am335x_enablemodule;
+               sc->sc_setclock = prcm_am335x_setclock;
+               break;
+       case BOARD_ID_OMAP3_BEAGLE:
+       case BOARD_ID_OMAP3_OVERO:
+               sc->sc_setup = prcm_v3_setup;
+               sc->sc_enablemodule = prcm_v3_enablemodule;
+               sc->sc_setclock = prcm_v3_setclock;
+               break;
+       case BOARD_ID_OMAP4_PANDA:
+               sc->sc_setup = NULL;
+               sc->sc_enablemodule = prcm_v4_enablemodule;
+               sc->sc_setclock = NULL;
+               sc->cm1_avail = 1;
+               sc->cm2_avail = 1;
+               break;
+       }
+
+       if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_prcm))
+               panic("prcm_attach: bus_space_map failed!");
+
+       if (sc->cm1_avail &&
+           bus_space_map(sc->sc_iot, aa->aa_dev->mem[1].addr,
+           aa->aa_dev->mem[1].size, 0, &sc->sc_cm1))
+               panic("prcm_attach: bus_space_map failed!");
+
+       if (sc->cm2_avail &&
+           bus_space_map(sc->sc_iot, aa->aa_dev->mem[2].addr,
+           aa->aa_dev->mem[2].size, 0, &sc->sc_cm2))
+               panic("prcm_attach: bus_space_map failed!");
+
+       reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION);
+       printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf);
+
+       if (sc->sc_setup != NULL)
+               sc->sc_setup(sc);
+}
+
+void
+prcm_v3_setup(struct prcm_softc *sc)
+{
+       /* Setup the 120MHZ DPLL5 clock, to be used by USB. */
+       prcm_setup_dpll5(sc);
+
+       prcm_fmask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FMASK;
+       prcm_imask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IMASK;
+       prcm_fmask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FADDR;
+       prcm_imask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IADDR;
+
+       prcm_fmask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FMASK;
+       prcm_imask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IMASK;
+       prcm_fmask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FADDR;
+       prcm_imask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IADDR;
+
+       prcm_fmask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FMASK;
+       prcm_imask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IMASK;
+       prcm_fmask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FADDR;
+       prcm_imask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IADDR;
+
+       prcm_fmask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_FMASK;
+       prcm_imask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_IMASK;
+       prcm_fmask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_FADDR;
+       prcm_imask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_IADDR;
+
+       prcm_fmask_mask[PRCM_REG_PER] = PRCM_REG_PER_FMASK;
+       prcm_imask_mask[PRCM_REG_PER] = PRCM_REG_PER_IMASK;
+       prcm_fmask_addr[PRCM_REG_PER] = PRCM_REG_PER_FADDR;
+       prcm_imask_addr[PRCM_REG_PER] = PRCM_REG_PER_IADDR;
+
+       prcm_fmask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FMASK;
+       prcm_imask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IMASK;
+       prcm_fmask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FADDR;
+       prcm_imask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IADDR;
+}
+
+void
+prcm_setclock(int clock, int speed)
+{
+       struct prcm_softc *sc = prcm_cd.cd_devs[0];
+
+       if (!sc->sc_setclock)
+               panic("%s: not initialised!", __func__);
+
+       sc->sc_setclock(sc, clock, speed);
+}
+
+void
+prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed)
+{
+       u_int32_t oreg, reg, mask;
+
+       /* set CLKSEL register */
+       if (clock == 1) {
+               oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
+                   PRCM_AM335X_CLKSEL_TIMER2_CLK);
+               mask = 3;
+               reg = oreg & ~mask;
+               reg |=0x02;
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm,
+                   PRCM_AM335X_CLKSEL_TIMER2_CLK, reg);
+       } else if (clock == 2) {
+               oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
+                   PRCM_AM335X_CLKSEL_TIMER3_CLK);
+               mask = 3;
+               reg = oreg & ~mask;
+               reg |=0x02;
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm,
+                   PRCM_AM335X_CLKSEL_TIMER3_CLK, reg);
+       }
+}
+
+void
+prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed)
+{
+       u_int32_t oreg, reg, mask;
+
+       if (clock == 1) {
+               oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP);
+               mask = 1;
+               reg = (oreg &~mask) | (speed & mask);
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg);
+       } else if (clock >= 2 && clock <= 9) {
+               int shift =  (clock-2);
+               oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER);
+               mask = 1 << (shift);
+               reg =  (oreg & ~mask) | ( (speed << shift) & mask);
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg);
+       } else
+               panic("%s: invalid clock %d", __func__, clock);
+}
+
+uint32_t
+prcm_v3_bit(int mod)
+{
+       switch(mod) {
+       case PRCM_MMC0:
+               return PRCM_CLK_EN_MMC1;
+       case PRCM_MMC1:
+               return PRCM_CLK_EN_MMC2;
+       case PRCM_MMC2:
+               return PRCM_CLK_EN_MMC3;
+       case PRCM_USB:
+               return PRCM_CLK_EN_USB;
+       case PRCM_GPIO0:
+               return PRCM_CLK_EN_GPIO1;
+       case PRCM_GPIO1:
+               return PRCM_CLK_EN_GPIO2;
+       case PRCM_GPIO2:
+               return PRCM_CLK_EN_GPIO3;
+       case PRCM_GPIO3:
+               return PRCM_CLK_EN_GPIO4;
+       case PRCM_GPIO4:
+               return PRCM_CLK_EN_GPIO5;
+       case PRCM_GPIO5:
+               return PRCM_CLK_EN_GPIO6;
+       default:
+               panic("%s: module not found\n", __func__);
+       }
+}
+
+uint32_t
+prcm_am335x_clkctrl(int mod)
+{
+       switch(mod) {
+       case PRCM_TIMER2:
+               return PRCM_AM335X_TIMER2_CLKCTRL;
+       case PRCM_TIMER3:
+               return PRCM_AM335X_TIMER3_CLKCTRL;
+       case PRCM_MMC0:
+               return PRCM_AM335X_MMC0_CLKCTRL;
+       case PRCM_MMC1:
+               return PRCM_AM335X_MMC1_CLKCTRL;
+       case PRCM_MMC2:
+               return PRCM_AM335X_MMC2_CLKCTRL;
+       case PRCM_USB:
+               return PRCM_AM335X_USB0_CLKCTRL;
+       case PRCM_GPIO0:
+               return PRCM_AM335X_GPIO0_CLKCTRL;
+       case PRCM_GPIO1:
+               return PRCM_AM335X_GPIO1_CLKCTRL;
+       case PRCM_GPIO2:
+               return PRCM_AM335X_GPIO2_CLKCTRL;
+       case PRCM_GPIO3:
+               return PRCM_AM335X_GPIO3_CLKCTRL;
+       case PRCM_TPCC:
+               return PRCM_AM335X_TPCC_CLKCTRL;
+       case PRCM_TPTC0:
+               return PRCM_AM335X_TPTC0_CLKCTRL;
+       case PRCM_TPTC1:
+               return PRCM_AM335X_TPTC1_CLKCTRL;
+       case PRCM_TPTC2:
+               return PRCM_AM335X_TPTC2_CLKCTRL;
+       case PRCM_I2C0:
+               return PRCM_AM335X_I2C0_CLKCTRL;
+       case PRCM_I2C1:
+               return PRCM_AM335X_I2C1_CLKCTRL;
+       case PRCM_I2C2:
+               return PRCM_AM335X_I2C2_CLKCTRL;
+       default:
+               panic("%s: module not found\n", __func__);
+       }
+}
+
+void
+prcm_enablemodule(int mod)
+{
+       struct prcm_softc *sc = prcm_cd.cd_devs[0];
+
+       if (!sc->sc_enablemodule)
+               panic("%s: not initialised!", __func__);
+
+       sc->sc_enablemodule(sc, mod);
+}
+
+void
+prcm_am335x_enablemodule(struct prcm_softc *sc, int mod)
+{
+       uint32_t clkctrl;
+       int reg;
+
+       /*set enable bits in CLKCTRL register */
+       reg = prcm_am335x_clkctrl(mod);
+       clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg);
+       clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK;
+       clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE;
+       bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl);
+
+       /* wait until module is enabled */
+       while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000)
+               ;
+}
+
+void
+prcm_v3_enablemodule(struct prcm_softc *sc, int mod)
+{
+       uint32_t bit;
+       uint32_t fclk, iclk, fmask, imask, mbit;
+       int freg, ireg, reg;
+
+       bit = prcm_v3_bit(mod);
+       reg = bit >> 5;
+
+       freg = prcm_fmask_addr[reg];
+       ireg = prcm_imask_addr[reg];
+       fmask = prcm_fmask_mask[reg];
+       imask = prcm_imask_mask[reg];
+
+       mbit = 1 << (bit & 0x1f);
+       if (fmask & mbit) { /* dont access the register if bit isn't present */
+               fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg);
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit);
+       }
+       if (imask & mbit) { /* dont access the register if bit isn't present */
+               iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg);
+               bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit);
+       }
+       printf("\n");
+}
+
+void
+prcm_v4_enablemodule(struct prcm_softc *sc, int mod)
+{
+       switch (mod) {
+               case PRCM_MMC0:
+                       break;
+               case PRCM_USBP1_PHY:
+               case PRCM_USBP2_PHY:
+                       prcm_v4_hsusbhost_set_source(mod, 0);
+               case PRCM_USB:
+               case PRCM_USBTLL:
+               case PRCM_USBP1_UTMI:
+               case PRCM_USBP1_HSIC:
+               case PRCM_USBP2_UTMI:
+               case PRCM_USBP2_HSIC:
+                       prcm_v4_hsusbhost_activate(mod);
+                       return;
+               case  PRCM_GPIO0:
+               case  PRCM_GPIO1:
+               case  PRCM_GPIO2:
+               case  PRCM_GPIO3:
+               case  PRCM_GPIO4:
+               case  PRCM_GPIO5:
+                       /* XXX */
+                       break;
+       default:
+               panic("%s: module not found\n", __func__);
+       }
+}
+
+int
+prcm_v4_hsusbhost_activate(int type)
+{
+       struct prcm_softc *sc = prcm_cd.cd_devs[0];
+       uint32_t i;
+       uint32_t clksel_reg_off;
+       uint32_t clksel, oclksel;
+
+       switch (type) {
+               case PRCM_USB:
+               case PRCM_USBP1_PHY:
+               case PRCM_USBP2_PHY:
+                       /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+                       clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
+                       clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
+                       oclksel = clksel;
+                       /* Enable the module and also enable the optional func clocks */
+                       if (type == PRCM_USB) {
+                               clksel &= ~O4_CLKCTRL_MODULEMODE_MASK;
+                               clksel |=  /*O4_CLKCTRL_MODULEMODE_ENABLE*/2;
+
+                               clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
+                       }
+
+                       break;
+
+               default:
+                       panic("%s: invalid type %d", __func__, type);
+                       return (EINVAL);
+       }
+       bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
+
+       /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+       for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) {
+               clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
+               if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED)
+                       break;
+       }
+
+       /* Check the enabled state */
+       if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) {
+               printf("Error: HERE failed to enable module with clock %d\n", type);
+               printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
+               return (ETIMEDOUT);
+       }
+
+       return (0);
+}
+
+int
+prcm_v4_hsusbhost_set_source(int clk, int clksrc)
+{
+       struct prcm_softc *sc = prcm_cd.cd_devs[0];
+       uint32_t clksel_reg_off;
+       uint32_t clksel;
+       unsigned int bit;
+
+       if (clk == PRCM_USBP1_PHY)
+               bit = 24;
+       else if (clk != PRCM_USBP2_PHY)
+               bit = 25;
+       else
+               return (-EINVAL);
+
+       /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+       clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
+       clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
+
+       /* XXX: Set the clock source to either external or internal */
+       if (clksrc == 0)
+               clksel |= (0x1 << bit);
+       else
+               clksel &= ~(0x1 << bit);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
+
+       return (0);
+}
+
+/*
+ * OMAP35xx Power, Reset, and Clock Management Reference Guide
+ * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference
+ * Manual (sprugn4h.pdf) note that DPLL5 provides a 120MHz clock for
+ * peripheral domain modules (page 107 and page 302).
+ * The reference clock for DPLL5 is DPLL5_ALWON_FCLK which is
+ * SYS_CLK, running at 13MHz.
+ */
+int
+prcm_setup_dpll5(struct prcm_softc *sc)
+{
+       uint32_t val;
+
+       /*
+        * We need to set the multiplier and divider values for PLL.
+        * To end up with 120MHz we take SYS_CLK, divide by it and multiply
+        * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration)
+        */
+       val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f);
+       bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val);
+
+       /* Clock divider from the PLL to the 120MHz clock. */
+       bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val);
+
+       /*
+        * spruf98o.pdf, page 2319:
+        * PERIPH2_DPLL_FREQSEL is 0x7 1.75MHz to 2.1MHz
+        * EN_PERIPH2_DPLL is 0x7
+        */
+       val = (7 << 4) | (7 << 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val);
+
+       /* Disable the interconnect clock auto-idle. */
+       bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0);
+
+       /* Wait until DPLL5 is locked and there's clock activity. */
+       while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
+           CM_IDLEST_CKGEN) & 0x01) == 0x00) {
+#ifdef DIAGNOSTIC
+               printf("CM_IDLEST_PLL = 0x%08x\n", val);
+#endif
+       }
+
+       return 0;
+}
diff --git a/prcmvar.h b/prcmvar.h
new file mode 100644 (file)
index 0000000..736bcfc
--- /dev/null
+++ b/prcmvar.h
@@ -0,0 +1,57 @@
+/* $OpenBSD: prcmvar.h,v 1.5 2014/03/18 07:34:17 syl Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void prcm_setclock(int clock, int speed);
+void prcm_enablemodule(int mod);
+void prcm_disablemodule(int mod);
+
+#define PRCM_CLK_SPEED_32      0
+#define PRCM_CLK_SPEED_SYS     1
+
+enum PRCM_MODULES {
+       PRCM_TIMER0,
+       PRCM_TIMER1,
+       PRCM_TIMER2,
+       PRCM_TIMER3,
+       PRCM_GPIO0,
+       PRCM_GPIO1,
+       PRCM_GPIO2,
+       PRCM_GPIO3,
+       PRCM_GPIO4,
+       PRCM_GPIO5,
+       PRCM_TPCC,
+       PRCM_TPTC0,
+       PRCM_TPTC1,
+       PRCM_TPTC2,
+       PRCM_MMC0,
+       PRCM_MMC1,
+       PRCM_MMC2,
+       PRCM_USB,
+       PRCM_USBTLL,
+       PRCM_USBP1_PHY,
+       PRCM_USBP1_UTMI,
+       PRCM_USBP1_HSIC,
+       PRCM_USBP2_PHY,
+       PRCM_USBP2_UTMI,
+       PRCM_USBP2_HSIC,
+       PRCM_I2C0,
+       PRCM_I2C1,
+       PRCM_I2C2,
+};
+
+#define PRCM_REG_MAX   6
+/* need interface for CM_AUTOIDLE */
diff --git a/sitara_cm.c b/sitara_cm.c
new file mode 100644 (file)
index 0000000..4958a4f
--- /dev/null
@@ -0,0 +1,394 @@
+/* $OpenBSD: sitara_cm.c,v 1.2 2013/11/06 19:03:07 syl Exp $ */
+/* $NetBSD: sitara_cm.c,v 1.1 2013/04/17 14:31:02 bouyer Exp $ */
+/*
+ * Copyright (c) 2010
+ *     Ben Gray <ben.r.gray@gmail.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/*
+ * SCM - System Control Module
+ *
+ * Hopefully in the end this module will contain a bunch of utility functions
+ * for configuring and querying the general system control registers, but for
+ * now it only does pin(pad) multiplexing.
+ *
+ * This is different from the GPIO module in that it is used to configure the
+ * pins between modules not just GPIO input/output.
+ *
+ * This file contains the generic top level driver, however it relies on chip
+ * specific settings and therefore expects an array of sitara_cm_padconf structs
+ * call ti_padconf_devmap to be located somewhere in the kernel.
+ *
+ */
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <machine/bus.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/sitara_cm.h>
+#include <armv7/omap/sitara_cmreg.h>
+
+void sitara_cm_attach(struct device *parent, struct device *self, void *aux);
+
+struct sitara_cm_softc {
+        struct device          sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct cfattach sitaracm_ca = {
+       sizeof (struct sitara_cm_softc), NULL, sitara_cm_attach
+};
+
+struct cfdriver sitaracm_cd = {
+       NULL, "sitaracm", DV_DULL
+};
+
+static struct sitara_cm_softc *sitara_cm_sc = NULL;
+
+#define        sitara_cm_read_2(sc, reg)               \
+    bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define        sitara_cm_write_2(sc, reg, val)         \
+    bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define        sitara_cm_read_4(sc, reg)               \
+    bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define        sitara_cm_write_4(sc, reg, val)         \
+    bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+
+/**
+ *     ti_padconf_devmap - Array of pins, should be defined one per SoC
+ *
+ *     This array is typically defined in one of the targeted *_scm_pinumx.c
+ *     files and is specific to the given SoC platform. Each entry in the array
+ *     corresponds to an individual pin.
+ */
+extern const struct sitara_cm_device sitara_cm_dev;
+
+
+/**
+ *     sitara_cm_padconf_from_name - searches the list of pads and returns entry
+ *                                  with matching ball name.
+ *     @ballname: the name of the ball
+ *
+ *     RETURNS:
+ *     A pointer to the matching padconf or NULL if the ball wasn't found.
+ */
+static const struct sitara_cm_padconf*
+sitara_cm_padconf_from_name(const char *ballname)
+{
+       const struct sitara_cm_padconf *padconf;
+
+       padconf = sitara_cm_dev.padconf;
+       while (padconf->ballname != NULL) {
+               if (strcmp(ballname, padconf->ballname) == 0)
+                       return(padconf);
+               padconf++;
+       }
+       
+       return (NULL);
+}
+
+/**
+ *     sitara_cm_padconf_set_internal - sets the muxmode and state for a pad/pin
+ *     @padconf: pointer to the pad structure
+ *     @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ *     @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *     
+ *
+ *     LOCKING:
+ *     Internally locks it's own context.
+ *
+ *     RETURNS:
+ *     0 on success.
+ *     EINVAL if pin requested is outside valid range or already in use.
+ */
+static int
+sitara_cm_padconf_set_internal(struct sitara_cm_softc *sc,
+    const struct sitara_cm_padconf *padconf,
+    const char *muxmode, unsigned int state)
+{
+       unsigned int mode;
+       uint16_t reg_val;
+
+       /* populate the new value for the PADCONF register */
+       reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask);
+
+       /* find the new mode requested */
+       for (mode = 0; mode < 8; mode++) {
+               if ((padconf->muxmodes[mode] != NULL) &&
+                   (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
+                       break;
+               }
+       }
+
+       /* couldn't find the mux mode */
+       if (mode >= 8) {
+               printf("%s: Invalid mux mode \"%s\"\n", __func__, muxmode);
+               return (EINVAL);
+       }
+
+       /* set the mux mode */
+       reg_val |= (uint16_t)(mode & sitara_cm_dev.padconf_muxmode_mask);
+       
+       /* write the register value (16-bit writes) */
+       sitara_cm_write_2(sc, padconf->reg_off, reg_val);
+       
+       return (0);
+}
+
+/**
+ *     sitara_cm_padconf_set - sets the muxmode and state for a pad/pin
+ *     @padname: the name of the pad, i.e. "c12"
+ *     @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ *     @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *     
+ *
+ *     LOCKING:
+ *     Internally locks it's own context.
+ *
+ *     RETURNS:
+ *     0 on success.
+ *     EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+sitara_cm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
+{
+       const struct sitara_cm_padconf *padconf;
+
+       if (!sitara_cm_sc)
+               return (ENXIO);
+
+       /* find the pin in the devmap */
+       padconf = sitara_cm_padconf_from_name(padname);
+       if (padconf == NULL)
+               return (EINVAL);
+       
+       return (
+           sitara_cm_padconf_set_internal(sitara_cm_sc, padconf, muxmode, state)
+           );
+}
+
+/**
+ *     sitara_cm_padconf_get - gets the muxmode and state for a pad/pin
+ *     @padname: the name of the pad, i.e. "c12"
+ *     @muxmode: upon return will contain the name of the muxmode of the pin
+ *     @state: upon return will contain the state of the pad/pin
+ *     
+ *
+ *     LOCKING:
+ *     Internally locks it's own context.
+ *
+ *     RETURNS:
+ *     0 on success.
+ *     EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+sitara_cm_padconf_get(const char *padname, const char **muxmode,
+    unsigned int *state)
+{
+       const struct sitara_cm_padconf *padconf;
+       uint16_t reg_val;
+
+       if (!sitara_cm_sc)
+               return (ENXIO);
+
+       /* find the pin in the devmap */
+       padconf = sitara_cm_padconf_from_name(padname);
+       if (padconf == NULL)
+               return (EINVAL);
+       
+       /* read the register value (16-bit reads) */
+       reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off);
+
+       /* save the state */
+       if (state)
+               *state = (reg_val & sitara_cm_dev.padconf_sate_mask);
+
+       /* save the mode */
+       if (muxmode) {
+               *muxmode = padconf->muxmodes[
+                   (reg_val & sitara_cm_dev.padconf_muxmode_mask)
+                   ];
+       }
+       
+       return (0);
+}
+
+/**
+ *     sitara_cm_padconf_set_gpiomode - converts a pad to GPIO mode.
+ *     @gpio: the GPIO pin number (0-195)
+ *     @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *
+ *     
+ *
+ *     LOCKING:
+ *     Internally locks it's own context.
+ *
+ *     RETURNS:
+ *     0 on success.
+ *     EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+sitara_cm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
+{
+       const struct sitara_cm_padconf *padconf;
+       uint16_t reg_val;
+
+       if (!sitara_cm_sc)
+               return (ENXIO);
+       
+       /* find the gpio pin in the padconf array */
+       padconf = sitara_cm_dev.padconf;
+       while (padconf->ballname != NULL) {
+               if (padconf->gpio_pin == gpio)
+                       break;
+               padconf++;
+       }
+       if (padconf->ballname == NULL)
+               return (EINVAL);
+
+       /* populate the new value for the PADCONF register */
+       reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask);
+
+       /* set the mux mode */
+       reg_val |=
+           (uint16_t)(padconf->gpio_mode & sitara_cm_dev.padconf_muxmode_mask);
+
+       /* write the register value (16-bit writes) */
+       sitara_cm_write_2(sitara_cm_sc, padconf->reg_off, reg_val);
+
+       return (0);
+}
+
+/**
+ *     sitara_cm_padconf_get_gpiomode - gets the current GPIO mode of the pin
+ *     @gpio: the GPIO pin number (0-195)
+ *     @state: upon return will contain the state
+ *
+ *     
+ *
+ *     LOCKING:
+ *     Internally locks it's own context.
+ *
+ *     RETURNS:
+ *     0 on success.
+ *     EINVAL if pin requested is outside valid range or not configured as GPIO.
+ */
+int
+sitara_cm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
+{
+       const struct sitara_cm_padconf *padconf;
+       uint16_t reg_val;
+
+       if (!sitara_cm_sc)
+               return (ENXIO);
+       
+       /* find the gpio pin in the padconf array */
+       padconf = sitara_cm_dev.padconf;
+       while (padconf->ballname != NULL) {
+               if (padconf->gpio_pin == gpio)
+                       break;
+               padconf++;
+       }
+       if (padconf->ballname == NULL)
+               return (EINVAL);
+
+       /* read the current register settings */
+       reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off);
+       
+       /*
+        * check to make sure the pins is configured as GPIO in the
+        * first state
+        */
+       if ((reg_val & sitara_cm_dev.padconf_muxmode_mask) !=
+           padconf->gpio_mode)
+               return (EINVAL);
+       
+       /*
+        * read and store the reset of the state,
+        * i.e. pull-up, pull-down, etc
+        */
+       if (state)
+               *state = (reg_val & sitara_cm_dev.padconf_sate_mask);
+       
+       return (0);
+}
+
+
+int
+sitara_cm_reg_read_4(uint32_t reg, uint32_t *val)
+{
+       if (!sitara_cm_sc)
+               return (ENXIO);
+
+       *val = sitara_cm_read_4(sitara_cm_sc, reg);
+       return (0);
+}
+
+int
+sitara_cm_reg_write_4(uint32_t reg, uint32_t val)
+{
+       if (!sitara_cm_sc)
+               return (ENXIO);
+
+       sitara_cm_write_4(sitara_cm_sc, reg, val);
+       return (0);
+}
+
+void
+sitara_cm_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct sitara_cm_softc *sc = (struct sitara_cm_softc *)self;
+       struct armv7_attach_args *aa = aux;
+       uint32_t rev;
+
+       if (sitara_cm_sc)
+               panic("sitara_cm_attach: already attached");
+
+       sc->sc_iot = aa->aa_iot;
+
+       if (bus_space_map(aa->aa_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_ioh) != 0)
+               panic("%s: bus_space_map failed!\n", __func__);
+
+       sitara_cm_sc = sc;
+
+       if (sitara_cm_reg_read_4(OMAP2SCM_REVISION, &rev) != 0)
+               panic("sitara_cm_attach: read revision");
+       printf(": control module, rev %d.%d\n",
+           SCM_REVISION_MAJOR(rev), SCM_REVISION_MINOR(rev));
+}
diff --git a/sitara_cm.h b/sitara_cm.h
new file mode 100644 (file)
index 0000000..96be967
--- /dev/null
@@ -0,0 +1,78 @@
+/* $OpenBSD: sitara_cm.h,v 1.1 2013/09/04 14:38:32 patrick Exp $ */
+/* $NetBSD: sitara_cm.h,v 1.1 2013/04/17 14:31:02 bouyer Exp $ */
+/*
+ * Copyright (c) 2010
+ *     Ben Gray <ben.r.gray@gmail.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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.
+ *
+ */
+
+
+/**
+ *     Functions to configure the PIN multiplexing on the chip.
+ *
+ *     This is different from the GPIO module in that it is used to configure the
+ *     pins between modules not just GPIO input output.
+ *
+ */
+#ifndef _OMAP_SCM_H_
+#define _OMAP_SCM_H_
+
+struct sitara_cm_padconf {
+       uint16_t    reg_off;
+       uint16_t    gpio_pin;
+       uint16_t    gpio_mode;
+       const char  *ballname;
+       const char  *muxmodes[8];
+};
+
+struct sitara_cm_padstate {
+       const char  *state;
+       uint16_t    reg;
+};
+
+struct sitara_cm_device {
+       uint16_t                        padconf_muxmode_mask;
+       uint16_t                        padconf_sate_mask;
+       struct sitara_cm_padstate       *padstate;
+       struct sitara_cm_padconf                *padconf;
+};
+
+int sitara_cm_padconf_set(const char *padname, const char *muxmode, 
+    unsigned int state);
+int sitara_cm_padconf_get(const char *padname, const char **muxmode,
+    unsigned int *state);
+int sitara_cm_padconf_set_gpiomode(uint32_t gpio, unsigned int state);
+int sitara_cm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state);
+int sitara_cm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags);
+void sitara_cm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags);
+int sitara_cm_reg_read_4(uint32_t reg, uint32_t *val);
+int sitara_cm_reg_write_4(uint32_t reg, uint32_t val);
+
+#endif /* _OMAP_SCM_H_ */
diff --git a/sitara_cmreg.h b/sitara_cmreg.h
new file mode 100644 (file)
index 0000000..65aeeeb
--- /dev/null
@@ -0,0 +1,46 @@
+/* $OpenBSD: sitara_cmreg.h,v 1.1 2013/09/04 14:38:32 patrick Exp $ */
+/*     $NetBSD: sitara_cmreg.h,v 1.1 2013/04/17 15:04:39 bouyer Exp $  */
+
+/*
+ * Copyright (c) 2013 Manuel Bouyer.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* register definitions for the Control module found in the
+ * Texas Instrument AM335x SOC
+ */
+
+#ifndef _OMAP2SCMREG_H
+#define _OMAP2SCMREG_H
+
+#define OMAP2SCM_REVISION      0x0000
+#define SCM_REVISION_SCHEME(x) (((x) & 0xc0000000) >> 30)
+#define SCM_REVISION_FUNC(x)   (((x) & 0x0fff0000) >> 16)
+#define SCM_REVISION_RTL(x)    (((x) & 0x0000f800) >> 11)
+#define SCM_REVISION_MAJOR(x)  (((x) & 0x00000700) >>  8)
+#define SCM_REVISION_CUSTOM(x) (((x) & 0x000000c0) >>  6)
+#define SCM_REVISION_MINOR(x)  (((x) & 0x0000001f) >>  0)
+
+#define OMAP2SCM_MAC_ID0_LO    0x630
+#define OMAP2SCM_MAC_ID0_HI    0x634
+
+#endif /* _OMAP2SCMREG_H */
diff --git a/ti_iic.c b/ti_iic.c
new file mode 100644 (file)
index 0000000..33ad915
--- /dev/null
+++ b/ti_iic.c
@@ -0,0 +1,589 @@
+/*     $OpenBSD: ti_iic.c,v 1.2 2014/03/18 14:23:52 rapha Exp $        */
+/* $NetBSD: ti_iic.c,v 1.4 2013/04/25 13:04:27 rkujawa Exp $ */
+
+/*
+ * Copyright (c) 2013 Manuel Bouyer.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 2012 Jared D. McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/omap/prcmvar.h>
+#include <armv7/omap/sitara_cm.h>
+#include <armv7/omap/sitara_cmreg.h>
+#include <armv7/omap/ti_iicreg.h>
+
+#ifndef AM335X_I2C_SLAVE_ADDR
+#define AM335X_I2C_SLAVE_ADDR  0x01
+#endif
+
+#ifdef I2CDEBUG
+#define DPRINTF(args)  printf args
+#else
+#define DPRINTF(args)
+#endif
+
+/* operation in progress */
+typedef enum {
+       TI_I2CREAD,
+       TI_I2CWRITE,
+       TI_I2CDONE,
+       TI_I2CERROR
+} ti_i2cop_t;
+
+struct ti_iic_softc {
+       struct device           sc_dev;
+       struct i2c_controller   sc_ic;
+       struct rwlock           sc_buslock;
+       struct device           *sc_i2cdev;
+
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+
+       void                    *sc_ih;
+       ti_i2cop_t              sc_op;
+       int                     sc_buflen;
+       int                     sc_bufidx;
+       char                    *sc_buf;
+
+       int                     sc_rxthres;
+       int                     sc_txthres;
+};
+
+
+#define I2C_READ_REG(sc, reg)          \
+       bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define I2C_READ_DATA(sc)              \
+       bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, AM335X_I2C_DATA);
+#define I2C_WRITE_REG(sc, reg, val)    \
+       bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define I2C_WRITE_DATA(sc, val)                \
+       bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, AM335X_I2C_DATA, (val))
+
+#define DEVNAME(sc)    ((sc)->sc_dev.dv_xname)
+
+static void    ti_iic_attach(struct device *, struct device *, void *);
+static int     ti_iic_intr(void *);
+
+static int     ti_iic_acquire_bus(void *, int);
+static void    ti_iic_release_bus(void *, int);
+static int     ti_iic_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+                   size_t, void *, size_t, int);
+
+static int     ti_iic_reset(struct ti_iic_softc *);
+static int     ti_iic_op(struct ti_iic_softc *, i2c_addr_t, ti_i2cop_t,
+                   uint8_t *, size_t, int);
+static void    ti_iic_handle_intr(struct ti_iic_softc *, uint32_t);
+static void    ti_iic_do_read(struct ti_iic_softc *, uint32_t);
+static void    ti_iic_do_write(struct ti_iic_softc *, uint32_t);
+
+static int     ti_iic_wait(struct ti_iic_softc *, uint16_t, uint16_t, int);
+static uint32_t        ti_iic_stat(struct ti_iic_softc *, uint32_t);
+static int     ti_iic_flush(struct ti_iic_softc *);
+
+struct cfattach tiiic_ca = {
+       sizeof (struct ti_iic_softc), NULL, ti_iic_attach
+};
+
+struct cfdriver tiiic_cd = {
+       NULL, "tiiic", DV_DULL
+};
+
+static void
+ti_iic_attach(struct device *parent, struct device *self, void *args)
+{
+       struct ti_iic_softc *sc = (struct ti_iic_softc *)self;
+       struct armv7_attach_args *aa = args;
+       struct i2cbus_attach_args iba;
+       uint16_t rev;
+       const char *mode;
+       u_int state;
+       char buf[20];
+       char *pin;
+       /* BBB specific pin names */
+       char *pins[6] = {"I2C0_SDA", "I2C0_SCL",
+                       "SPIO_D1", "SPI0_CS0",
+                       "UART1_CTSn", "UART1_RTSn"};
+
+       sc->sc_iot = aa->aa_iot;
+       rw_init(&sc->sc_buslock, "tiiilk");
+
+       sc->sc_rxthres = sc->sc_txthres = 4;
+
+       if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
+           aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!");
+
+       sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_NET,
+           ti_iic_intr, sc, DEVNAME(sc));
+
+       prcm_enablemodule(PRCM_I2C0 + aa->aa_dev->unit);
+
+       if (board_id == BOARD_ID_AM335X_BEAGLEBONE) {
+               pin = pins[aa->aa_dev->unit * 2];
+               snprintf(buf, sizeof buf, "I2C%d_SDA", aa->aa_dev->unit);
+               if (sitara_cm_padconf_set(pin, buf,
+                   (0x01 << 4) | (0x01 << 5) | (0x01 << 6)) != 0) {
+                       printf(": can't switch %s pad\n", buf);
+                       return;
+               }
+               if (sitara_cm_padconf_get(pin, &mode, &state) == 0) {
+                       printf(": %s state %d ", mode, state);
+               }
+
+               pin = pins[aa->aa_dev->unit * 2 + 1];
+               snprintf(buf, sizeof buf, "I2C%d_SCL", aa->aa_dev->unit);
+               if (sitara_cm_padconf_set(pin, buf,
+                   (0x01 << 4) | (0x01 << 5) | (0x01 << 6)) != 0) {
+                       printf(": can't switch %s pad\n", buf);
+                       return;
+               }
+               if (sitara_cm_padconf_get(pin, &mode, &state) == 0) {
+                       printf(": %s state %d ", mode, state);
+               }
+       }
+
+       rev = I2C_READ_REG(sc, AM335X_I2C_REVNB_LO);
+       printf(" rev %d.%d\n",
+           (int)I2C_REVNB_LO_MAJOR(rev),
+           (int)I2C_REVNB_LO_MINOR(rev));
+
+       ti_iic_reset(sc);
+       ti_iic_flush(sc);
+
+       sc->sc_ic.ic_cookie = sc;
+       sc->sc_ic.ic_acquire_bus = ti_iic_acquire_bus;
+       sc->sc_ic.ic_release_bus = ti_iic_release_bus;
+       sc->sc_ic.ic_exec = ti_iic_exec;
+
+       bzero(&iba, sizeof iba);
+       iba.iba_name = "iic";
+       iba.iba_tag = &sc->sc_ic;
+       (void) config_found(&sc->sc_dev, &iba, iicbus_print);
+}
+
+static int
+ti_iic_intr(void *arg)
+{
+       struct ti_iic_softc *sc = arg;
+       uint32_t stat;
+
+       DPRINTF(("ti_iic_intr\n"));
+       stat = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS);
+       I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS, stat);
+       DPRINTF(("ti_iic_intr pre handle sc->sc_op eq %#x\n", sc->sc_op));
+
+       ti_iic_handle_intr(sc, stat);
+
+       if (sc->sc_op == TI_I2CERROR || sc->sc_op == TI_I2CDONE) {
+               DPRINTF(("ti_iic_intr post handle sc->sc_op %#x\n", sc->sc_op));
+               wakeup(&sc->sc_dev);
+       }
+
+       DPRINTF(("ti_iic_intr status 0x%x\n", stat));
+
+       return 1;
+}
+
+static int
+ti_iic_acquire_bus(void *opaque, int flags)
+{
+       struct ti_iic_softc *sc = opaque;
+
+       if (flags & I2C_F_POLL)
+               return 0;
+
+       return (rw_enter(&sc->sc_buslock, RW_WRITE));
+}
+
+static void
+ti_iic_release_bus(void *opaque, int flags)
+{
+       struct ti_iic_softc *sc = opaque;
+
+       if (flags & I2C_F_POLL)
+               return;
+
+       rw_exit(&sc->sc_buslock);
+}
+
+static int
+ti_iic_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
+    const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+       struct ti_iic_softc *sc = opaque;
+       int err;
+
+
+       DPRINTF(("ti_iic_exec: op 0x%x cmdlen %zd len %zd flags 0x%x\n",
+           op, cmdlen, len, flags));
+
+#define __UNCONST(a)  ((void *)(unsigned long)(const void *)(a))
+       if (cmdlen > 0) {
+               err = ti_iic_op(sc, addr, TI_I2CWRITE, __UNCONST(cmdbuf),
+                   cmdlen, (I2C_OP_READ_P(op) ? 0 : I2C_F_STOP) | flags);
+               if (err)
+                       goto done;
+       }
+       if (I2C_OP_STOP_P(op))
+               flags |= I2C_F_STOP;
+
+       /*
+        * I2C controller doesn't allow for zero-byte transfers.
+        */
+       if (len == 0)
+               goto done;
+
+       if (I2C_OP_READ_P(op))
+               err = ti_iic_op(sc, addr, TI_I2CREAD, buf, len, flags);
+       else
+               err = ti_iic_op(sc, addr, TI_I2CWRITE, buf, len, flags);
+
+done:
+       if (err)
+               ti_iic_reset(sc);
+
+       ti_iic_flush(sc);
+
+       DPRINTF(("ti_iic_exec: done %d\n", err));
+       return err;
+}
+
+static int
+ti_iic_reset(struct ti_iic_softc *sc)
+{
+       uint32_t psc, scll, sclh;
+       int i;
+
+       DPRINTF(("ti_iic_reset\n"));
+
+       /* Disable */
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
+       /* Soft reset */
+       I2C_WRITE_REG(sc, AM335X_I2C_SYSC, I2C_SYSC_SRST);
+       delay(1000);
+       /* enable so that we can check for reset complete */
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, I2C_CON_EN);
+       delay(1000);
+       for (i = 0; i < 1000; i++) { /* 1s delay for reset */
+               if (I2C_READ_REG(sc, AM335X_I2C_SYSS) & I2C_SYSS_RDONE)
+                       break;
+       }
+       /* Disable again */
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
+       delay(50000);
+
+       if (i >= 1000) {
+               printf("%s: couldn't reset module\n", DEVNAME(sc));
+               return 1;
+       }
+
+       /* XXX standard speed only */
+       psc = 3;
+       scll = 53;
+       sclh = 55;
+
+       /* Clocks */
+       I2C_WRITE_REG(sc, AM335X_I2C_PSC, psc);
+       I2C_WRITE_REG(sc, AM335X_I2C_SCLL, scll);
+       I2C_WRITE_REG(sc, AM335X_I2C_SCLH, sclh);
+
+       /* Own I2C address */
+       I2C_WRITE_REG(sc, AM335X_I2C_OA, AM335X_I2C_SLAVE_ADDR);
+
+       /* 5 bytes fifo */
+       I2C_WRITE_REG(sc, AM335X_I2C_BUF,
+           I2C_BUF_RXTRSH(sc->sc_rxthres) | I2C_BUF_TXTRSH(sc->sc_txthres));
+
+       /* Enable */
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, I2C_CON_EN);
+
+       return 0;
+}
+
+static int
+ti_iic_op(struct ti_iic_softc *sc, i2c_addr_t addr, ti_i2cop_t op,
+    uint8_t *buf, size_t buflen, int flags)
+{
+       uint16_t con, stat, mask;
+       int err, retry;
+
+       KASSERT(op == TI_I2CREAD || op == TI_I2CWRITE);
+       DPRINTF(("ti_iic_op: addr %#x op %#x buf %p buflen %#x flags %#x\n", 
+           addr, op, buf, (unsigned int) buflen, flags));
+
+       mask = I2C_IRQSTATUS_ARDY | I2C_IRQSTATUS_NACK | I2C_IRQSTATUS_AL;
+       if (op == TI_I2CREAD)
+               mask |= I2C_IRQSTATUS_RDR | I2C_IRQSTATUS_RRDY;
+       else
+               mask |= I2C_IRQSTATUS_XDR | I2C_IRQSTATUS_XRDY;
+
+       err = ti_iic_wait(sc, I2C_IRQSTATUS_BB, 0, flags);
+       if (err) {
+               DPRINTF(("ti_iic_op: wait error %d\n", err));
+               return err;
+       }
+
+       con = I2C_CON_EN;
+       con |= I2C_CON_MST;
+       con |= I2C_CON_STT;
+       if (flags & I2C_F_STOP)
+               con |= I2C_CON_STP;
+       if (addr & ~0x7f)
+               con |= I2C_CON_XSA;
+       if (op == TI_I2CWRITE)
+               con |= I2C_CON_TRX;
+
+       sc->sc_op = op;
+       sc->sc_buf = buf;
+       sc->sc_buflen = buflen;
+       sc->sc_bufidx = 0;
+
+       I2C_WRITE_REG(sc,
+           AM335X_I2C_CON, I2C_CON_EN | I2C_CON_MST | I2C_CON_STP);
+       DPRINTF(("ti_iic_op: op %d con 0x%x ", op, con));
+       I2C_WRITE_REG(sc, AM335X_I2C_CNT, buflen);
+       I2C_WRITE_REG(sc, AM335X_I2C_SA, (addr & I2C_SA_MASK));
+       DPRINTF(("SA 0x%x len %d\n",
+           I2C_READ_REG(sc, AM335X_I2C_SA), I2C_READ_REG(sc, AM335X_I2C_CNT)));
+
+       if ((flags & I2C_F_POLL) == 0) {
+               /* clear any pending interrupt */
+               I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS,
+                   I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS));
+               /* and enable */
+               I2C_WRITE_REG(sc, AM335X_I2C_IRQENABLE_SET, mask);
+       }
+       /* start transfer */
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, con);
+
+       if ((flags & I2C_F_POLL) == 0) {
+               /* and wait for completion */
+               DPRINTF(("ti_iic_op waiting, op %#x\n", sc->sc_op));
+               while (sc->sc_op == op) {
+                       if (tsleep(&sc->sc_dev, PWAIT, "tiiic", 500)
+                           == EWOULDBLOCK) {
+                               /* timeout */
+                               op = TI_I2CERROR;
+                       }
+               }
+               DPRINTF(("ti_iic_op waiting done, op %#x\n", sc->sc_op));
+
+               /* disable interrupts */
+               I2C_WRITE_REG(sc, AM335X_I2C_IRQENABLE_CLR, 0xffff);
+       } else {
+               /* poll for completion */
+               DPRINTF(("ti_iic_op polling, op %x\n", sc->sc_op));
+               while (sc->sc_op == op) {
+                       stat = ti_iic_stat(sc, mask);
+                       DPRINTF(("ti_iic_op stat 0x%x\n", stat));
+                       if (stat == 0) /* timeout */
+                               sc->sc_op = TI_I2CERROR;
+                       else
+                               ti_iic_handle_intr(sc, stat);
+                       I2C_WRITE_REG(sc, AM335X_I2C_IRQSTATUS, stat);
+               }
+               DPRINTF(("ti_iic_op polling done, op now %x\n", sc->sc_op));
+       }
+       retry = 10000;
+       I2C_WRITE_REG(sc, AM335X_I2C_CON, 0);
+       while (I2C_READ_REG(sc, AM335X_I2C_CON) & I2C_CON_MST) {
+               delay(100);
+               if (--retry == 0)
+                       break;
+       }
+
+       return (sc->sc_op == TI_I2CDONE) ? 0 : EIO;
+}
+
+static void
+ti_iic_handle_intr(struct ti_iic_softc *sc, uint32_t stat)
+{
+       KASSERT(stat != 0);
+       DPRINTF(("ti_iic_handle_intr stat %#x\n", stat));
+
+       if (stat & (I2C_IRQSTATUS_NACK|I2C_IRQSTATUS_AL)) {
+               sc->sc_op = TI_I2CERROR;
+               return;
+       }
+       if (stat & I2C_IRQSTATUS_ARDY) {
+               sc->sc_op = TI_I2CDONE;
+               return;
+       }
+       if (sc->sc_op == TI_I2CREAD)
+               ti_iic_do_read(sc, stat);
+       else if (sc->sc_op == TI_I2CWRITE)
+               ti_iic_do_write(sc, stat);
+       else
+               return;
+}
+void
+ti_iic_do_read(struct ti_iic_softc *sc, uint32_t stat)
+{
+       int len = 0;
+
+       DPRINTF(("ti_iic_do_read stat %#x\n", stat));
+       if (stat & I2C_IRQSTATUS_RDR) {
+               len = I2C_READ_REG(sc, AM335X_I2C_BUFSTAT);
+               len = I2C_BUFSTAT_RXSTAT(len);
+               DPRINTF(("ti_iic_do_read receive drain len %d left %d\n",
+                   len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
+       } else if (stat & I2C_IRQSTATUS_RRDY) {
+               len = sc->sc_rxthres + 1;
+               DPRINTF(("ti_iic_do_read receive len %d left %d\n",
+                   len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
+       }
+       for (;
+           sc->sc_bufidx < sc->sc_buflen && len > 0;
+           sc->sc_bufidx++, len--) {
+               sc->sc_buf[sc->sc_bufidx] = I2C_READ_DATA(sc);
+               DPRINTF(("ti_iic_do_read got b[%d]=0x%x\n", sc->sc_bufidx,
+                   sc->sc_buf[sc->sc_bufidx]));
+       }
+       DPRINTF(("ti_iic_do_read done\n"));
+}
+
+void
+ti_iic_do_write(struct ti_iic_softc *sc, uint32_t stat)
+{
+       int len = 0;
+
+       DPRINTF(("ti_iic_do_write stat %#x\n", stat));
+
+       if (stat & I2C_IRQSTATUS_XDR) {
+               len = I2C_READ_REG(sc, AM335X_I2C_BUFSTAT);
+               len = I2C_BUFSTAT_TXSTAT(len);
+               DPRINTF(("ti_iic_do_write xmit drain len %d left %d\n",
+                   len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
+       } else if (stat & I2C_IRQSTATUS_XRDY) {
+               len = sc->sc_txthres + 1;
+               DPRINTF(("ti_iic_do_write xmit len %d left %d\n",
+                   len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
+       }
+       for (;
+           sc->sc_bufidx < sc->sc_buflen && len > 0;
+           sc->sc_bufidx++, len--) {
+               DPRINTF(("ti_iic_do_write send b[%d]=0x%x\n",
+                   sc->sc_bufidx, sc->sc_buf[sc->sc_bufidx]));
+               I2C_WRITE_DATA(sc, sc->sc_buf[sc->sc_bufidx]);
+       }
+       DPRINTF(("ti_iic_do_write done\n"));
+}
+
+static int
+ti_iic_wait(struct ti_iic_softc *sc, uint16_t mask, uint16_t val, int flags)
+{
+       int retry = 10;
+       uint16_t v;
+       DPRINTF(("ti_iic_wait mask %#x val %#x flags %#x\n", mask, val, flags));
+
+       while (((v = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW)) & mask) != val) {
+               --retry;
+               if (retry == 0) {
+                       printf("%s: wait timeout, mask=%#x val=%#x stat=%#x\n",
+                           DEVNAME(sc), mask, val, v);
+                       return EBUSY;
+               }
+               if (flags & I2C_F_POLL)
+                       delay(50000);
+               else
+                       tsleep(&sc->sc_dev, PWAIT, "tiiic", 50);
+       }
+       DPRINTF(("ti_iic_wait done retry %#x\n", retry));
+
+       return 0;
+}
+
+static uint32_t
+ti_iic_stat(struct ti_iic_softc *sc, uint32_t mask)
+{
+       uint32_t v;
+       int retry = 500;
+       DPRINTF(("ti_iic_wait mask %#x\n", mask));
+       while (--retry > 0) {
+               v = I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW) & mask;
+               if (v != 0)
+                       break;
+               delay(100);
+       }
+       DPRINTF(("ti_iic_wait done retry %#x\n", retry));
+       return v;
+}
+
+static int
+ti_iic_flush(struct ti_iic_softc *sc)
+{
+       DPRINTF(("ti_iic_flush\n"));
+#if 0
+       int retry = 1000;
+       uint16_t v;
+
+       while ((v =
+           I2C_READ_REG(sc, AM335X_I2C_IRQSTATUS_RAW)) & I2C_IRQSTATUS_RRDY) {
+               if (--retry == 0) {
+                       printf("%s: flush timeout, stat = %#x\n", DEVNAME(sc), v);
+                       return EBUSY;
+               }
+               (void)I2C_READ_DATA(sc);
+               delay(1000);
+       }
+#endif
+
+       I2C_WRITE_REG(sc, AM335X_I2C_CNT, 0);
+       return 0;
+}
diff --git a/ti_iicreg.h b/ti_iicreg.h
new file mode 100644 (file)
index 0000000..4de67a6
--- /dev/null
@@ -0,0 +1,136 @@
+/*     $OpenBSD: ti_iicreg.h,v 1.1 2013/11/24 15:00:22 rapha Exp $     */
+/*     $NetBSD: ti_iicreg.h,v 1.1 2013/04/17 14:33:06 bouyer Exp $     */
+
+/*
+ * Copyright (c) 2013 Manuel Bouyer.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* register definitions for the i2c controller found in the
+ * Texas Instrument AM335x SOC
+ */
+
+#ifndef _AM335XIICREG_H
+#define _AM335XIICREG_H
+
+#define AM335X_I2C_REVNB_LO            0x00
+#define                I2C_REVNB_LO_RTL(x)             (((x) >> 11) & 0x01f)
+#define                I2C_REVNB_LO_MAJOR(x)           (((x) >>  8) & 0x007)
+#define                I2C_REVNB_LO_CUSTOM(x)          (((x) >>  6) & 0x003)
+#define                I2C_REVNB_LO_MINOR(x)           (((x) >>  0) & 0x01f)
+#define AM335X_I2C_REVNB_HI            0x04
+#define                I2C_REVNB_HI_SCHEME(x)          (((x) >> 14) & 0x003)
+#define                I2C_REVNB_HI_FUNC(x)            (((x) >>  0) & 0xfff)
+#define AM335X_I2C_SYSC                        0x10
+#define                I2C_SYSC_CLKACTIVITY_OCP        0x0010
+#define                I2C_SYSC_CLKACTIVITY_SYSTEM     0x0020
+#define                I2C_SYSC_IDLE_MASK              0x0018
+#define                I2C_SYSC_IDLE_FORCE             0x0000
+#define                I2C_SYSC_IDLE_SMART             0x0010
+#define                I2C_SYSC_IDLE_NONE              0x0008
+#define                I2C_SYSC_ENAWAKEUP              0x0004
+#define                I2C_SYSC_SRST                   0x0002
+#define                I2C_SYSC_AUTOIDLE               0x0001
+#define AM335X_I2C_IRQSTATUS_RAW               0x24
+#define AM335X_I2C_IRQSTATUS           0x28
+#define AM335X_I2C_IRQENABLE_SET               0x2C
+#define AM335X_I2C_IRQENABLE_CLR               0x30
+#define AM335X_I2C_WE                  0x34
+#define                I2C_IRQSTATUS_XDR               0x4000
+#define                I2C_IRQSTATUS_RDR               0x2000
+#define                I2C_IRQSTATUS_BB                0x1000
+#define                I2C_IRQSTATUS_ROVR              0x0800
+#define                I2C_IRQSTATUS_XUDF              0x0400
+#define                I2C_IRQSTATUS_AAS               0x0200
+#define                I2C_IRQSTATUS_BF                0x0100
+#define                I2C_IRQSTATUS_AERR              0x0080
+#define                I2C_IRQSTATUS_STC               0x0040
+#define                I2C_IRQSTATUS_GC                0x0020
+#define                I2C_IRQSTATUS_XRDY              0x0010
+#define                I2C_IRQSTATUS_RRDY              0x0008
+#define                I2C_IRQSTATUS_ARDY              0x0004
+#define                I2C_IRQSTATUS_NACK              0x0002
+#define                I2C_IRQSTATUS_AL                0x0001
+#define AM335X_I2C_DMARXENABLE_SET     0x38
+#define AM335X_I2C_DMATXENABLE_SET     0x3C
+#define AM335X_I2C_DMARXENABLE_CLR     0x40
+#define                I2C_DMARXENABLE                 0x0001
+#define AM335X_I2C_DMATXENABLE_CLR     0x44
+#define                I2C_DMATXENABLE                 0x0001
+#define AM335X_I2C_DMARXWAKE_EN                0x48
+       /* use same bits as IRQ */
+#define AM335X_I2C_DMATXWAKE_EN                0x4C
+       /* use same bits as IRQ */
+#define AM335X_I2C_SYSS                        0x90
+#define                I2C_SYSS_RDONE                  0x0001
+#define AM335X_I2C_BUF                 0x94
+#define                I2C_BUF_RDMA_EN                 0x8000
+#define                I2C_BUF_RXFIFO_CLR              0x4000
+#define                I2C_BUF_RXTRSH_MASK             0x3f00
+#define                I2C_BUF_RXTRSH(x)               ((x) << 8)
+#define                I2C_BUF_XDMA_EN                 0x0080
+#define                I2C_BUF_TXFIFO_CLR              0x0040
+#define                I2C_BUF_TXTRSH_MASK             0x003f
+#define                I2C_BUF_TXTRSH(x)               ((x) << 0)
+#define AM335X_I2C_CNT                 0x98
+#define                I2C_CNT_MASK                    0xffff
+#define AM335X_I2C_DATA                        0x9C
+#define                I2C_DATA_MASK                   0x00ff
+#define AM335X_I2C_CON                 0xA4
+#define                I2C_CON_EN                      0x8000
+#define                I2C_CON_STB                     0x0800
+#define                I2C_CON_MST                     0x0400
+#define                I2C_CON_TRX                     0x0200
+#define                I2C_CON_XSA                     0x0100
+#define                I2C_CON_XOA0                    0x0080
+#define                I2C_CON_XOA1                    0x0040
+#define                I2C_CON_XOA2                    0x0020
+#define                I2C_CON_XOA3                    0x0010
+#define                I2C_CON_STP                     0x0002
+#define                I2C_CON_STT                     0x0001
+#define AM335X_I2C_OA                  0xA8
+#define                I2C_OA_MASK                     0x03ff
+#define AM335X_I2C_SA                  0xAC
+#define                I2C_SA_MASK                     0x03ff
+#define AM335X_I2C_PSC                 0xB0
+#define                I2C_PSC_MASK                    0x000f
+#define AM335X_I2C_SCLL                        0xB4
+#define                I2C_SCLL_MASK                   0x000f
+#define AM335X_I2C_SCLH                        0xB8
+#define                I2C_SCLH_MASK                   0x000f
+#define AM335X_I2C_SYSTEST             0xBC
+#define AM335X_I2C_BUFSTAT             0xC0
+#define                I2C_BUFSTAT_FIFODEPTH(x)        (((x) >> 14) & 0x03)
+#define                I2C_BUFSTAT_RXSTAT(x)           (((x) >>  8) & 0x3f)
+#define                I2C_BUFSTAT_TXSTAT(x)           (((x) >>  0) & 0x3f)
+#define AM335X_I2C_OA1                 0xC4
+#define AM335X_I2C_OA2                 0xC8
+#define AM335X_I2C_OA3                 0xCC
+       /* same bits as I2C_OA */
+#define AM335X_I2C_ACTOA                       0xD0
+#define AM335X_I2C_SBLOCK              0xD4
+#define                I2C_ACTOA_OA3_ACT               0x0008
+#define                I2C_ACTOA_OA2_ACT               0x0004
+#define                I2C_ACTOA_OA1_ACT               0x0002
+#define                I2C_ACTOA_OA0_ACT               0x0001
+
+#endif /* _AM335XIICREG_H */