summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2013-11-20 11:38:11 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-01-15 04:52:40 +0000
commit5edde63ac253c98ddb8a5c8584b766f09336d49c (patch)
tree5c4af6a0f63fecc638faec3d9123dce2fad75023
parent727053a3761b52a60c94c9cfc75d2f842595cc55 (diff)
downloadchrome-ec-5edde63ac253c98ddb8a5c8584b766f09336d49c.tar.gz
ite: Watchdog module added
Watchdog module added. Off by default because of following limitations: - When programming, the WD fires, and programming fails. For now, you have to program twice. BRANCH=none BUG=chrome-os-partner:23575 TEST=Manually wrote in a while(1); and made sure watchdog warning triggers first, prints IPC register, and then soon after the watchdog timer resets the chip. Signed-off-by: Alec Berg <alecaberg@chromium.org> Change-Id: Ia83f58f3ae108f755d2f139ada22a22e2fbdc2fa Reviewed-on: https://chromium-review.googlesource.com/177397 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/it83xx/hwtimer.c18
-rw-r--r--chip/it83xx/watchdog.c83
-rw-r--r--include/watchdog.h6
3 files changed, 107 insertions, 0 deletions
diff --git a/chip/it83xx/hwtimer.c b/chip/it83xx/hwtimer.c
index cf4de26be8..3493843adc 100644
--- a/chip/it83xx/hwtimer.c
+++ b/chip/it83xx/hwtimer.c
@@ -13,6 +13,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "watchdog.h"
/* 128us (2^7 us) between 2 ticks */
#define TICK_INTERVAL_LOG2 7
@@ -64,6 +65,11 @@ void __hw_clock_source_set(uint32_t ts)
static void __hw_clock_source_irq(void)
{
+#ifdef CONFIG_WATCHDOG
+ /* Determine interrupt number. */
+ int irq = IT83XX_INTC_IVCT3 - 16;
+#endif
+
/*
* If this is a SW interrupt, then process the timers, but don't
* increment the time_us.
@@ -73,6 +79,18 @@ static void __hw_clock_source_irq(void)
return;
}
+#ifdef CONFIG_WATCHDOG
+ /*
+ * Both the external timer for the watchdog warning and the HW timer
+ * go through this irq. So, if this interrupt was caused by watchdog
+ * warning timer, then call that function.
+ */
+ if (irq == IT83XX_IRQ_EXT_TIMER3) {
+ watchdog_warning_irq();
+ return;
+ }
+#endif
+
/* clear interrupt status */
task_clear_pending_irq(IT83XX_IRQ_TMR_B0);
diff --git a/chip/it83xx/watchdog.c b/chip/it83xx/watchdog.c
new file mode 100644
index 0000000000..d22a3da538
--- /dev/null
+++ b/chip/it83xx/watchdog.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2013 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 driver */
+
+#include "common.h"
+#include "cpu.h"
+#include "hooks.h"
+#include "panic.h"
+#include "registers.h"
+#include "task.h"
+#include "watchdog.h"
+
+/*
+ * We use timer3 to trigger an interrupt just before the watchdog timer
+ * will fire so that we can capture important state information before
+ * being reset.
+ */
+
+/* Magic value to tickle the watchdog register. */
+#define ITE83XX_WATCHDOG_MAGIC_WORD 0x5C
+
+void watchdog_warning_irq(void)
+{
+ /* clear interrupt status */
+ task_clear_pending_irq(IT83XX_IRQ_EXT_TIMER3);
+
+ /* Reset warning timer (timer 3). */
+ IT83XX_ETWD_ET3CTRL = 0x03;
+
+ panic_printf("Pre-watchdog warning! IPC: %08x\n", get_ipc());
+}
+
+void watchdog_reload(void)
+{
+ /* Reset warning timer (timer 3). */
+ IT83XX_ETWD_ET3CTRL = 0x03;
+
+ /* Restart (tickle) watchdog timer. */
+ IT83XX_ETWD_EWDKEYR = ITE83XX_WATCHDOG_MAGIC_WORD;
+}
+DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);
+
+int watchdog_init(void)
+{
+ /* Unlock access to watchdog registers. */
+ IT83XX_ETWD_ETWCFG = 0x00;
+
+ /* Set timer 3 and WD timer to use 1.024kHz clock. */
+ IT83XX_ETWD_ET3PSR = 0x01;
+ IT83XX_ETWD_ET1PSR = 0x01;
+
+ /* Set WDT key match enabled and WDT clock to use ET1PSR. */
+ IT83XX_ETWD_ETWCFG = 0x30;
+
+ /* Specify that watchdog cannot be stopped. */
+ IT83XX_ETWD_ETWCTRL = 0x00;
+
+ /* Set timer 3 load value to 1024 (~1.05 seconds). */
+ IT83XX_ETWD_ET3CNTLH2R = 0x00;
+ IT83XX_ETWD_ET3CNTLHR = 0x04;
+ IT83XX_ETWD_ET3CNTLLR = 0x00;
+
+ /* Enable interrupt on timer 3 expiration. */
+ task_enable_irq(IT83XX_IRQ_EXT_TIMER3);
+
+ /* Start timer 3. */
+ IT83XX_ETWD_ET3CTRL = 0x03;
+
+ /* Start timer 1 (must be started for watchdog timer to run). */
+ IT83XX_ETWD_ET1CNTLLR = 0x00;
+
+ /* Set watchdog timer to ~1.3 seconds. Writing CNTLL starts timer. */
+ IT83XX_ETWD_EWDCNTLHR = 0x05;
+ IT83XX_ETWD_EWDCNTLLR = 0x00;
+
+ /* Lock access to watchdog registers. */
+ IT83XX_ETWD_ETWCFG = 0x3f;
+
+ return EC_SUCCESS;
+}
diff --git a/include/watchdog.h b/include/watchdog.h
index 02c603ca40..1981e3ce10 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -31,6 +31,12 @@ int watchdog_init(void);
*/
void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp);
+/**
+ * Watchdog has not been tickled recently warning. This function should be
+ * called when the watchdog is close to firing.
+ */
+void watchdog_warning_irq(void);
+
/* Reload the watchdog counter */
#ifdef CONFIG_WATCHDOG
void watchdog_reload(void);