summaryrefslogtreecommitdiff
path: root/sys/arch/armv7/omap
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2013-09-04 14:38:50 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2013-09-04 14:38:50 +0000
commit6bbb01e146782eed471c94cbe2563ae8b59d1b8b (patch)
tree367a031eac776c18fc2f1d73bf86cb60576272b1 /sys/arch/armv7/omap
parentd33bef10c2430729f5df07f3a6eca73a8f3f5d1f (diff)
In the future, we shouldn't have one port port ARM SoC, that's just
ridiculous. This is the first step for a common and generic ARM port for ARMv7 SoCs.
Diffstat (limited to 'sys/arch/armv7/omap')
-rw-r--r--sys/arch/armv7/omap/am335x.c180
-rw-r--r--sys/arch/armv7/omap/am335x_cm_padconf.c350
-rw-r--r--sys/arch/armv7/omap/am335x_prcmreg.h48
-rw-r--r--sys/arch/armv7/omap/beagle_machdep.c1024
-rw-r--r--sys/arch/armv7/omap/dmtimer.c414
-rw-r--r--sys/arch/armv7/omap/gptimer.c441
-rw-r--r--sys/arch/armv7/omap/if_cpsw.c1264
-rw-r--r--sys/arch/armv7/omap/if_cpswreg.h139
-rw-r--r--sys/arch/armv7/omap/intc.c423
-rw-r--r--sys/arch/armv7/omap/intc.h74
-rw-r--r--sys/arch/armv7/omap/omap.c232
-rw-r--r--sys/arch/armv7/omap/omap3.c196
-rw-r--r--sys/arch/armv7/omap/omap3_prcmreg.h197
-rw-r--r--sys/arch/armv7/omap/omap4.c200
-rw-r--r--sys/arch/armv7/omap/omap4_prcmreg.h27
-rw-r--r--sys/arch/armv7/omap/omap_com.c112
-rw-r--r--sys/arch/armv7/omap/omapid.c101
-rw-r--r--sys/arch/armv7/omap/omapvar.h58
-rw-r--r--sys/arch/armv7/omap/omdisplay.c1370
-rw-r--r--sys/arch/armv7/omap/omdog.c113
-rw-r--r--sys/arch/armv7/omap/omehci.c487
-rw-r--r--sys/arch/armv7/omap/omehcivar.h232
-rw-r--r--sys/arch/armv7/omap/omgpio.c641
-rw-r--r--sys/arch/armv7/omap/omgpiovar.h40
-rw-r--r--sys/arch/armv7/omap/ommmc.c1232
-rw-r--r--sys/arch/armv7/omap/omohci.c353
-rw-r--r--sys/arch/armv7/omap/omusbtll.c175
-rw-r--r--sys/arch/armv7/omap/prcm.c482
-rw-r--r--sys/arch/armv7/omap/prcmvar.h42
-rw-r--r--sys/arch/armv7/omap/sitara_cm.c394
-rw-r--r--sys/arch/armv7/omap/sitara_cm.h78
-rw-r--r--sys/arch/armv7/omap/sitara_cmreg.h46
32 files changed, 11165 insertions, 0 deletions
diff --git a/sys/arch/armv7/omap/am335x.c b/sys/arch/armv7/omap/am335x.c
new file mode 100644
index 00000000000..4ab39623c1d
--- /dev/null
+++ b/sys/arch/armv7/omap/am335x.c
@@ -0,0 +1,180 @@
+/* $OpenBSD: am335x.c,v 1.1 2013/09/04 14:38:29 patrick 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/omap/omapvar.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 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 0x300
+#define HSMMC0_ADDR 0x48060000
+#define HSMMC0_IRQ 64
+
+#define CPSW_SIZE 0x4000
+#define CPSW_ADDR 0x4A100000
+#define CPSW_IRQ 40
+
+struct omap_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 } },
+ },
+
+ /*
+ * 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 }
+ },
+
+ /*
+ * MMC
+ */
+
+ { .name = "ommmc",
+ .unit = 0,
+ .mem = { { HSMMC0_ADDR, HSMMCx_SIZE } },
+ .irq = { HSMMC0_IRQ }
+ },
+
+ /* cpsw Ethernet */
+ { .name = "cpsw",
+ .unit = 0,
+ .mem = { { CPSW_ADDR, CPSW_SIZE } },
+ .irq = { CPSW_IRQ }
+ },
+
+ /* Terminator */
+ { .name = NULL,
+ .unit = 0
+ }
+};
+
+void
+am335x_init(void)
+{
+ omap_set_devs(am335x_devs);
+}
diff --git a/sys/arch/armv7/omap/am335x_cm_padconf.c b/sys/arch/armv7/omap/am335x_cm_padconf.c
new file mode 100644
index 00000000000..3723b99165c
--- /dev/null
+++ b/sys/arch/armv7/omap/am335x_cm_padconf.c
@@ -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/sys/arch/armv7/omap/am335x_prcmreg.h b/sys/arch/armv7/omap/am335x_prcmreg.h
new file mode 100644
index 00000000000..f7077423c15
--- /dev/null
+++ b/sys/arch/armv7/omap/am335x_prcmreg.h
@@ -0,0 +1,48 @@
+/* $OpenBSD: am335x_prcmreg.h,v 1.1 2013/09/04 14:38:30 patrick 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_MMC0_CLKCTRL 0x003c
+#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_CM_WKUP 0x0400
+#define PRCM_AM335X_GPIO0_CLKCTRL 0x0408
+#define PRCM_AM335X_TIMER0_CLKCTRL 0x0410
+#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/sys/arch/armv7/omap/beagle_machdep.c b/sys/arch/armv7/omap/beagle_machdep.c
new file mode 100644
index 00000000000..a48d1a62c90
--- /dev/null
+++ b/sys/arch/armv7/omap/beagle_machdep.c
@@ -0,0 +1,1024 @@
+/* $OpenBSD: beagle_machdep.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */
+/* $NetBSD: lubbock_machdep.c,v 1.2 2003/07/15 00:25:06 lukem Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * 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 Genetec Corporation may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION
+ * 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.
+ *
+ * Machine dependant functions for kernel setup for
+ * Intel DBPXA250 evaluation board (a.k.a. Lubbock).
+ * Based on iq80310_machhdep.c
+ */
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited.
+ * 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 Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Machine dependant functions for kernel setup for Intel IQ80310 evaluation
+ * boards using RedBoot firmware.
+ */
+
+/*
+ * DIP switches:
+ *
+ * S19: no-dot: set RB_KDB. enter kgdb session.
+ * S20: no-dot: set RB_SINGLE. don't go multi user mode.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/exec.h>
+#include <sys/proc.h>
+#include <sys/msgbuf.h>
+#include <sys/reboot.h>
+#include <sys/termios.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <dev/cons.h>
+#include <dev/ic/smc91cxxreg.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_extern.h>
+
+#include <machine/bootconfig.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <arm/undefined.h>
+#include <arm/machdep.h>
+
+#include <arm/armv7/armv7reg.h>
+#include <arm/armv7/armv7var.h>
+
+#include <arm/cortex/smc.h>
+#include <machine/machine_reg.h>
+#include <armv7/omap/omapvar.h>
+
+#include "wsdisplay.h"
+
+/* Kernel text starts 2MB in from the bottom of the kernel address space. */
+#define KERNEL_TEXT_BASE (KERNEL_BASE + 0x00000000)
+#define KERNEL_VM_BASE (KERNEL_BASE + 0x04000000)
+
+/*
+ * The range 0xc1000000 - 0xccffffff is available for kernel VM space
+ * Core-logic registers and I/O mappings occupy 0xfd000000 - 0xffffffff
+ */
+/*
+#define KERNEL_VM_SIZE 0x0C000000
+*/
+#define KERNEL_VM_SIZE 0x10000000
+
+
+/*
+ * Address to call from cpu_reset() to reset the machine.
+ * This is machine architecture dependant as it varies depending
+ * on where the ROM appears when you turn the MMU off.
+ */
+
+u_int cpu_reset_address = 0;
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE 1
+#define ABT_STACK_SIZE 1
+#ifdef IPKDB
+#define UND_STACK_SIZE 2
+#else
+#define UND_STACK_SIZE 1
+#endif
+
+BootConfig bootconfig; /* Boot config storage */
+char *boot_args = NULL;
+char *boot_file = "";
+
+vaddr_t physical_start;
+vaddr_t physical_freestart;
+vaddr_t physical_freeend;
+vaddr_t physical_end;
+u_int free_pages;
+vaddr_t pagetables_start;
+int physmem = 0;
+
+/*int debug_flags;*/
+#ifndef PMAP_STATIC_L1S
+int max_processes = 64; /* Default number */
+#endif /* !PMAP_STATIC_L1S */
+
+/* Physical and virtual addresses for some global pages */
+pv_addr_t systempage;
+pv_addr_t irqstack;
+pv_addr_t undstack;
+pv_addr_t abtstack;
+extern pv_addr_t kernelstack;
+pv_addr_t minidataclean;
+
+vaddr_t msgbufphys;
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+#ifdef PMAP_DEBUG
+extern int pmap_debug_level;
+#endif
+
+uint32_t board_id;
+
+#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */
+#define KERNEL_PT_KERNEL_NUM 32
+#define KERNEL_PT_VMDATA (KERNEL_PT_KERNEL+KERNEL_PT_KERNEL_NUM)
+ /* Page tables for mapping kernel VM */
+#define KERNEL_PT_VMDATA_NUM 8 /* start with 16MB of KVM */
+#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM)
+
+pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
+
+extern struct user *proc0paddr;
+
+/*
+ * safepri is a safe priority for sleep to set for a spin-wait
+ * during autoconfiguration or after a panic.
+ */
+int safepri = 0;
+
+/* Prototypes */
+
+void omdog_reset(void);
+void beagle_powerdown(void);
+
+char bootargs[MAX_BOOT_STRING];
+void process_kernel_args(char *);
+
+void consinit(void);
+void early_clkman(u_int, int);
+void kgdb_port_init(void);
+void change_clock(uint32_t v);
+
+bs_protos(bs_notimpl);
+
+#include "com.h"
+#if NCOM > 0
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#endif
+
+#ifndef CONSPEED
+#define CONSPEED B115200 /* What u-boot */
+#endif
+#ifndef CONMODE
+#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
+#endif
+
+int comcnspeed = CONSPEED;
+int comcnmode = CONMODE;
+
+/*
+ *
+ */
+void
+beagle_powerdown(void)
+{
+
+ /*
+ pxa2x0_watchdog_boot();
+ */
+}
+
+/*
+ * void boot(int howto, char *bootstr)
+ *
+ * Reboots the system
+ *
+ * Deal with any syncing, unmounting, dumping and shutdown hooks,
+ * then reset the CPU.
+ */
+void
+boot(int howto)
+{
+#ifdef DIAGNOSTIC
+ /* info */
+ printf("boot: howto=%08x curproc=%p\n", howto, curproc);
+#endif
+
+ /*
+ * If we are still cold then hit the air brakes
+ * and crash to earth fast
+ */
+ if (cold) {
+ doshutdownhooks();
+ if ((howto & (RB_HALT | RB_USERREQ)) != RB_USERREQ) {
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+ printf("rebooting...\n");
+ delay(500000);
+ omdog_reset();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+ }
+
+ /* Disable console buffering */
+/* cnpollc(1);*/
+
+ /*
+ * If RB_NOSYNC was not specified sync the discs.
+ * Note: Unless cold is set to 1 here, syslogd will die during the
+ * unmount. It looks like syslogd is getting woken up only to find
+ * that it cannot page part of the binary in as the filesystem has
+ * been unmounted.
+ */
+ if (!(howto & RB_NOSYNC))
+ bootsync(howto);
+
+ /* Say NO to interrupts */
+ splhigh();
+
+ /* Do a dump if requested. */
+ if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
+ dumpsys();
+
+ /* Run any shutdown hooks */
+ doshutdownhooks();
+
+ /* Make sure IRQ's are disabled */
+ IRQdisable;
+
+ if (howto & RB_HALT) {
+ if (howto & RB_POWERDOWN) {
+
+ printf("\nAttempting to power down...\n");
+ delay(500000);
+ beagle_powerdown();
+ }
+
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+
+ printf("rebooting...\n");
+ delay(500000);
+ omdog_reset();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+}
+
+static __inline
+pd_entry_t *
+read_ttb(void)
+{
+ long ttb;
+
+ __asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r" (ttb));
+
+
+ return (pd_entry_t *)(ttb & ~((1<<14)-1));
+}
+
+#if 1
+#define VERBOSE_INIT_ARM
+#endif
+
+/*
+ * simple memory mapping function used in early bootstrap stage
+ * before pmap is initialized.
+ * size and cacheability are ignored and map one section with nocache.
+ */
+static vaddr_t section_free = 0xfd000000; /* XXX - huh */
+
+int bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp);
+int
+bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ u_long startpa;
+ vaddr_t va;
+ pd_entry_t *pagedir = read_ttb();
+ /* This assumes PA==VA for page directory */
+
+ va = section_free;
+ section_free += L1_S_SIZE;
+
+ /*
+ startpa = trunc_page(bpa);
+ */
+ startpa = bpa & ~L1_S_OFFSET;
+ pmap_map_section((vaddr_t)pagedir, va, startpa,
+ VM_PROT_READ | VM_PROT_WRITE, PTE_NOCACHE);
+ cpu_tlb_flushD();
+
+ *bshp = (bus_space_handle_t)(va + (bpa - startpa));
+
+ return(0);
+}
+
+static void
+copy_io_area_map(pd_entry_t *new_pd)
+{
+ pd_entry_t *cur_pd = read_ttb();
+ vaddr_t va;
+
+ for (va = MACHINE_IO_AREA_VBASE;
+ (cur_pd[va>>L1_S_SHIFT] & L1_TYPE_MASK) == L1_TYPE_S;
+ va += L1_S_SIZE) {
+
+ new_pd[va>>L1_S_SHIFT] = cur_pd[va>>L1_S_SHIFT];
+ if (va == (ARM_VECTORS_HIGH & ~(0x00400000 - 1)))
+ break; /* STUPID */
+
+ }
+}
+
+void parse_uboot_tags(void *);
+
+/*
+ * u_int initarm(...)
+ *
+ * Initial entry point on startup. This gets called before main() is
+ * entered.
+ * It should be responsible for setting up everything that must be
+ * in place when main is called.
+ * This includes
+ * Taking a copy of the boot configuration structure.
+ * Initialising the physical console so characters can be printed.
+ * Setting up page tables for the kernel
+ * Relocating the kernel to the bottom of physical memory
+ */
+u_int
+initarm(void *arg0, void *arg1, void *arg2)
+{
+ int loop;
+ int loop1;
+ u_int l1pagetable;
+ pv_addr_t kernel_l1pt;
+ paddr_t memstart;
+ psize_t memsize;
+ extern void omap4_smc_call(uint32_t, uint32_t);
+
+#if 0
+ int led_data = 0;
+#endif
+ /* early bus_space_map support */
+ struct bus_space tmp_bs_tag;
+ int (*map_func_save)(void *, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+
+ board_id = (uint32_t)arg1;
+
+ /*
+ * Heads up ... Setup the CPU / MMU / TLB functions
+ */
+ if (set_cpufuncs())
+ panic("cpu not recognized!");
+
+ switch (board_id) {
+ case BOARD_ID_OMAP4_PANDA:
+ /* disable external L2 cache */
+ omap4_smc_call(0x102, 0);
+ break;
+ }
+
+#if 0
+ /* Calibrate the delay loop. */
+#endif
+
+ /*
+ * Temporarily replace bus_space_map() functions so that
+ * console devices can get mapped.
+ *
+ * Note that this relies upon the fact that both regular
+ * and a4x bus_space tags use the same map function.
+ */
+#if defined(CPU_ARMv7)
+ tmp_bs_tag = armv7_bs_tag;
+ map_func_save = armv7_bs_tag.bs_map;
+ armv7_bs_tag.bs_map = bootstrap_bs_map;
+ armv7_a4x_bs_tag.bs_map = bootstrap_bs_map;
+#endif
+ tmp_bs_tag.bs_map = bootstrap_bs_map;
+
+ /* setup a serial console for very early boot */
+ consinit();
+
+ /* Talk to the user */
+ printf("\nOpenBSD/beagle booting ...\n");
+
+ printf("arg0 %p arg1 %p arg2 %p\n", arg0, arg1, arg2);
+ parse_uboot_tags(arg2);
+
+ /*
+ * Examine the boot args string for options we need to know about
+ * now.
+ */
+ process_kernel_args(bootconfig.bootstring);
+#ifdef RAMDISK_HOOKS
+ boothowto |= RB_DFLTROOT;
+#endif /* RAMDISK_HOOKS */
+
+
+ /* normally u-boot will set up bootconfig.dramblocks */
+ if (bootconfig.dramblocks == 0) {
+ uint32_t sdrc_mcfg_0, sdrc_mcfg_1, memsize0, memsize1;
+ sdrc_mcfg_0 = *(uint32_t *)0x6d000080;
+ sdrc_mcfg_1 = *(uint32_t *)0x6d0000b0;
+ memsize0 = (((sdrc_mcfg_0 >> 8))&0x3ff) * (2 * 1024 * 1024);
+ memsize1 = (((sdrc_mcfg_1 >> 8))&0x3ff) * (2 * 1024 * 1024);
+ memsize = memsize0 + memsize1;
+
+ memstart = SDRAM_START;
+ memsize = 0x02000000; /* 32MB */
+ /* Fake bootconfig structure for the benefit of pmap.c */
+ /* XXX must make the memory description h/w independant */
+ bootconfig.dram[0].address = memstart;
+ bootconfig.dram[0].pages = memsize0 / PAGE_SIZE;
+ bootconfig.dramblocks = 1;
+ if (memsize1 != 0) {
+ bootconfig.dram[1].address = bootconfig.dram[0].address
+ + memsize0; /* XXX */
+ bootconfig.dram[1].pages = memsize1 / PAGE_SIZE;
+ bootconfig.dramblocks++; /* both banks populated */
+ }
+ } else {
+ /* doesn't deal with multiple segments, hopefully u-boot collaped them into one */
+ memstart = bootconfig.dram[0].address;
+ memsize = bootconfig.dram[0].pages * PAGE_SIZE;
+ printf("memory size derived from u-boot\n");
+ for (loop = 0; loop < bootconfig.dramblocks; loop++) {
+ printf("bootconf.mem[%d].address = %08x pages %d/0x%08x\n",
+ loop, bootconfig.dram[0].address, bootconfig.dram[0].pages,
+ bootconfig.dram[0].pages * PAGE_SIZE);
+ }
+ }
+
+ /*
+ * Set up the variables that define the availablilty of
+ * physical memory. For now, we're going to set
+ * physical_freestart to 0xa0200000 (where the kernel
+ * was loaded), and allocate the memory we need downwards.
+ * If we get too close to the page tables that RedBoot
+ * set up, we will panic. We will update physical_freestart
+ * and physical_freeend later to reflect what pmap_bootstrap()
+ * wants to see.
+ *
+ * XXX pmap_bootstrap() needs an enema.
+ */
+ physical_start = bootconfig.dram[0].address;
+ physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE);
+
+ {
+ extern char _end[];
+ physical_freestart = (((unsigned long)_end - KERNEL_TEXT_BASE +0xfff) & ~0xfff) + memstart;
+ physical_freeend = memstart+memsize;
+ }
+
+ physmem = (physical_end - physical_start) / PAGE_SIZE;
+
+#ifdef DEBUG
+ /* Tell the user about the memory */
+ printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem,
+ physical_start, physical_end - 1);
+#endif
+
+ /*
+ * Okay, the kernel starts 2MB in from the bottom of physical
+ * memory. We are going to allocate our bootstrap pages downwards
+ * from there.
+ *
+ * We need to allocate some fixed page tables to get the kernel
+ * going. We allocate one page directory and a number of page
+ * tables and store the physical addresses in the kernel_pt_table
+ * array.
+ *
+ * The kernel page directory must be on a 16K boundary. The page
+ * tables must be on 4K bounaries. What we do is allocate the
+ * page directory on the first 16K boundary that we encounter, and
+ * the page tables on 4K boundaries otherwise. Since we allocate
+ * at least 3 L2 page tables, we are guaranteed to encounter at
+ * least one 16K aligned region.
+ */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Allocating page tables\n");
+#endif
+
+ free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE;
+
+#ifdef VERBOSE_INIT_ARM
+ printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n",
+ physical_freestart, free_pages, free_pages);
+#endif
+
+ /* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np) \
+ alloc_pages((var).pv_pa, (np)); \
+ (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start;
+
+#define alloc_pages(var, np) \
+ (var) = physical_freestart ; \
+ physical_freestart += ((np) * PAGE_SIZE); \
+ if (physical_freeend < physical_freestart) \
+ panic("initarm: out of memory"); \
+ free_pages -= (np); \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ loop1 = 0;
+ kernel_l1pt.pv_pa = 0;
+ for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) {
+ /* Are we 16KB aligned for an L1 ? */
+ if (((physical_freestart) & (L1_TABLE_SIZE - 1)) == 0
+ && kernel_l1pt.pv_pa == 0) {
+ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+ } else {
+ valloc_pages(kernel_pt_table[loop1],
+ L2_TABLE_SIZE / PAGE_SIZE);
+ ++loop1;
+ }
+ }
+
+ /* This should never be able to happen but better confirm that. */
+ if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0)
+ panic("initarm: Failed to align the kernel page directory");
+
+ /*
+ * Allocate a page for the system page mapped to V0x00000000
+ * This page will just contain the system vectors and can be
+ * shared by all processes.
+ */
+ vector_page = ARM_VECTORS_HIGH;
+ alloc_pages(systempage.pv_pa, 1);
+ systempage.pv_va = vector_page;
+
+ /* Allocate stacks for all modes */
+ valloc_pages(irqstack, IRQ_STACK_SIZE);
+ valloc_pages(abtstack, ABT_STACK_SIZE);
+ valloc_pages(undstack, UND_STACK_SIZE);
+ valloc_pages(kernelstack, UPAGES);
+
+ /* Allocate enough pages for cleaning the Mini-Data cache. */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa,
+ irqstack.pv_va);
+ printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa,
+ abtstack.pv_va);
+ printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa,
+ undstack.pv_va);
+ printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa,
+ kernelstack.pv_va);
+#endif
+
+ /*
+ * XXX Defer this to later so that we can reclaim the memory
+ * XXX used by the RedBoot page tables.
+ */
+ alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE);
+
+ /*
+ * Ok we have allocated physical pages for the primary kernel
+ * page tables
+ */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa);
+#endif
+
+ /*
+ * Now we start construction of the L1 page table
+ * We start by mapping the L2 page tables into the L1.
+ * This means that we can replace L1 mappings later on if necessary
+ */
+ l1pagetable = kernel_l1pt.pv_pa;
+
+ /* Map the L2 pages tables in the L1 page table */
+ pmap_link_l2pt(l1pagetable, vector_page & ~(0x00400000 - 1),
+ &kernel_pt_table[KERNEL_PT_SYS]);
+
+ for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++)
+ pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000,
+ &kernel_pt_table[KERNEL_PT_KERNEL + loop]);
+
+ for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++)
+ pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000,
+ &kernel_pt_table[KERNEL_PT_VMDATA + loop]);
+
+ /* update the top of the kernel VM */
+ pmap_curmaxkvaddr =
+ KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000);
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Mapping kernel\n");
+#endif
+
+ /* Now we fill in the L2 pagetable for the kernel static code/data */
+ {
+ extern char etext[], _end[];
+ size_t textsize = (u_int32_t) etext - KERNEL_TEXT_BASE;
+ size_t totalsize = (u_int32_t) _end - KERNEL_TEXT_BASE;
+ u_int logical;
+
+ textsize = (textsize + PGOFSET) & ~PGOFSET;
+ totalsize = (totalsize + PGOFSET) & ~PGOFSET;
+
+ logical = 0x00000000; /* offset of kernel in RAM */
+
+ logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+ physical_start + logical, textsize,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+ logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+ physical_start + logical, totalsize - textsize,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ }
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Constructing L2 page tables\n");
+#endif
+
+ /* Map the stack pages */
+ pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+ IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
+ ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
+ UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
+ UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE);
+
+ pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+ L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE);
+
+ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+ pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
+ kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+ }
+
+ /* Map the Mini-Data cache clean area. */
+
+ /* Map the vector page. */
+#if 0
+ /* MULTI-ICE requires that page 0 is NC/NB so that it can download the
+ * cache-clean code there. */
+ pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_NOCACHE);
+#else
+ pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+#endif
+
+ /*
+ * map integrated peripherals at same address in l1pagetable
+ * so that we can continue to use console.
+ */
+ copy_io_area_map((pd_entry_t *)l1pagetable);
+
+
+ /*
+ * Now we have the real page tables in place so we can switch to them.
+ * Once this is done we will be running with the REAL kernel page
+ * tables.
+ */
+
+ /* be a client to all domains */
+ cpu_domains(0x55555555);
+ /* Switch tables */
+
+ cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+ setttb(kernel_l1pt.pv_pa);
+ cpu_tlb_flushID();
+ cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+
+ /*
+ * Moved from cpu_startup() as data_abort_handler() references
+ * this during uvm init
+ */
+ proc0paddr = (struct user *)kernelstack.pv_va;
+ proc0.p_addr = proc0paddr;
+
+ arm32_vector_init(vector_page, ARM_VEC_ALL);
+
+ /*
+ * Pages were allocated during the secondary bootstrap for the
+ * stacks for different CPU modes.
+ * We must now set the r13 registers in the different CPU modes to
+ * point to these stacks.
+ * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+ * of the stack memory.
+ */
+
+ set_stackptr(PSR_IRQ32_MODE,
+ irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_ABT32_MODE,
+ abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_UND32_MODE,
+ undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+ /*
+ * Well we should set a data abort handler.
+ * Once things get going this will change as we will need a proper
+ * handler.
+ * Until then we will use a handler that just panics but tells us
+ * why.
+ * Initialisation of the vectors will just panic on a data abort.
+ * This just fills in a slighly better one.
+ */
+
+ data_abort_handler_address = (u_int)data_abort_handler;
+ prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+ undefined_handler_address = (u_int)undefinedinstruction_bounce;
+
+ /* Initialise the undefined instruction handlers */
+#ifdef VERBOSE_INIT_ARM
+ printf("undefined ");
+#endif
+ undefined_init();
+
+ /* Load memory into UVM. */
+#ifdef VERBOSE_INIT_ARM
+ printf("page ");
+#endif
+ uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */
+ uvm_page_physload(atop(physical_freestart), atop(physical_freeend),
+ atop(physical_freestart), atop(physical_freeend), 0);
+
+ /* Boot strap pmap telling it where the kernel page table is */
+#ifdef VERBOSE_INIT_ARM
+ printf("pmap ");
+#endif
+ pmap_bootstrap((pd_entry_t *)kernel_l1pt.pv_va, KERNEL_VM_BASE,
+ KERNEL_VM_BASE + KERNEL_VM_SIZE);
+
+#ifdef IPKDB
+ /* Initialise ipkdb */
+ ipkdb_init();
+ if (boothowto & RB_KDB)
+ ipkdb_connect(0);
+#endif
+
+ /*
+ * Restore proper bus_space operation, now that pmap is initialized.
+ */
+#if defined(CPU_ARMv7)
+ armv7_bs_tag.bs_map = map_func_save;
+ armv7_a4x_bs_tag.bs_map = map_func_save;
+#endif
+
+#ifdef DDB
+ db_machine_init();
+
+ /* Firmware doesn't load symbols. */
+ ddb_init();
+
+ if (boothowto & RB_KDB)
+ Debugger();
+#endif
+
+ switch (board_id) {
+ case BOARD_ID_OMAP3_BEAGLE:
+ printf("board type: beagle\n");
+ break;
+ case BOARD_ID_AM335X_BEAGLEBONE:
+ printf("board type: beaglebone\n");
+ break;
+ case BOARD_ID_OMAP3_OVERO:
+ printf("board type: overo\n");
+ break;
+ case BOARD_ID_OMAP4_PANDA:
+ printf("board type: panda\n");
+ break;
+ default:
+ printf("board type %x unknown", board_id);
+ }
+
+ /* We return the new stack pointer address */
+ return(kernelstack.pv_va + USPACE_SVC_STACK_TOP);
+}
+
+
+void
+process_kernel_args(char *args)
+{
+ char *cp = args;
+
+ if (cp == NULL) {
+ boothowto = RB_AUTOBOOT;
+ return;
+ }
+
+ boothowto = 0;
+
+ /* Make a local copy of the bootargs */
+ strncpy(bootargs, cp, MAX_BOOT_STRING - sizeof(int));
+
+ cp = bootargs;
+ boot_file = bootargs;
+
+ /* Skip the kernel image filename */
+ while (*cp != ' ' && *cp != 0)
+ ++cp;
+
+ if (*cp != 0)
+ *cp++ = 0;
+
+ while (*cp == ' ')
+ ++cp;
+
+ boot_args = cp;
+
+ printf("bootfile: %s\n", boot_file);
+ printf("bootargs: %s\n", boot_args);
+
+ /* Setup pointer to boot flags */
+ while (*cp != '-')
+ if (*cp++ == '\0')
+ return;
+
+ for (;*++cp;) {
+ int fl;
+
+ fl = 0;
+ switch(*cp) {
+ case 'a':
+ fl |= RB_ASKNAME;
+ break;
+ case 'c':
+ fl |= RB_CONFIG;
+ break;
+ case 'd':
+ fl |= RB_KDB;
+ break;
+ case 's':
+ fl |= RB_SINGLE;
+ break;
+ default:
+ printf("unknown option `%c'\n", *cp);
+ break;
+ }
+ boothowto |= fl;
+ }
+}
+
+
+void
+consinit(void)
+{
+ static int consinit_called = 0;
+#if NCOM > 0
+ paddr_t paddr;
+#endif
+
+ if (consinit_called != 0)
+ return;
+
+ consinit_called = 1;
+
+#if NCOM > 0
+ switch (board_id) {
+ case BOARD_ID_OMAP3_BEAGLE:
+ case BOARD_ID_OMAP3_OVERO:
+ paddr = 0x49020000;
+ break;
+ case BOARD_ID_AM335X_BEAGLEBONE:
+ paddr = 0x44E09000; /* UART0 */
+ break;
+ case BOARD_ID_OMAP4_PANDA:
+ paddr = 0x48020000;
+ break;
+ default:
+ panic("board type %x unknown", board_id);
+ /* XXX - HELP */
+ }
+ comcnattach(&armv7_a4x_bs_tag, paddr, comcnspeed, 48000000, comcnmode);
+ comdefaultrate = comcnspeed;
+#endif /* NCOM */
+}
+
+
+//int glass_console = 0;
+
+void
+board_startup(void)
+{
+ if (boothowto & RB_CONFIG) {
+#ifdef BOOT_CONFIG
+ user_config();
+#else
+ printf("kernel does not support -c; continuing..\n");
+#endif
+ }
+}
+
+void
+platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
+ uint32_t op, uint32_t val)
+{
+ extern void omap4_smc_call(uint32_t, uint32_t);
+
+ 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);
+}
diff --git a/sys/arch/armv7/omap/dmtimer.c b/sys/arch/armv7/omap/dmtimer.c
new file mode 100644
index 00000000000..36c82c9dbd4
--- /dev/null
+++ b/sys/arch/armv7/omap/dmtimer.c
@@ -0,0 +1,414 @@
+/*
+ * 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/omap/omapvar.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 omap_attach_args *oa = args;
+ bus_space_handle_t ioh;
+ u_int32_t rev, cfg;
+
+ sc->sc_iot = oa->oa_iot;
+
+ if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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 = oa->oa_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%x",
+ oa->oa_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 ((now - sc->sc_nexttickevent) < (now - sc->sc_nextstatevent))
+ 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) {
+ printf("%s: negative duration!\n", __func__);
+ 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/sys/arch/armv7/omap/gptimer.c b/sys/arch/armv7/omap/gptimer.c
new file mode 100644
index 00000000000..6741766e4f8
--- /dev/null
+++ b/sys/arch/armv7/omap/gptimer.c
@@ -0,0 +1,441 @@
+/* $OpenBSD: gptimer.c,v 1.1 2013/09/04 14:38:30 patrick 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/omap/omapvar.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 omap_attach_args *oa = args;
+ bus_space_handle_t ioh;
+ u_int32_t rev;
+
+ gptimer_iot = oa->oa_iot;
+ if (bus_space_map(gptimer_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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 = oa->oa_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%x",
+ oa->oa_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 ((now - nexttickevent) < (now - nextstatevent))
+ 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/sys/arch/armv7/omap/if_cpsw.c b/sys/arch/armv7/omap/if_cpsw.c
new file mode 100644
index 00000000000..67fc5a97467
--- /dev/null
+++ b/sys/arch/armv7/omap/if_cpsw.c
@@ -0,0 +1,1264 @@
+/* $OpenBSD: if_cpsw.c,v 1.1 2013/09/04 14:38:30 patrick 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/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/omap/omapvar.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)
+
+/* __BIT(n): nth bit, where __BIT(0) == 0x1. */
+#define __BIT(__n) \
+ (((uint32_t)(__n) >= NBBY * sizeof(uint32_t)) ? 0 : ((uint32_t)1 << (uint32_t)(__n)))
+
+/* __BITS(m, n): bits m through n, m < n. */
+#define __BITS(__m, __n) \
+ ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
+
+/* find least significant bit that is set */
+#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
+
+#define __PRIuBIT PRIuMAX
+#define __PRIuBITS __PRIuBIT
+
+#define __PRIxBIT PRIxMAX
+#define __PRIxBITS __PRIxBIT
+
+#define __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / __LOWEST_SET_BIT(__mask))
+
+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;
+ const char sc_name;
+ 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_ec;
+ struct mii_data sc_mii;
+ void *sc_ih;
+ 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
+ uint8_t sc_enaddr[ETHER_ADDR_LEN];
+ volatile bool sc_txrun;
+ volatile bool sc_rxrun;
+ volatile bool sc_txeoq;
+ volatile bool sc_rxeoq;
+ struct timeout sc_tick;
+};
+
+void cpsw_get_mac_addr(struct cpsw_softc *);
+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 *);
+
+struct cfattach cpsw_ca = {
+ sizeof (struct cpsw_softc), NULL, cpsw_attach
+};
+
+struct cfdriver cpsw_cd = {
+ NULL, "cpsw", DV_IFNET
+};
+
+/*
+ * * Return the number of bytes in the mbuf chain, m.
+ * */
+static __inline u_int
+m_length(const struct mbuf *m)
+{
+ const struct mbuf *m0;
+ u_int pktlen;
+
+ if ((m->m_flags & M_PKTHDR) != 0)
+ return m->m_pkthdr.len;
+
+ pktlen = 0;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ pktlen += m0->m_len;
+ return pktlen;
+}
+
+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 uint32_t
+cpsw_read_4(struct cpsw_softc * const sc, bus_size_t const offset)
+{
+ return bus_space_read_4(sc->sc_bst, sc->sc_bsh, offset);
+}
+
+static inline void
+cpsw_write_4(struct cpsw_softc * const sc, bus_size_t const offset,
+ uint32_t const value)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, offset, value);
+}
+
+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;
+ uint32_t * const dp = bdp->word;
+ const bus_size_t c = nitems(bdp->word);
+
+ bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c);
+}
+
+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;
+ uint32_t * const dp = bdp->word;
+ const bus_size_t c = nitems(bdp->word);
+
+ bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c);
+}
+
+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;
+ uint32_t * const dp = bdp->word;
+ const bus_size_t c = nitems(bdp->word);
+
+ bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c);
+}
+
+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;
+ uint32_t * const dp = bdp->word;
+ const bus_size_t c = nitems(bdp->word);
+
+ bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c);
+}
+
+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)
+{
+ 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)) {
+ CPSW_PRINTF(sc, "%s(%d): Invalid Ethernet address!\n",
+ __FILE__, __LINE__);
+ } else {
+ sc->sc_enaddr[0] = (mac_hi >> 0) & 0xff;
+ sc->sc_enaddr[1] = (mac_hi >> 8) & 0xff;
+ sc->sc_enaddr[2] = (mac_hi >> 16) & 0xff;
+ sc->sc_enaddr[3] = (mac_hi >> 24) & 0xff;
+ sc->sc_enaddr[4] = (mac_lo >> 0) & 0xff;
+ sc->sc_enaddr[5] = (mac_lo >> 8) & 0xff;
+ }
+}
+
+void
+cpsw_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct cpsw_softc *sc = (struct cpsw_softc *)self;
+ struct omap_attach_args *oa = aux;
+ struct arpcom * const ec = &sc->sc_ec;
+ struct ifnet * const ifp = &ec->ac_if;
+ int error;
+ u_int i;
+
+ timeout_set(&sc->sc_tick, cpsw_tick, sc);
+
+ cpsw_get_mac_addr(sc);
+
+#if 0
+ /* XXX Start here, we need to setup the interrupt properly */
+ sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB,
+ ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
+ int irqno,
+ int level,
+ int (*func)(void *),
+ void *cookie,
+ char *name;
+#endif
+ sc->sc_rxthih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_RXTH,
+ IPL_NET, cpsw_rxthintr, sc, sc->sc_dev.dv_xname);
+ sc->sc_rxih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_RX,
+ IPL_NET, cpsw_rxintr, sc, sc->sc_dev.dv_xname);
+ sc->sc_txih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_TX,
+ IPL_NET, cpsw_txintr, sc, sc->sc_dev.dv_xname);
+ sc->sc_miscih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_MISC,
+ IPL_NET, cpsw_miscintr, sc, sc->sc_dev.dv_xname);
+
+ sc->sc_bst = oa->oa_iot;
+ sc->sc_bdt = oa->oa_dmat;
+
+ error = bus_space_map(sc->sc_bst, oa->oa_dev->mem[0].addr, oa->oa_dev->mem[0].size, 0,
+ &sc->sc_bsh);
+ if (error) {
+ printf("can't map registers: %d\n", error);
+ return;
+ }
+
+ sc->sc_txdescs_pa = oa->oa_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;
+ }
+ printf(" txdescs at %p", (void *)sc->sc_bsh_txdescs);
+
+ sc->sc_rxdescs_pa = oa->oa_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;
+ }
+ printf(" rxdescs at %p", (void *)sc->sc_bsh_rxdescs);
+
+ 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;
+ }
+
+ /* XXX Not sure if this is the correct way to do this. orig below.
+ sc->sc_txpad = kmem_zalloc(ETHER_MIN_LEN, KM_SLEEP);
+ */
+ sc->sc_txpad = malloc(ETHER_MIN_LEN, M_TEMP, M_WAITOK);
+ 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);
+
+ printf(", address %s\n", ether_sprintf(sc->sc_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);
+ IFQ_SET_READY(&ifp->if_snd);
+ memcpy(ifp->if_xname, sc->sc_dev.dv_xname, 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;
+
+#if 0
+ sc->sc_ec.ec_mii = &sc->sc_mii;
+#endif
+ 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);
+ }
+
+ memcpy(sc->sc_ec.ac_enaddr, sc->sc_enaddr, ETHER_ADDR_LEN);
+ 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;
+ uint32_t * const dw = bd.word;
+ struct mbuf *m;
+ bus_dmamap_t dm;
+ u_int sopi; /* Start of Packet Index */
+ u_int eopi = ~0;
+ u_int seg;
+ u_int txfree;
+ int txstart = -1;
+ int error;
+ bool pad;
+ u_int mlen;
+
+ if (__predict_false((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) !=
+ IFF_RUNNING)) {
+ 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;
+
+ while (txfree > 0) {
+ IFQ_POLL(&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);
+ if (error == EFBIG) {
+ printf("won't fit\n");
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ m_freem(m);
+ ifp->if_oerrors++;
+ continue;
+ } else if (error != 0) {
+ printf("error\n");
+ break;
+ }
+
+ if (dm->dm_nsegs + 1 >= txfree) {
+ ifp->if_flags |= IFF_OACTIVE;
+ bus_dmamap_unload(sc->sc_bdt, dm);
+ break;
+ }
+
+ mlen = m_length(m);
+ pad = mlen < CPSW_PAD_LEN;
+
+ KASSERT(rdp->tx_mb[sc->sc_txnext] == NULL);
+ rdp->tx_mb[sc->sc_txnext] = m;
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+
+ bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ if (txstart == -1)
+ txstart = sc->sc_txnext;
+ sopi = eopi = sc->sc_txnext;
+ for (seg = 0; seg < dm->dm_nsegs; seg++) {
+ dw[0] = cpsw_txdesc_paddr(sc,
+ TXDESC_NEXT(sc->sc_txnext));
+ dw[1] = dm->dm_segs[seg].ds_addr;
+ dw[2] = dm->dm_segs[seg].ds_len;
+ dw[3] = 0;
+
+ if (seg == 0)
+ dw[3] |= CPDMA_BD_SOP | CPDMA_BD_OWNER |
+ MAX(mlen, CPSW_PAD_LEN);
+
+ if (seg == dm->dm_nsegs - 1 && !pad)
+ dw[3] |= 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) {
+ dw[0] = cpsw_txdesc_paddr(sc,
+ TXDESC_NEXT(sc->sc_txnext));
+ dw[1] = sc->sc_txpad_pa;
+ dw[2] = CPSW_PAD_LEN - mlen;
+ dw[3] = 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 NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+ }
+
+ 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;
+ cpsw_write_4(sc, 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 ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s = splnet();
+ int error = 0;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&sc->sc_ec, ifa);
+#endif
+
+ 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_ec, 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("device timeout\n");
+
+ 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 ((cpsw_read_4(sc, reg) & __BIT(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;
+
+ cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) |
+ ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+ if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+ return 0;
+
+ v = cpsw_read_4(sc, MDIOUSERACCESS0);
+ if (v & __BIT(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;
+
+ cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) | (1 << 30) |
+ ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16) | val);
+
+ if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
+ goto out;
+
+ v = cpsw_read_4(sc, MDIOUSERACCESS0);
+ if ((v & __BIT(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;
+ uint32_t * const dw = bd.word;
+ 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 */
+ dw[0] = 0;
+ dw[1] = rdp->rx_dm[i]->dm_segs[0].ds_addr;
+ dw[2] = MIN(0x7ff, rdp->rx_dm[i]->dm_segs[0].ds_len);
+ dw[3] = 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 mii_data * const mii = &sc->sc_mii;
+ int i;
+
+ cpsw_stop(ifp);
+
+ sc->sc_txnext = 0;
+ sc->sc_txhead = 0;
+
+ /* Reset wrapper */
+ cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1);
+
+ /* Reset SS */
+ cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1);
+
+ /* Clear table (30) and enable ALE(31) and set passthrough (4) */
+ cpsw_write_4(sc, CPSW_ALE_CONTROL, (3 << 30) | 0x10);
+
+ /* Reset and init Sliver port 1 and 2 */
+ for (i = 0; i < 2; i++) {
+ /* Reset */
+ cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
+ while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1);
+ /* Set Slave Mapping */
+ cpsw_write_4(sc, CPSW_SL_RX_PRI_MAP(i), 0x76543210);
+ cpsw_write_4(sc, CPSW_PORT_P_TX_PRI_MAP(i+1), 0x33221100);
+ cpsw_write_4(sc, CPSW_SL_RX_MAXLEN(i), 0x5f2);
+ /* Set MAC Address */
+ cpsw_write_4(sc, CPSW_PORT_P_SA_HI(i+1),
+ sc->sc_enaddr[0] | (sc->sc_enaddr[1] << 8) |
+ (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[3] << 24));
+ cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1),
+ sc->sc_enaddr[4] | (sc->sc_enaddr[5] << 8));
+
+ /* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5),
+ IFCTL_A(15), IFCTL_B(16) FIXME */
+ cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), 1 | (1<<5) | (1<<15) | (1<<16));
+
+ /* Set ALE port to forwarding(3) */
+ cpsw_write_4(sc, CPSW_ALE_PORTCTL(i+1), 3);
+ }
+
+ /* Set Host Port Mapping */
+ cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
+ cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+
+ /* Set ALE port to forwarding(3) */
+ cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3);
+
+ cpsw_write_4(sc, CPSW_SS_PTYPE, 0);
+ cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7);
+
+ cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1);
+
+ for (i = 0; i < 8; i++) {
+ cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0);
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0);
+ cpsw_write_4(sc, 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;
+
+ cpsw_write_4(sc, 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 */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, ETHER_ALIGN);
+
+ /* Clear all interrupt Masks */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+ cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+
+ /* Enable TX & RX DMA */
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1);
+
+ /* Enable TX and RX interrupt receive for core 0 */
+ cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 1);
+ cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 1);
+ cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F);
+
+ /* Enable host Error Interrupt */
+ cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 2);
+
+ /* Enable interrupts for TX and RX Channel 0 */
+ cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_SET, 1);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1);
+
+ /* Ack stalled irqs */
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH);
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX);
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
+
+ /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+ cpsw_write_4(sc, MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
+
+ mii_mediachg(mii);
+
+ /* Write channel 0 RX HDP */
+ cpsw_write_4(sc, 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;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ 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);
+
+ cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 1);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 1);
+ cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 0x0);
+ cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0x0);
+ cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F);
+
+ cpsw_write_4(sc, CPSW_CPDMA_TX_TEARDOWN, 0);
+ cpsw_write_4(sc, 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 */
+ cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1);
+
+ /* Reset SS */
+ cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1);
+
+ for (i = 0; i < 2; i++) {
+ cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
+ while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1);
+ }
+
+ /* Reset CPDMA */
+ cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1);
+ while(cpsw_read_4(sc, 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|IFF_OACTIVE);
+ ifp->if_timer = 0;
+
+ /* 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 */
+ cpsw_write_4(sc, 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_ec.ac_if;
+ struct cpsw_ring_data * const rdp = sc->sc_rdp;
+ struct cpsw_cpdma_bd bd;
+ const uint32_t * const dw = bd.word;
+ bus_dmamap_t dm;
+ struct mbuf *m;
+ u_int i;
+ u_int len, off;
+
+ 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 (ISSET(dw[3], CPDMA_BD_OWNER))
+ break;
+
+ if (ISSET(dw[3], CPDMA_BD_TDOWNCMPLT)) {
+ sc->sc_rxrun = false;
+ return 1;
+ }
+
+ if ((dw[3] & (CPDMA_BD_SOP|CPDMA_BD_EOP)) !=
+ (CPDMA_BD_SOP|CPDMA_BD_EOP)) {
+ /* Debugger(); */
+ }
+
+ 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;
+ }
+
+ off = __SHIFTOUT(dw[2], (uint32_t)__BITS(26, 16));
+ len = __SHIFTOUT(dw[3], (uint32_t)__BITS(10, 0));
+
+ if (ISSET(dw[3], CPDMA_BD_PASSCRC))
+ len -= ETHER_CRC_LEN;
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_data += off;
+
+ ifp->if_ipackets++;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif
+ ether_input_mbuf(ifp, m);
+
+next:
+ sc->sc_rxhead = RXDESC_NEXT(sc->sc_rxhead);
+ if (ISSET(dw[3], CPDMA_BD_EOQ)) {
+ sc->sc_rxeoq = true;
+ break;
+ } else {
+ sc->sc_rxeoq = false;
+ }
+ cpsw_write_4(sc, CPSW_CPDMA_RX_CP(0),
+ cpsw_rxdesc_paddr(sc, i));
+ }
+
+ if (sc->sc_rxeoq) {
+ printf("rxeoq\n");
+ /* Debugger(); */
+ }
+
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX);
+
+ 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_ec.ac_if;
+ struct cpsw_ring_data * const rdp = sc->sc_rdp;
+ struct cpsw_cpdma_bd bd;
+ const uint32_t * const dw = bd.word;
+ bool handled = false;
+ uint32_t tx0_cp;
+ u_int cpi;
+
+ KASSERT(sc->sc_txrun);
+
+ tx0_cp = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0));
+
+ if (tx0_cp == 0xfffffffc) {
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CP(0), 0xfffffffc);
+ cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), 0);
+ sc->sc_txrun = false;
+ return 0;
+ }
+
+ cpi = (tx0_cp - sc->sc_txdescs_pa) / sizeof(struct cpsw_cpdma_bd);
+
+ for (;;) {
+ tx0_cp = cpsw_read_4(sc, 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 (dw[2] == 0) {
+ /* Debugger(); */
+ }
+
+ if (ISSET(dw[3], CPDMA_BD_SOP) == 0)
+ goto next;
+
+ if (ISSET(dw[3], CPDMA_BD_OWNER)) {
+ printf("pwned %x %x %x\n", cpi, sc->sc_txhead, sc->sc_txnext);
+ break;
+ }
+
+ if (ISSET(dw[3], 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;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+next:
+ if (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) {
+ sc->sc_txeoq = true;
+ }
+ if (sc->sc_txhead == cpi) {
+ cpsw_write_4(sc, 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 (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) {
+ sc->sc_txeoq = true;
+ break;
+ }
+ }
+
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
+
+ if ((sc->sc_txnext != sc->sc_txhead) && sc->sc_txeoq) {
+ if (cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)) == 0) {
+ sc->sc_txeoq = false;
+ cpsw_write_4(sc, 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 = cpsw_read_4(sc, CPSW_WR_C_MISC_STAT(0));
+ printf("%s %x FIRE\n", __func__, miscstat);
+
+#define CPSW_MISC_HOST_PEND __BIT32(2)
+#define CPSW_MISC_STAT_PEND __BIT32(3)
+
+ if (ISSET(miscstat, CPSW_MISC_HOST_PEND)) {
+ /* Host Error */
+ dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED);
+ printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
+
+ printf("rxhead %02x\n", sc->sc_rxhead);
+
+ stat = cpsw_read_4(sc, CPSW_CPDMA_DMASTATUS);
+ printf("CPSW_CPDMA_DMASTATUS %x\n", stat);
+ stat = cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0));
+ printf("CPSW_CPDMA_TX0_HDP %x\n", stat);
+ stat = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0));
+ printf("CPSW_CPDMA_TX0_CP %x\n", stat);
+ stat = cpsw_read_4(sc, CPSW_CPDMA_RX_HDP(0));
+ printf("CPSW_CPDMA_RX0_HDP %x\n", stat);
+ stat = cpsw_read_4(sc, CPSW_CPDMA_RX_CP(0));
+ printf("CPSW_CPDMA_RX0_CP %x\n", stat);
+
+ /* Debugger(); */
+
+ cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_CLEAR, dmastat);
+ dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED);
+ printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
+ }
+
+ cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
+
+ return 1;
+}
diff --git a/sys/arch/armv7/omap/if_cpswreg.h b/sys/arch/armv7/omap/if_cpswreg.h
new file mode 100644
index 00000000000..4df6e42c356
--- /dev/null
+++ b/sys/arch/armv7/omap/if_cpswreg.h
@@ -0,0 +1,139 @@
+/* $OpenBSD: if_cpswreg.h,v 1.1 2013/09/04 14:38:30 patrick 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_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 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_CPPI_RAM_OFFSET 0x2000
+
+#define CPSW_PRINTF(sc, fmt, args...) printf("%s: " fmt, sc->sc_dev, ##args)
+
+#define __BIT32(x) ((uint32_t)__BIT(x))
+#define __BITS32(x, y) ((uint32_t)__BITS((x), (y)))
+
+/* flags for desciptor word 3 */
+#define CPDMA_BD_SOP __BIT32(31)
+#define CPDMA_BD_EOP __BIT32(30)
+#define CPDMA_BD_OWNER __BIT32(29)
+#define CPDMA_BD_EOQ __BIT32(28)
+#define CPDMA_BD_TDOWNCMPLT __BIT32(27)
+#define CPDMA_BD_PASSCRC __BIT32(26)
+#define CPDMA_BD_PKT_ERR_MASK __BITS32(21,20)
+
+struct cpsw_cpdma_bd {
+ uint32_t word[4];
+};
+
+/* 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/sys/arch/armv7/omap/intc.c b/sys/arch/armv7/omap/intc.c
new file mode 100644
index 00000000000..2e515a54b16
--- /dev/null
+++ b/sys/arch/armv7/omap/intc.c
@@ -0,0 +1,423 @@
+/* $OpenBSD: intc.c,v 1.1 2013/09/04 14:38:30 patrick 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/omap/omapvar.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 omap_attach_args *oa = args;
+ int i;
+ u_int32_t rev;
+
+ intc_iot = oa->oa_iot;
+ if (bus_space_map(intc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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(I32_bit);
+}
+
+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(I32_bit);
+#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(I32_bit);
+
+ /* 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(I32_bit);
+ TAILQ_REMOVE(&intc_handler[irqno].iq_list, ih, ih_list);
+ if (ih->ih_name != NULL)
+ evcount_detach(&ih->ih_count);
+ free(ih, M_DEVBUF);
+ 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/sys/arch/armv7/omap/intc.h b/sys/arch/armv7/omap/intc.h
new file mode 100644
index 00000000000..afb54dd41a3
--- /dev/null
+++ b/sys/arch/armv7/omap/intc.h
@@ -0,0 +1,74 @@
+/* $OpenBSD: intc.h,v 1.1 2013/09/04 14:38:30 patrick 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/sys/arch/armv7/omap/omap.c b/sys/arch/armv7/omap/omap.c
new file mode 100644
index 00000000000..259176ac212
--- /dev/null
+++ b/sys/arch/armv7/omap/omap.c
@@ -0,0 +1,232 @@
+/* $OpenBSD: omap.c,v 1.1 2013/09/04 14:38:30 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 <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <arch/arm/armv7/armv7var.h>
+#include <armv7/omap/omapvar.h>
+
+struct arm32_bus_dma_tag omap_bus_dma_tag = {
+ 0,
+ 0,
+ NULL,
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ _bus_dmamap_sync,
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
+
+struct board_dev {
+ char *name;
+ int unit;
+};
+
+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 },
+ { "dmtimer", 0 },
+ { "dmtimer", 1 },
+ { "omdog", 0 },
+ { "ommmc", 0 }, /* HSMMC0 */
+ { "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 board_dev *board_devs;
+
+struct omap_dev *omap_devs = NULL;
+
+struct omap_softc {
+ struct device sc_dv;
+};
+
+int omap_match(struct device *, void *, void *);
+void omap_attach(struct device *, struct device *, void *);
+int omap_submatch(struct device *, void *, void *);
+
+struct cfattach omap_ca = {
+ sizeof(struct omap_softc), omap_match, omap_attach
+};
+
+struct cfdriver omap_cd = {
+ NULL, "omap", DV_DULL
+};
+
+int
+omap_match(struct device *parent, void *cfdata, void *aux)
+{
+ return (1);
+}
+
+void
+omap_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct board_dev *bd;
+
+ switch (board_id) {
+ case BOARD_ID_OMAP3_BEAGLE:
+ printf(": BeagleBoard\n");
+ omap3_init();
+ board_devs = beagleboard_devs;
+ break;
+ case BOARD_ID_AM335X_BEAGLEBONE:
+ printf(": BeagleBone\n");
+ am335x_init();
+ board_devs = beaglebone_devs;
+ break;
+ case BOARD_ID_OMAP3_OVERO:
+ printf(": Gumstix Overo\n");
+ omap3_init();
+ board_devs = overo_devs;
+ break;
+ case BOARD_ID_OMAP4_PANDA:
+ printf(": PandaBoard\n");
+ omap4_init();
+ board_devs = pandaboard_devs;
+ break;
+ default:
+ printf("\n");
+ panic("%s: board type 0x%x unknown", __func__, board_id);
+ }
+
+ /* Directly configure on-board devices (dev* in config file). */
+ for (bd = board_devs; bd->name != NULL; bd++) {
+ struct omap_dev *od = omap_find_dev(bd->name, bd->unit);
+ struct omap_attach_args oa;
+
+ if (od == NULL) {
+ printf("%s: device %s unit %d not found\n",
+ self->dv_xname, bd->name, bd->unit);
+ continue;
+ }
+
+ memset(&oa, 0, sizeof(oa));
+ oa.oa_dev = od;
+ oa.oa_iot = &armv7_bs_tag;
+ oa.oa_dmat = &omap_bus_dma_tag;
+
+ if (config_found_sm(self, &oa, NULL, omap_submatch) == NULL)
+ printf("%s: device %s unit %d not configured\n",
+ self->dv_xname, bd->name, bd->unit);
+ }
+}
+
+/*
+ * We do direct configuration of devices on this SoC "bus", so we
+ * never call the child device's match function at all (it can be
+ * NULL in the struct cfattach).
+ */
+int
+omap_submatch(struct device *parent, void *child, void *aux)
+{
+ struct cfdata *cf = child;
+ struct omap_attach_args *oa = aux;
+
+ if (strcmp(cf->cf_driver->cd_name, oa->oa_dev->name) == 0)
+ return (1);
+
+ /* "These are not the droids you are looking for." */
+ return (0);
+}
+
+void
+omap_set_devs(struct omap_dev *devs)
+{
+ omap_devs = devs;
+}
+
+struct omap_dev *
+omap_find_dev(const char *name, int unit)
+{
+ struct omap_dev *od;
+
+ if (omap_devs == NULL)
+ panic("%s: omap_devs == NULL", __func__);
+
+ for (od = omap_devs; od->name != NULL; od++) {
+ if (od->unit == unit && strcmp(od->name, name) == 0)
+ return (od);
+ }
+
+ return (NULL);
+}
diff --git a/sys/arch/armv7/omap/omap3.c b/sys/arch/armv7/omap/omap3.c
new file mode 100644
index 00000000000..913770fff24
--- /dev/null
+++ b/sys/arch/armv7/omap/omap3.c
@@ -0,0 +1,196 @@
+/* $OpenBSD: omap3.c,v 1.1 2013/09/04 14:38:30 patrick 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/omap/omapvar.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 omap_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)
+{
+ omap_set_devs(omap3_devs);
+}
diff --git a/sys/arch/armv7/omap/omap3_prcmreg.h b/sys/arch/armv7/omap/omap3_prcmreg.h
new file mode 100644
index 00000000000..3d41d170655
--- /dev/null
+++ b/sys/arch/armv7/omap/omap3_prcmreg.h
@@ -0,0 +1,197 @@
+/* $OpenBSD: omap3_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.
+ */
+
+/* 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_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_GPT1 1
+#define CM_FCLKEN_WKUP_GPIOS 4
+#define CM_FCLKEN_WKUP_MPU_WDT 8
+#define CM_ICLKEN_WKUP 0xc10
+#define CM_ICLKEN_WKUP_GPT1 0x01
+#define CM_ICLKEN_WKUP_32KSYNC 0x02
+#define CM_ICLKEN_WKUP_GPIOS 0x04
+#define CM_ICLKEN_WKUP_MPU_WDT 0x08
+#define CM_ICLKEN_WKUP_WDT1 0x10
+#define CM_ICLKEN_WKUP_OMAPCTRL 0x20
+#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_ICLKEN_PER 0x1010
+#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 0x5140
+#define CM_CLKSTCTRL_EMU 0x5148
+#define CM_CLKSTST_EMU 0x514C
+#define CM_CLKSEL2_EMU 0x5150
+#define CM_CLKSEL3_EMU 0x5154
+
+#define CM_POLCTRL 0x529C
+
+#define CM_IDLEST_NEON 0x5320
+#define CM_CLKSTCTRL_NEON 0x5348
+
+#define CM_FCLKEN_USBHOST 0x5400
+#define CM_ICLKEN_USBHOST 0x5410
+#define CM_IDLEST_USBHOST 0x5420
+#define CM_AUTOIDLE_USBHOST 0x5430
+#define CM_SLEEPDEP_USBHOST 0x5444
+#define CM_CLKSTCTRL_USBHOST 0x5448
+#define CM_CLKSTST_USBHOST 0x544C
+
+/* from prcmvar.h */
+#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 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 CM_CORE_EN_USBTLL (PRCM_REG_CORE_CLK3_BASE + 2)
+#define CM_CORE_EN_TS (PRCM_REG_CORE_CLK3_BASE + 1)
+#define CM_CORE_EN_CPEFUSE (PRCM_REG_CORE_CLK3_BASE + 0)
+
+#define PRCM_REG_USBHOST 3
+#define PRCM_REG_USBHOST_FADDR 0x1400
+#define PRCM_REG_USBHOST_IADDR 0x1410
+#define PRCM_REG_USBHOST_FMASK 0x3
+#define PRCM_REG_USBHOST_IMASK 0x1
+#define PRCM_REG_USBHOST_BASE (PRCM_REG_USBHOST*32)
+
+#define PRCM_CLK_EN_USB (PRCM_REG_USBHOST_BASE + 0)
diff --git a/sys/arch/armv7/omap/omap4.c b/sys/arch/armv7/omap/omap4.c
new file mode 100644
index 00000000000..3ba281127e3
--- /dev/null
+++ b/sys/arch/armv7/omap/omap4.c
@@ -0,0 +1,200 @@
+/* $OpenBSD: omap4.c,v 1.1 2013/09/04 14:38:30 patrick 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 <arch/arm/armv7/armv7var.h>
+
+#include <armv7/omap/omapvar.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 0x300
+#define HSMMC1_ADDR 0x4809c000
+#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 omap_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)
+{
+ omap_set_devs(omap4_devs);
+}
diff --git a/sys/arch/armv7/omap/omap4_prcmreg.h b/sys/arch/armv7/omap/omap4_prcmreg.h
new file mode 100644
index 00000000000..9cff537f1ab
--- /dev/null
+++ b/sys/arch/armv7/omap/omap4_prcmreg.h
@@ -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/sys/arch/armv7/omap/omap_com.c b/sys/arch/armv7/omap/omap_com.c
new file mode 100644
index 00000000000..8700000d6a5
--- /dev/null
+++ b/sys/arch/armv7/omap/omap_com.c
@@ -0,0 +1,112 @@
+/* $OpenBSD: omap_com.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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 omap_attach_args *oa = aux;
+
+ sc->sc_iot = &armv7_a4x_bs_tag; /* XXX: This sucks */
+ sc->sc_iobase = oa->oa_dev->mem[0].addr;
+ sc->sc_frequency = 48000000;
+ sc->sc_uarttype = COM_UART_TI16750;
+
+ if (bus_space_map(sc->sc_iot, sc->sc_iobase,
+ oa->oa_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(oa->oa_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/sys/arch/armv7/omap/omapid.c b/sys/arch/armv7/omap/omapid.c
new file mode 100644
index 00000000000..23c5245d5b9
--- /dev/null
+++ b/sys/arch/armv7/omap/omapid.c
@@ -0,0 +1,101 @@
+/* $OpenBSD: omapid.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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 omap_attach_args *oa = args;
+ struct omapid_softc *sc = (struct omapid_softc *) self;
+ uint32_t rev;
+ uint32_t newclockrate = 0;
+ char *board;
+
+ sc->sc_iot = oa->oa_iot;
+ if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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/sys/arch/armv7/omap/omapvar.h b/sys/arch/armv7/omap/omapvar.h
new file mode 100644
index 00000000000..b2a2e565f5e
--- /dev/null
+++ b/sys/arch/armv7/omap/omapvar.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: omapvar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@drahn.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.
+ */
+
+/* Physical memory range for on-chip devices. */
+struct omap_mem {
+ u_int32_t addr; /* physical start address */
+ u_int32_t size; /* size of range in bytes */
+};
+
+#define OMAP_DEV_NMEM 4 /* number of memory ranges */
+#define OMAP_DEV_NIRQ 4 /* number of IRQs per device */
+
+/* Descriptor for all on-chip devices. */
+struct omap_dev {
+ char *name; /* driver name or made up name */
+ int unit; /* driver instance number or -1 */
+ struct omap_mem mem[OMAP_DEV_NMEM]; /* memory ranges */
+ int irq[OMAP_DEV_NIRQ]; /* IRQ number(s) */
+};
+
+/* Passed as third arg to attach functions. */
+struct omap_attach_args {
+ struct omap_dev *oa_dev;
+ bus_space_tag_t oa_iot;
+ bus_dma_tag_t oa_dmat;
+};
+
+void omap_set_devs(struct omap_dev *);
+struct omap_dev *omap_find_dev(const char *, int);
+
+void omap3_init(void);
+void omap4_init(void);
+void am335x_init(void);
+
+/* XXX */
+void *avic_intr_establish(int irqno, int level, int (*func)(void *),
+ void *arg, char *name);
+
+/* board identification - from uboot */
+#define BOARD_ID_AM335X_BEAGLEBONE 3589
+#define BOARD_ID_OMAP3_BEAGLE 1546
+#define BOARD_ID_OMAP3_OVERO 1798
+#define BOARD_ID_OMAP4_PANDA 2791
+extern uint32_t board_id;
diff --git a/sys/arch/armv7/omap/omdisplay.c b/sys/arch/armv7/omap/omdisplay.c
new file mode 100644
index 00000000000..4e5cea513c5
--- /dev/null
+++ b/sys/arch/armv7/omap/omdisplay.c
@@ -0,0 +1,1370 @@
+/* $OpenBSD: omdisplay.c,v 1.1 2013/09/04 14:38:31 patrick 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/omapvar.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);
+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 = {
+ omdisplay_ioctl,
+ omdisplay_mmap,
+ omdisplay_alloc_screen,
+ omdisplay_free_screen,
+ omdisplay_show_screen,
+ NULL, /* load font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ 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);
+ 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);
+}
+
+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/sys/arch/armv7/omap/omdog.c b/sys/arch/armv7/omap/omdog.c
new file mode 100644
index 00000000000..73bbc73391a
--- /dev/null
+++ b/sys/arch/armv7/omap/omdog.c
@@ -0,0 +1,113 @@
+/* $OpenBSD: omdog.c,v 1.1 2013/09/04 14:38:31 patrick 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 <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <armv7/omap/omapvar.h>
+#include <armv7/omap/omgpiovar.h>
+
+/* registers */
+#define WIDR 0x00
+#define WD_SYSCONFIG 0x10
+#define WD_SYSSTATUS 0x14
+#define WISR 0x18
+#define WIER 0x1C
+#define WCLR 0x24
+#define WCRR 0x28
+#define WLDR 0x2C
+#define WTGR 0x30
+#define WWPS 0x34
+#define WWPS_PEND_ALL 0x1f
+#define WSPR 0x48
+
+
+struct omdog_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+struct omdog_softc *omdog_sc;
+
+/*
+ * to enable the watchdog, write 0xXXXXbbbb then 0xXXXX4444 to WSPR
+ * to disable the watchdog, write 0xXXXXaaaa then 0xXXXX5555 to WSPR
+ */
+
+void omdog_attach(struct device *parent, struct device *self, void *args);
+void omdog_wpending(int flags);
+
+struct cfattach omdog_ca = {
+ sizeof (struct omdog_softc), NULL, omdog_attach
+};
+
+struct cfdriver omdog_cd = {
+ NULL, "omdog", DV_DULL
+};
+
+void
+omdog_attach(struct device *parent, struct device *self, void *args)
+{
+ struct omap_attach_args *oa = args;
+ struct omdog_softc *sc = (struct omdog_softc *) self;
+ u_int32_t rev;
+
+ sc->sc_iot = oa->oa_iot;
+ if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("gptimer_attach: bus_space_map failed!");
+
+ 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;
+}
+
+void
+omdog_wpending(int flags)
+{
+ struct omdog_softc *sc = omdog_sc;
+ while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) & flags)
+ ;
+}
+
+void omdog_reset(void); /* XXX */
+
+void
+omdog_reset()
+{
+ if (omdog_sc == NULL)
+ return;
+
+ bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR, 0xffffff80);
+ omdog_wpending(WWPS_PEND_ALL);
+
+ /* this sequence will start the watchdog. */
+ bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WSPR, 0xbbbb);
+ omdog_wpending(WWPS_PEND_ALL);
+ bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WSPR, 0x4444);
+ omdog_wpending(WWPS_PEND_ALL);
+ delay(100000);
+}
diff --git a/sys/arch/armv7/omap/omehci.c b/sys/arch/armv7/omap/omehci.c
new file mode 100644
index 00000000000..1fc17f84abc
--- /dev/null
+++ b/sys/arch/armv7/omap/omehci.c
@@ -0,0 +1,487 @@
+/* $OpenBSD: omehci.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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 omap_attach_args *oa = aux;
+ usbd_status r;
+ char *devname = sc->sc.sc_bus.bdev.dv_xname;
+ uint32_t i;
+
+ sc->sc.iot = oa->oa_iot;
+ sc->sc.sc_bus.dmatag = oa->oa_dmat;
+ sc->sc.sc_size = oa->oa_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, oa->oa_dev->mem[0].addr,
+ oa->oa_dev->mem[0].size, 0, &sc->sc.ioh)) {
+ printf(": cannot map mem space\n");
+ goto out;
+ }
+
+ if (bus_space_map(sc->sc.iot, oa->oa_dev->mem[1].addr,
+ oa->oa_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, oa->oa_dev->mem[2].addr,
+ oa->oa_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(oa->oa_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;
+ }
+
+ sc->sc.sc_child = config_found((void *)sc, &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, oa->oa_dev->mem[2].size);
+mem1:
+ bus_space_unmap(sc->sc.iot, sc->uhh_ioh, oa->oa_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(&sc->sc, 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/sys/arch/armv7/omap/omehcivar.h b/sys/arch/armv7/omap/omehcivar.h
new file mode 100644
index 00000000000..8eed72d4a5a
--- /dev/null
+++ b/sys/arch/armv7/omap/omehcivar.h
@@ -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/sys/arch/armv7/omap/omgpio.c b/sys/arch/armv7/omap/omgpio.c
new file mode 100644
index 00000000000..1f7ca3232ee
--- /dev/null
+++ b/sys/arch/armv7/omap/omgpio.c
@@ -0,0 +1,641 @@
+/* $OpenBSD: omgpio.c,v 1.1 2013/09/04 14:38:31 patrick 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 <arm/cpufunc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <armv7/omap/omapvar.h>
+#include <armv7/omap/omgpiovar.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
+#define GPIO3_SIZE 0x100
+
+/* 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_IRQSTATUS1 0x118
+#define GPIO4_IRQENABLE1 0x11C
+#define GPIO4_WAKEUPENABLE 0x120
+#define GPIO4_IRQSTATUS2 0x128
+#define GPIO4_IRQENABLE2 0x12C
+#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_CLEARIRQENABLE1 0x160
+#define GPIO4_SETIRQENABLE1 0x164
+#define GPIO4_CLEARIRQENABLE2 0x170
+#define GPIO4_SETIRQENABLE2 0x174
+#define GPIO4_CLEARWKUPENA 0x180
+#define GPIO4_SETWKUENA 0x184
+#define GPIO4_CLEARDATAOUT 0x190
+#define GPIO4_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_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;
+ unsigned int (*sc_get_bit)(struct omgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_bit)(struct omgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_clear_bit)(struct omgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_dir)(struct omgpio_softc *sc,
+ unsigned int gpio, unsigned int dir);
+};
+
+#define GPIO_PIN_TO_INST(x) ((x) >> 5)
+#define GPIO_PIN_TO_OFFSET(x) ((x) & 0x1f)
+
+int omgpio_match(struct device *parent, void *v, void *aux);
+void omgpio_attach(struct device *parent, struct device *self, void *args);
+void omgpio_recalc_interrupts(struct omgpio_softc *sc);
+int omgpio_irq(void *);
+int omgpio_irq_dummy(void *);
+
+unsigned int omgpio_v3_get_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v3_set_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v3_clear_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v3_set_dir(struct omgpio_softc *, unsigned int , unsigned int);
+unsigned int omgpio_v4_get_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v4_set_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v4_clear_bit(struct omgpio_softc *, unsigned int);
+void omgpio_v4_set_dir(struct omgpio_softc *, unsigned int, unsigned int);
+unsigned int omgpio_v4_get_dir(struct omgpio_softc *, unsigned int);
+
+
+struct cfattach omgpio_ca = {
+ sizeof (struct omgpio_softc), omgpio_match, omgpio_attach
+};
+
+struct cfdriver omgpio_cd = {
+ NULL, "omgpio", DV_DULL
+};
+
+int
+omgpio_match(struct device *parent, void *v, void *aux)
+{
+ switch (board_id) {
+ case BOARD_ID_OMAP3_BEAGLE:
+ case BOARD_ID_OMAP3_OVERO:
+ break; /* continue trying */
+ 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 omap_attach_args *oa = args;
+ struct omgpio_softc *sc = (struct omgpio_softc *) self;
+ u_int32_t rev;
+
+ sc->sc_iot = oa->oa_iot;
+ if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("omgpio_attach: bus_space_map failed!");
+
+
+ switch (board_id) {
+ case BOARD_ID_OMAP3_BEAGLE:
+ case BOARD_ID_OMAP3_OVERO:
+ sc->sc_omap_ver = 3;
+ sc->sc_get_bit = omgpio_v3_get_bit;
+ sc->sc_set_bit = omgpio_v3_set_bit;
+ sc->sc_clear_bit = omgpio_v3_clear_bit;
+ sc->sc_set_dir = omgpio_v3_set_dir;
+ break;
+ case BOARD_ID_OMAP4_PANDA:
+ sc->sc_omap_ver = 4;
+ sc->sc_get_bit = omgpio_v4_get_bit;
+ sc->sc_set_bit = omgpio_v4_set_bit;
+ sc->sc_clear_bit = omgpio_v4_clear_bit;
+ sc->sc_set_dir = omgpio_v4_set_dir;
+ break;
+ }
+
+ rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_REVISION);
+
+ printf(" omap%d rev %d.%d\n", sc->sc_omap_ver, rev >> 4 & 0xf,
+ rev & 0xf);
+
+ sc->sc_irq = oa->oa_dev->irq[0];
+
+ if (sc->sc_omap_ver == 3) {
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ GPIO3_CLEARIRQENABLE1, ~0);
+ } else if (sc->sc_omap_ver == 4) {
+ /* XXX - nothing? */
+ }
+
+ /* XXX - SYSCONFIG */
+ /* XXX - CTRL */
+ /* XXX - DEBOUNCE */
+}
+
+/* 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
+
+/*
+ * get_bit() is not reliable if used on an output pin.
+ */
+
+unsigned int
+omgpio_get_bit(unsigned int gpio)
+{
+ struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ return sc->sc_get_bit(sc, gpio);
+}
+
+void
+omgpio_set_bit(unsigned int gpio)
+{
+ struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_bit(sc, gpio);
+}
+
+void
+omgpio_clear_bit(unsigned int gpio)
+{
+ struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_clear_bit(sc, gpio);
+}
+void
+omgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+ struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_dir(sc, gpio, dir);
+}
+
+unsigned int
+omgpio_v3_get_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t reg;
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_DATAIN);
+ return (reg >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1;
+}
+
+void
+omgpio_v3_set_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_SETDATAOUT,
+ 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_v3_clear_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_CLEARDATAOUT,
+ 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_v3_set_dir(struct omgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+ int s;
+ u_int32_t reg;
+
+ s = splhigh();
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_DATAIN);
+ if (dir == OMGPIO_DIR_IN)
+ reg |= 1 << GPIO_PIN_TO_OFFSET(gpio);
+ else
+ reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_OE, reg);
+
+ splx(s);
+}
+
+unsigned int
+omgpio_v4_get_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t reg;
+
+ if(omgpio_v4_get_dir(sc, gpio) == OMGPIO_DIR_IN)
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_DATAIN);
+ else
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_DATAOUT);
+ return (reg >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1;
+}
+
+void
+omgpio_v4_set_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_SETDATAOUT,
+ 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_v4_clear_bit(struct omgpio_softc *sc, unsigned int gpio)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_CLEARDATAOUT,
+ 1 << GPIO_PIN_TO_OFFSET(gpio));
+}
+
+void
+omgpio_v4_set_dir(struct omgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+ int s;
+ u_int32_t reg;
+
+ s = splhigh();
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE);
+ if (dir == OMGPIO_DIR_IN)
+ reg |= 1 << GPIO_PIN_TO_OFFSET(gpio);
+ else
+ reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE, reg);
+
+ splx(s);
+}
+
+unsigned int
+omgpio_v4_get_dir(struct omgpio_softc *sc, unsigned int gpio)
+{
+ int s;
+ u_int32_t dir, reg;
+
+ s = splhigh();
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE);
+ if (reg & (1 << GPIO_PIN_TO_OFFSET(gpio)))
+ dir = OMGPIO_DIR_IN;
+ else
+ dir = OMGPIO_DIR_OUT;
+
+ splx(s);
+
+ return dir;
+}
+
+#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)];
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQSTATUS1,
+ 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)];
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_CLEARIRQENABLE1,
+ 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)];
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_SETIRQENABLE1,
+ 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 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_FALLINGDETECT);
+ re = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_RISINGDETECT);
+ l0 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT0);
+ l1 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_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;
+ }
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_FALLINGDETECT, fe);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_RISINGDETECT, re);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT0, l0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_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(I32_bit);
+
+ /* 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(I32_bit);
+
+ 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);
+
+ 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 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQSTATUS1);
+
+ 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,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQENABLE1)
+
+ );
+ }
+ 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/sys/arch/armv7/omap/omgpiovar.h b/sys/arch/armv7/omap/omgpiovar.h
new file mode 100644
index 00000000000..1a47dd948a9
--- /dev/null
+++ b/sys/arch/armv7/omap/omgpiovar.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: omgpiovar.h,v 1.1 2013/09/04 14:38:31 patrick 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);
+
+/* 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/sys/arch/armv7/omap/ommmc.c b/sys/arch/armv7/omap/ommmc.c
new file mode 100644
index 00000000000..ccb12ff9206
--- /dev/null
+++ b/sys/arch/armv7/omap/ommmc.c
@@ -0,0 +1,1232 @@
+/* $OpenBSD: ommmc.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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_CON 0x02C
+#define MMCHS_CON_INIT (1<<1)
+#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_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 */
+ u_int sc_flags;
+
+ struct device *sdmmc; /* generic SD/MMC device */
+ int clockbit; /* clock control bit */
+ u_int clkbase; /* base clock frequency in KHz */
+ int maxblklen; /* maximum block length */
+ int flags; /* flags for this host */
+ uint32_t ocr; /* OCR value from capabilities */
+// u_int8_t regs[14]; /* host controller state */
+ uint32_t intr_status; /* soft interrupt status */
+ uint32_t intr_error_status; /* */
+};
+
+
+/* Host controller functions called by the attachment driver. */
+int 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)
+
+#define HDEVNAME(sc) ((sc)->sc_dev.dv_xname)
+
+/* flag values */
+#define SHF_USE_DMA 0x0001
+
+/* MMCHS should only be accessed with 4 byte reads or writes. */
+#if 0
+struct regtbl {
+ char* name;
+ uint32_t reg;
+} tblname[] = {
+ {"MMCHS_SYSCONFIG", MMCHS_SYSCONFIG},
+ {"MMCHS_SYSSTATUS", MMCHS_SYSSTATUS},
+ {"MMCHS_CSRE", MMCHS_CSRE},
+ {"MMCHS_SYSTEST", MMCHS_SYSTEST},
+ {"MMCHS_CON", MMCHS_CON},
+ {"MMCHS_PWCNT", MMCHS_PWCNT},
+ {"MMCHS_BLK", MMCHS_BLK},
+ {"MMCHS_ARG", MMCHS_ARG},
+ {"MMCHS_CMD", MMCHS_CMD},
+ {"MMCHS_RSP10", MMCHS_RSP10},
+ {"MMCHS_RSP32", MMCHS_RSP32},
+ {"MMCHS_RSP54", MMCHS_RSP54},
+ {"MMCHS_RSP76", MMCHS_RSP76},
+ {"MMCHS_DATA", MMCHS_DATA},
+ {"MMCHS_PSTATE", MMCHS_PSTATE},
+ {"MMCHS_HCTL", MMCHS_HCTL},
+ {"MMCHS_SYSCTL", MMCHS_SYSCTL},
+ {"MMCHS_STAT", MMCHS_STAT},
+ {"MMCHS_IE", MMCHS_IE},
+ {"MMCHS_ISE", MMCHS_ISE},
+ {"MMCHS_AC12", MMCHS_AC12},
+ {"MMCHS_CAPA", MMCHS_CAPA},
+ {"MMCHS_CUR_CAPA", MMCHS_CUR_CAPA},
+ {NULL, 0 }
+};
+uint32_t HREAD4(struct ommmc_softc *sc, uint32_t reg);
+void HWRITE4(struct ommmc_softc *sc, uint32_t reg, uint32_t val);
+uint32_t HREAD4(struct ommmc_softc *sc, uint32_t reg)
+{
+ uint32_t val;
+ int i;
+ char *regname = "???";
+ for (i = 0; tblname[i].name != NULL; i++) {
+ if (tblname[i].reg == reg) {
+ regname = tblname[i].name;
+ break;
+ }
+ }
+ val = (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)));
+ printf("read reg[%s] = %x\n", regname, val);
+ return val;
+
+}
+void HWRITE4(struct ommmc_softc *sc, uint32_t reg, uint32_t val)
+{
+ char *regname = "???";
+ int i;
+ for (i = 0; tblname[i].name != NULL; i++) {
+ if (tblname[i].reg == reg) {
+ regname = tblname[i].name;
+ break;
+ }
+ }
+ printf("write reg[%s] = %x\n", regname, 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))
+#else
+#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))
+#endif
+
+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);
+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 *, u_char *, int);
+void ommmc_write_data(struct ommmc_softc *, u_char *, 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,
+ /* 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 omap_attach_args *oa = args;
+ struct sdmmcbus_attach_args saa;
+ int baseaddr;
+ int error = 1;
+
+ /* XXX - ICLKEN, FCLKEN? */
+
+ baseaddr = oa->oa_dev->mem[0].addr;
+ if (board_id == BOARD_ID_OMAP4_PANDA ||
+ board_id == BOARD_ID_AM335X_BEAGLEBONE) {
+ /* omap4430 has mmc registers offset +0x100 */
+ baseaddr += 0x100;
+ }
+
+ sc->sc_iot = oa->oa_iot;
+ if (bus_space_map(sc->sc_iot, baseaddr, oa->oa_dev->mem[0].size,
+ 0, &sc->sc_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ printf("\n");
+
+ /* XXX DMA channels? */
+ /* FIXME prcm_enableclock(sc->clockbit); */
+
+ sc->sc_ih = arm_intr_establish(oa->oa_dev->irq[0], IPL_SDMMC,
+ ommmc_intr, sc, sc->sc_dev.dv_xname);
+
+#if 0
+ /* XXX - IIRC firmware should set this */
+ /* Controller Voltage Capabilities Initialization */
+ HSET4(sc, MMCHS_CAPA, MMCHS_CAPA_VS18 | MMCHS_CAPA_VS30);
+#endif
+
+#ifdef SDHC_DEBUG
+ ommmc_dump_regs(sc);
+#endif
+
+ /*
+ * Reset the host controller and enable interrupts.
+ */
+ (void)ommmc_host_reset(sc);
+
+#if 0
+ /* Determine host capabilities. */
+ caps = HREAD4(sc, SDHC_CAPABILITIES);
+
+ /* 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",
+ sc->sc_dev.dv_xname);
+ 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",
+ sc->sc_dev.dv_xname, 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 (HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_VS18)
+ SET(sc->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
+ if (HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_VS30)
+ SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
+ if (HREAD4(sc, MMCHS_CAPA) & 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 ((HREAD4(sc, MMCHS_CAPA) & 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));
+ }
+
+ sc->maxblklen = 512; /* XXX */
+
+ /*
+ * 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;
+
+ sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
+ if (sc->sdmmc == NULL) {
+ error = 0;
+ goto err;
+ }
+
+ return;
+
+err:
+ return;
+}
+
+
+/*
+ * Power hook established by or called from attachment driver.
+ */
+void
+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;
+ u_int32_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)
+{
+#if 0
+ struct ommmc_softc *sc = sch;
+ return ISSET(HREAD4(sc, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
+ 1 : 0;
+#else
+ return 1; /* XXX */
+#endif
+}
+
+/*
+ * 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_7V_1_8V | MMC_OCR_1_8V_1_9V))
+ 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, u_int 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();
+
+#ifdef DIAGNOSTIC
+ /* Must not stop the clock if commands are in progress. */
+ if (ISSET(HREAD4(sc, MMCHS_PSTATE), MMCHS_PSTATE_CMDI|MMCHS_PSTATE_DATI)
+ && ommmc_card_detect(sc))
+ printf("ommmc_sdclk_frequency_select: command in progress\n");
+#endif
+
+ /*
+ * 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;
+}
+
+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", HDEVNAME(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", HDEVNAME(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",
+ HDEVNAME(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)
+{
+ u_int32_t blksize = 0;
+ u_int32_t blkcount = 0;
+ u_int32_t command;
+ int error;
+ int s;
+
+ DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
+ "proc=\"%s\"\n", HDEVNAME(sc), cmd->c_opcode, cmd->c_arg,
+ cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ?
+ curproc->p_comm : ""));
+
+ /*
+ * The maximum block length for commands should be the minimum
+ * of the host buffer size and the card buffer size. (1.7.2)
+ */
+
+ /* Fragment the data into proper blocks. */
+ if (cmd->c_datalen > 0) {
+ blksize = MIN(cmd->c_datalen, cmd->c_blklen);
+ blkcount = cmd->c_datalen / blksize;
+ if (cmd->c_datalen % blksize > 0) {
+ /* XXX: Split this command. (1.7.4) */
+ printf("%s: data not a multiple of %d bytes\n",
+ HDEVNAME(sc), blksize);
+ return EINVAL;
+ }
+ }
+
+ /* Check limit imposed by 9-bit block count. (1.7.2) */
+ if (blkcount > MMCHS_BLK_NBLK_MAX) {
+ printf("%s: too much data\n", HDEVNAME(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",
+ HDEVNAME(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)
+{
+ u_char *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", HDEVNAME(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",
+ HDEVNAME(sc), cmd->c_error));
+}
+
+void
+ommmc_read_data(struct ommmc_softc *sc, u_char *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, u_char *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", HDEVNAME(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", HDEVNAME(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", HDEVNAME(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;
+
+ u_int32_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", HDEVNAME(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", HDEVNAME(sc)));
+ HCLR4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ);
+ sdmmc_card_intr(sc->sdmmc);
+ }
+ return 1;
+}
+
+#ifdef SDHC_DEBUG
+
+struct {
+ char * name;
+ uint32_t off;
+ } reglist[] = {
+ { "MMCHS_SYSCONFIG", 0x010 },
+ { "MMCHS_SYSSTATUS", 0x014 },
+ { "MMCHS_CSRE", 0x024 },
+ { "MMCHS_SYSTEST", 0x028 },
+ { "MMCHS_CON", 0x02C },
+ { "MMCHS_PWCNT", 0x030 },
+ { "MMCHS_BLK", 0x104 },
+ { "MMCHS_ARG", 0x108 },
+ { "MMCHS_CMD", 0x10C },
+ { "MMCHS_RSP10", 0x110 },
+ { "MMCHS_RSP32", 0x114 },
+ { "MMCHS_RSP54", 0x118 },
+ { "MMCHS_RSP76", 0x11C },
+ { "MMCHS_DATA", 0x120 },
+ { "MMCHS_PSTATE", 0x124 },
+ { "MMCHS_HCTL", 0x128 },
+ { "MMCHS_SYSCTL", 0x12C },
+ { "MMCHS_STAT", 0x130 },
+ { "MMCHS_IE", 0x134 },
+ { "MMCHS_ISE", 0x138 },
+ { "MMCHS_AC12", 0x13C },
+ { "MMCHS_CAPA", 0x140 },
+ { "MMCHS_CUR_CAPA", 0x148 },
+ { NULL, 0x0 }
+};
+void
+ommmc_dump_regs(struct ommmc_softc *sc)
+{
+ int i;
+ for (i = 0; reglist[i].name != NULL; i++) {
+ printf("reg %s = %08x\n", reglist[i].name,
+ HREAD4(sc, reglist[i].off));
+ }
+}
+#endif
diff --git a/sys/arch/armv7/omap/omohci.c b/sys/arch/armv7/omap/omohci.c
new file mode 100644
index 00000000000..976a35bbef1
--- /dev/null
+++ b/sys/arch/armv7/omap/omohci.c
@@ -0,0 +1,353 @@
+/* $OpenBSD: omohci.c,v 1.1 2013/09/04 14:38:31 patrick 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/omapvar.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;
+ }
+
+ sc->sc.sc_child = config_found((void *)sc, &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(&sc->sc, 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/sys/arch/armv7/omap/omusbtll.c b/sys/arch/armv7/omap/omusbtll.c
new file mode 100644
index 00000000000..ba2daa7a75c
--- /dev/null
+++ b/sys/arch/armv7/omap/omusbtll.c
@@ -0,0 +1,175 @@
+/* $OpenBSD: omusbtll.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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 omap_attach_args *oa = args;
+ u_int32_t rev;
+
+ sc->sc_iot = oa->oa_iot;
+ if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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/sys/arch/armv7/omap/prcm.c b/sys/arch/armv7/omap/prcm.c
new file mode 100644
index 00000000000..c255c861962
--- /dev/null
+++ b/sys/arch/armv7/omap/prcm.c
@@ -0,0 +1,482 @@
+/* $OpenBSD: prcm.c,v 1.1 2013/09/04 14:38:31 patrick 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/omap/omapvar.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 omap_attach_args *oa = args;
+ struct prcm_softc *sc = (struct prcm_softc *) self;
+ u_int32_t reg;
+
+ sc->sc_iot = oa->oa_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, oa->oa_dev->mem[0].addr,
+ oa->oa_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, oa->oa_dev->mem[1].addr,
+ oa->oa_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, oa->oa_dev->mem[2].addr,
+ oa->oa_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)
+ sc->sc_setup(sc);
+
+ printf("\n");
+}
+
+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_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_MMC:
+ return PRCM_CLK_EN_MMC1;
+ case PRCM_USB:
+ return PRCM_CLK_EN_USB;
+ 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_MMC:
+ return PRCM_AM335X_MMC0_CLKCTRL;
+ case PRCM_USB:
+ return PRCM_AM335X_USB0_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_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;
+ 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", 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/sys/arch/armv7/omap/prcmvar.h b/sys/arch/armv7/omap/prcmvar.h
new file mode 100644
index 00000000000..c3070b4ac8e
--- /dev/null
+++ b/sys/arch/armv7/omap/prcmvar.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: prcmvar.h,v 1.1 2013/09/04 14:38:32 patrick 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_MMC,
+ PRCM_USB,
+ PRCM_USBTLL,
+ PRCM_USBP1_PHY,
+ PRCM_USBP1_UTMI,
+ PRCM_USBP1_HSIC,
+ PRCM_USBP2_PHY,
+ PRCM_USBP2_UTMI,
+ PRCM_USBP2_HSIC
+};
+
+#define PRCM_REG_MAX 6
+/* need interface for CM_AUTOIDLE */
diff --git a/sys/arch/armv7/omap/sitara_cm.c b/sys/arch/armv7/omap/sitara_cm.c
new file mode 100644
index 00000000000..4b493fb78d7
--- /dev/null
+++ b/sys/arch/armv7/omap/sitara_cm.c
@@ -0,0 +1,394 @@
+/* $OpenBSD: sitara_cm.c,v 1.1 2013/09/04 14:38:32 patrick 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/omap/omapvar.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 omap_attach_args *oa = aux;
+ uint32_t rev;
+
+ if (sitara_cm_sc)
+ panic("sitara_cm_attach: already attached");
+
+ sc->sc_iot = oa->oa_iot;
+
+ if (bus_space_map(oa->oa_iot, oa->oa_dev->mem[0].addr,
+ oa->oa_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/sys/arch/armv7/omap/sitara_cm.h b/sys/arch/armv7/omap/sitara_cm.h
new file mode 100644
index 00000000000..96be9673d0b
--- /dev/null
+++ b/sys/arch/armv7/omap/sitara_cm.h
@@ -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/sys/arch/armv7/omap/sitara_cmreg.h b/sys/arch/armv7/omap/sitara_cmreg.h
new file mode 100644
index 00000000000..65aeeeb53da
--- /dev/null
+++ b/sys/arch/armv7/omap/sitara_cmreg.h
@@ -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 */