summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu/arm926ejs/kirkwood/cpu.c75
-rw-r--r--include/asm-arm/arch-kirkwood/cpu.h2
2 files changed, 77 insertions, 0 deletions
diff --git a/cpu/arm926ejs/kirkwood/cpu.c b/cpu/arm926ejs/kirkwood/cpu.c
index 795a739..bab5faf 100644
--- a/cpu/arm926ejs/kirkwood/cpu.c
+++ b/cpu/arm926ejs/kirkwood/cpu.c
@@ -195,6 +195,78 @@ int kw_config_mpp(u32 mpp0_7, u32 mpp8_15, u32 mpp16_23, u32 mpp24_31,
return 0;
}
+/*
+ * SYSRSTn Duration Counter Support
+ *
+ * Kirkwood SoC implements a hardware-based SYSRSTn duration counter.
+ * When SYSRSTn is asserted low, a SYSRSTn duration counter is running.
+ * The SYSRSTn duration counter is useful for implementing a manufacturer
+ * or factory reset. Upon a long reset assertion that is greater than a
+ * pre-configured environment variable value for sysrstdelay,
+ * The counter value is stored in the SYSRSTn Length Counter Register
+ * The counter is based on the 25-MHz reference clock (40ns)
+ * It is a 29-bit counter, yielding a maximum counting duration of
+ * 2^29/25 MHz (21.4 seconds). When the counter reach its maximum value,
+ * it remains at this value until counter reset is triggered by setting
+ * bit 31 of KW_REG_SYSRST_CNT
+ */
+static void kw_sysrst_action(void)
+{
+ int ret;
+ char *s = getenv("sysrstcmd");
+
+ if (!s) {
+ debug("Error.. %s failed, check sysrstcmd\n",
+ __FUNCTION__);
+ return;
+ }
+
+ debug("Starting %s process...\n", __FUNCTION__);
+#if !defined(CONFIG_SYS_HUSH_PARSER)
+ ret = run_command (s, 0);
+#else
+ ret = parse_string_outer(s, FLAG_PARSE_SEMICOLON
+ | FLAG_EXIT_FROM_LOOP);
+#endif
+ if (ret < 0)
+ debug("Error.. %s failed\n", __FUNCTION__);
+ else
+ debug("%s process finished\n", __FUNCTION__);
+}
+
+static void kw_sysrst_check(void)
+{
+ u32 sysrst_cnt, sysrst_dly;
+ char *s;
+
+ /*
+ * no action if sysrstdelay environment variable is not defined
+ */
+ s = getenv("sysrstdelay");
+ if (s == NULL)
+ return;
+
+ /* read sysrstdelay value */
+ sysrst_dly = (u32) simple_strtoul(s, NULL, 10);
+
+ /* read SysRst Length counter register (bits 28:0) */
+ sysrst_cnt = (0x1fffffff & readl(KW_REG_SYSRST_CNT));
+ debug("H/w Rst hold time: %d.%d secs\n",
+ sysrst_cnt / SYSRST_CNT_1SEC_VAL,
+ sysrst_cnt % SYSRST_CNT_1SEC_VAL);
+
+ /* clear the counter for next valid read*/
+ writel(1 << 31, KW_REG_SYSRST_CNT);
+
+ /*
+ * sysrst_action:
+ * if H/w Reset key is pressed and hold for time
+ * more than sysrst_dly in seconds
+ */
+ if (sysrst_cnt >= SYSRST_CNT_1SEC_VAL * sysrst_dly)
+ kw_sysrst_action();
+}
+
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
@@ -298,6 +370,9 @@ int arch_misc_init(void)
temp = get_cr();
set_cr(temp & ~CR_V);
+ /* checks and execute resset to factory event */
+ kw_sysrst_check();
+
return 0;
}
#endif /* CONFIG_ARCH_MISC_INIT */
diff --git a/include/asm-arm/arch-kirkwood/cpu.h b/include/asm-arm/arch-kirkwood/cpu.h
index d1440af..b3022a3 100644
--- a/include/asm-arm/arch-kirkwood/cpu.h
+++ b/include/asm-arm/arch-kirkwood/cpu.h
@@ -36,6 +36,8 @@
((_x ? KW_EGIGA0_BASE : KW_EGIGA1_BASE) + 0x44c)
#define KW_REG_DEVICE_ID (KW_MPP_BASE + 0x34)
+#define KW_REG_SYSRST_CNT (KW_MPP_BASE + 0x50)
+#define SYSRST_CNT_1SEC_VAL (25*1000000)
#define KW_REG_MPP_OUT_DRV_REG (KW_MPP_BASE + 0xE0)
enum memory_bank {