diff options
author | Simon Glass <sjg@chromium.org> | 2012-06-03 07:55:51 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-06-15 13:39:22 -0700 |
commit | 8db2c7f910661661b3dfb67fb2eb99a16ee14de5 (patch) | |
tree | c14fb08148cee74a8dbad53c365a525313b9db0f /chip/stm32/watchdog.c | |
parent | 9f2e621d8032199b727918f04430d5cd0951c0c3 (diff) | |
download | chrome-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>
Diffstat (limited to 'chip/stm32/watchdog.c')
-rw-r--r-- | chip/stm32/watchdog.c | 46 |
1 files changed, 45 insertions, 1 deletions
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; } |