diff options
Diffstat (limited to 'chip')
-rw-r--r-- | chip/it83xx/hwtimer.c | 18 | ||||
-rw-r--r-- | chip/it83xx/watchdog.c | 83 |
2 files changed, 101 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; +} |