summaryrefslogtreecommitdiff
path: root/chip/ish/watchdog.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2019-03-14 13:14:15 -0600
committerchrome-bot <chrome-bot@chromium.org>2019-03-26 04:44:00 -0700
commit9a5a7225737051e9523a775ebf8bba63f144259b (patch)
tree4c604846f721c564c9dd966d7e5184230805c243 /chip/ish/watchdog.c
parent5555323902f965a6e489e797f0e156d460e62d67 (diff)
downloadchrome-ec-9a5a7225737051e9523a775ebf8bba63f144259b.tar.gz
ish: Add watchdog timer
This adds support for the watchdog timer (WDT) available on Intel Sensor Hub (ISH). The ISH will reset after T1 expires; see the comments at the top of watchdog.c for further information on this design decision. Originally, we had planned to implement a counter that would disable the WDT after N failures. This was abandoned, since the register used to store the counter was not able to maintain a value across reset on a reliable basis (see b:128679825). BUG=b:127980538,b:128679825 BRANCH=none TEST=Used waitms command on arcada to verify WDT triggered a warning IRQ after T1 and reset the system. Change-Id: I4bd16c253110d60c57eb24cda2abc0facee20748 Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1526316 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'chip/ish/watchdog.c')
-rw-r--r--chip/ish/watchdog.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/chip/ish/watchdog.c b/chip/ish/watchdog.c
new file mode 100644
index 0000000000..fd0ebcf247
--- /dev/null
+++ b/chip/ish/watchdog.c
@@ -0,0 +1,84 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Watchdog Timer
+ *
+ * In ISH, there is a watchdog timer available from the hardware. It is
+ * controlled by a few registers:
+ *
+ * - WDT_CONTROL (consists of enable bit, T1, and T2 values): When T1
+ * reaches 0, a warning is fired. After T2 then reaches 0, the system
+ * will reset.
+ * - WDT_RELOAD: Pet the watchdog by setting to 1
+ * - WDT_VALUES: Gives software access to T1 and T2 if needed
+ *
+ * For ISH implementation, we wish to reset only the ISH. Waiting until
+ * T2 expires will kill the whole system. The functionality of T2 is
+ * ignored, and we simply call system_reset when T1 expires. T2 will
+ * only be used if the system cannot reset when T1 expires.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "task.h"
+#include "registers.h"
+#include "system.h"
+#include "watchdog.h"
+
+/* Units are hundreds of milliseconds */
+#define WDT_T1_PERIOD (100) /* 10 seconds */
+#define WDT_T2_PERIOD (10) /* 1 second */
+
+int watchdog_init(void)
+{
+ /* Initialize WDT clock divider */
+ CCU_WDT_CD = WDT_CLOCK_HZ / 10; /* 10 Hz => 100 ms period */
+
+ /* Enable the watchdog timer and set initial T1/T2 values */
+ WDT_CONTROL = WDT_CONTROL_ENABLE_BIT
+ | (WDT_T2_PERIOD << 8)
+ | WDT_T1_PERIOD;
+
+ task_enable_irq(ISH_WDT_IRQ);
+
+ return EC_SUCCESS;
+}
+
+/* Parameters are pushed by hardware, we only care about %EIP */
+__attribute__ ((noreturn))
+void watchdog_warning(uint32_t errorcode,
+ uint32_t eip,
+ uint32_t cs,
+ uint32_t eflags)
+{
+ ccprintf("\nWDT Expired. EIP was 0x%08X. Resetting...\n", eip);
+ cflush();
+
+ system_reset(SYSTEM_RESET_AP_WATCHDOG);
+ __builtin_unreachable();
+}
+
+__attribute__ ((noreturn))
+void watchdog_warning_irq(void)
+{
+ /*
+ * Parameters to watchdog_warning were pushed by hardware, use
+ * asm here to re-use these parameters in the call.
+ */
+ __asm__ ("call watchdog_warning\n");
+ __builtin_unreachable();
+}
+DECLARE_IRQ(ISH_WDT_IRQ, watchdog_warning_irq);
+
+void watchdog_reload(void)
+{
+ /*
+ * ISH Supplemental Registers Info, 1.2.6.2:
+ * "When firmware writes a 1 to this bit, hardware reloads
+ * the values in WDT_T1 and WDT_T2..."
+ */
+ WDT_RELOAD = 1;
+}
+DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);