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>
This commit is contained in:
Alec Berg
2013-11-20 11:38:11 -08:00
committed by chrome-internal-fetch
parent 727053a376
commit 5edde63ac2
3 changed files with 107 additions and 0 deletions

View File

@@ -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);

83
chip/it83xx/watchdog.c Normal file
View File

@@ -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;
}

View File

@@ -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);