summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-06-03 07:55:51 -0700
committerGerrit <chrome-bot@google.com>2012-06-15 13:39:22 -0700
commit8db2c7f910661661b3dfb67fb2eb99a16ee14de5 (patch)
treec14fb08148cee74a8dbad53c365a525313b9db0f
parent9f2e621d8032199b727918f04430d5cd0951c0c3 (diff)
downloadchrome-ec-8db2c7f910661661b3dfb67fb2eb99a16ee14de5.tar.gz
stm32: Add an early warning of watchdog firing
Rather than just reset with no information when we hit a watchdog, try to anticipate the problem and display a trace message as on lm4. This solution is not ideal since we must constantly reset the WWDG to make it work. It may be better to look at dedicating a timer to this purpose instead, since we are really just shadowing the IWDG and don't actually need the reset functionality. One problem is that we now have a fairly short time limit on many operations, since if we can't service an interrupt within about 30ms then the WWDG will reset the system. It also affects JTAG since it seems that the watchdog goes off the first time JTAG is invoked to program the flash. The solution here is to retry. For these reasons it is implemented as an option, CONFIG_WATCHDOG_HELP. BUG=chrome-os-partner:10145 TEST=manual: build for all boards On snow: > waitms 500 See that there is no message > waitms 1300 Time: 0x0000000000733ba3 us Deadline: 0x00000000006b6db2 -> -0.511473 s from now Active timers: Task Ready Name Events Time (s) 0 R << idle >> 00000000 0.000000 1 R WATCHDOG 80000000 0.000000 2 KEYSCAN 00000000 0.000000 3 GAIAPOWER 00000000 0.000000 4 R CONSOLE 00000000 0.000000 5 HOSTCMD 00000000 0.000000 --- UART initialized after reboot --- [Reset cause: watchdog] [Image: RO, snow_v1.1.32-8c00326-dirty 2012-06-03 07:54:29 sjg@sglass.mtv.corp.google.com] done Change-Id: I042fcc9ecd9c21210ea3826ca69c943aab949d1f Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/24398 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--README10
-rw-r--r--chip/stm32/registers.h3
-rw-r--r--chip/stm32/watchdog.c46
3 files changed, 58 insertions, 1 deletions
diff --git a/README b/README
index 9f8a5c3b8c..00aa6662b1 100644
--- a/README
+++ b/README
@@ -24,3 +24,13 @@ by Google. See below diagram for architecture.
| driverlib. |
+--------------------+
+
+
+Build Options
+=============
+
+- CONFIG_WATCHDOG_HELP
+
+ Try to detect a watchdog that is about to fire, and print a trace.
+ This is needed on STM32, where the independent watchdog has no early
+ warning feature and the windowed watchdog has a very short period.
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index d06538c7e2..e11364f60c 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -333,6 +333,9 @@ static inline uint16_t *stm32_i2c_reg(int port, int offset)
#define STM32_WWDG_CFR REG32(STM32_WWDG_BASE + 0x04)
#define STM32_WWDG_SR REG32(STM32_WWDG_BASE + 0x08)
+#define STM32_WWDG_TB_8 (3 << 7)
+#define STM32_WWDG_EWI (1 << 9)
+
#define STM32_IWDG_BASE 0x40003000
#define STM32_IWDG_KR REG32(STM32_IWDG_BASE + 0x00)
diff --git a/chip/stm32/watchdog.c b/chip/stm32/watchdog.c
index 1fd84b2f43..a25e2576ca 100644
--- a/chip/stm32/watchdog.c
+++ b/chip/stm32/watchdog.c
@@ -26,11 +26,31 @@
#define IWDG_PRESCALER 6
#define IWDG_PRESCALER_DIV (1 << ((IWDG_PRESCALER) + 2))
+/*
+ * We use the WWDG as an early warning for the real watchdog, which just
+ * resets. Since it has a very short period, we need to allow several cycles
+ * of this to make up one IWDG cycle. The WWDG's early warning kicks in
+ * half way through the cycle, with a maximum time of 65.54ms at 32 MHz.
+ */
+#define WATCHDOG_CYCLES_BEFORE_RESET \
+ (WATCHDOG_PERIOD_MS / (65540 * 32000 / CPU_CLOCK))
+
+/* Keep a track of how many WWDG cycles we have had */
+static unsigned int watchdog_count;
+
+
+static void watchdog_reset_count(void)
+{
+ watchdog_count = WATCHDOG_CYCLES_BEFORE_RESET;
+}
+
void watchdog_reload(void)
{
/* Reload the watchdog */
STM32_IWDG_KR = 0xaaaa;
+
+ watchdog_reset_count();
}
@@ -44,7 +64,17 @@ void watchdog_reload(void)
*/
void watchdog_check(uint32_t excep_lr, uint32_t excep_sp)
{
- /* This is not actually called for now, since we reset instead */
+ /* Reset the windowed watchdog here */
+ STM32_WWDG_CR = 0xff;
+ STM32_WWDG_SR = 0;
+
+ /* If the count has expired, output a trace */
+ if (!--watchdog_count) {
+ /* Reset here, to give the UART enough time to send trace */
+ watchdog_reset_count();
+ watchdog_trace(excep_lr, excep_sp);
+ watchdog_reset_count();
+ }
}
@@ -86,5 +116,19 @@ int watchdog_init(void)
/* Start the watchdog (and re-lock registers) */
STM32_IWDG_KR = 0xcccc;
+ watchdog_reset_count();
+
+#ifdef CONFIG_WATCHDOG_HELP
+ /* enable clock */
+ STM32_RCC_APB1ENR |= 1 << 11;
+
+ STM32_WWDG_SR = 0;
+ STM32_WWDG_CR = 0xff;
+ STM32_WWDG_CFR = 0x7f | STM32_WWDG_TB_8 | STM32_WWDG_EWI;
+
+ /* Enable watchdog interrupt */
+ task_enable_irq(IRQ_WATCHDOG);
+#endif
+
return EC_SUCCESS;
}