diff options
author | Scott Worley <scott.worley@microchip.corp-partner.google.com> | 2020-12-19 10:30:25 -0500 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-02-10 02:27:46 +0000 |
commit | 9cf67b7e5bc8ba1660569f30ae4fa8da1c1c2cd5 (patch) | |
tree | b3730bd68724c687459e830027d07d48a08197af /chip/mchp/watchdog.c | |
parent | f690ffc357a4421d2b4a62e8cd774627aba0e022 (diff) | |
download | chrome-ec-9cf67b7e5bc8ba1660569f30ae4fa8da1c1c2cd5.tar.gz |
mchp: MEC152X watchdog interrupt support
MEC152X watchdog timer can fire an EC interrupt. Update
watchdog code to use EC interrupt and not use 16-bit timer
used for MEC170X.
BRANCH=none
BUG=b:177463787
TEST=Booted skylake RVP to Chrome OS
Signed-off-by: Scott Worley <scott.worley@microchip.corp-partner.google.com>
Change-Id: I16ed7c6e7140f6d3fbda190e3bcb0565ce13e70f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2601206
Reviewed-by: Ravin Kumar <ravin.kumar@microchip.com>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Reviewed-by: Vijay P Hiremath <vijay.p.hiremath@intel.com>
Tested-by: Ravin Kumar <ravin.kumar@microchip.com>
Diffstat (limited to 'chip/mchp/watchdog.c')
-rw-r--r-- | chip/mchp/watchdog.c | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/chip/mchp/watchdog.c b/chip/mchp/watchdog.c index 0533155e08..f7e47ee3b7 100644 --- a/chip/mchp/watchdog.c +++ b/chip/mchp/watchdog.c @@ -24,6 +24,21 @@ void watchdog_reload(void) } DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT); +/* + * MEC1701 WDG asserts chip reset on LOAD count expiration. + * WDG interrupt is simulated using a 16-bit general purpose + * timer whose period is sufficiently less that the WDG timeout + * period allowing watchdog trace data to be saved. + * + * MEC152x adds interrupt capability to the WDT. + * Enable MEC152x WDG interrupt. WDG event will assert + * IRQ and kick itself starting another LOAD timeout. + * After the new LOAD expires WDG will assert chip reset. + * The WDG ISR calls watchdog trace save API, upon return we + * enter a spin loop waiting for the LOAD period to expire. + * WDG does not have a way to trigger an immediate reset except + * by re-programming it. + */ int watchdog_init(void) { #ifdef CONFIG_WATCHDOG_HELP @@ -65,6 +80,7 @@ int watchdog_init(void) MCHP_TMR16_CNT(0) = CONFIG_AUX_TIMER_PERIOD_MS; MCHP_TMR16_CNT(0) |= BIT(5); #endif + MCHP_WDG_CTL = 0; /* Clear WDT PCR sleep enable */ MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_WDT); @@ -72,22 +88,78 @@ int watchdog_init(void) /* Set timeout. It takes 1007us to decrement WDG_CNT by 1. */ MCHP_WDG_LOAD = CONFIG_WATCHDOG_PERIOD_MS * 1000 / 1007; +#if defined(CHIP_FAMILY_MEC152X) + MCHP_WDG_STATUS = MCHP_WDG_STS_IRQ; + MCHP_WDG_IEN = MCHP_WDG_IEN_IRQ_EN; + MCHP_WDG_CTL |= MCHP_WDG_RESET_IRQ_EN; + MCHP_INT_ENABLE(MCHP_WDG_GIRQ) = MCHP_WDG_GIRQ_BIT; + task_enable_irq(MCHP_IRQ_WDG); +#endif + /* Start watchdog */ #ifdef CONFIG_CHIPSET_DEBUG /* WDT will not count if JTAG TRST# is pulled high by JTAG cable */ - MCHP_WDG_CTL = BIT(4) | BIT(0); + MCHP_WDG_CTL = MCHP_WDT_CTL_ENABLE | MCHP_WDT_CTL_JTAG_STALL_EN; #else - MCHP_WDG_CTL |= 1; + MCHP_WDG_CTL |= MCHP_WDT_CTL_ENABLE; #endif return EC_SUCCESS; } -#ifdef CONFIG_WATCHDOG_HELP +/* MEC152x Watchdog can fire an interrupt to CPU before system reset */ +#if defined(CHIP_FAMILY_MEC152X) + void __keep watchdog_check(uint32_t excep_lr, uint32_t excep_sp) { - trace0(0, WDT, 0, "Watchdog check from 16-bit basic timer0 ISR"); + /* Clear WDG first then aggregator */ + MCHP_WDG_STATUS = MCHP_WDG_STS_IRQ; + MCHP_INT_SOURCE(MCHP_WDG_GIRQ) = MCHP_WDG_GIRQ_BIT; + + /* Cause WDG to reload again. */ + MCHP_WDG_KICK = 1; + + watchdog_trace(excep_lr, excep_sp); + + /* Reset system by re-programing WDT to trigger after 2 32KHz clocks */ + MCHP_WDG_CTL = 0; /* clear enable to allow write to load register */ + MCHP_WDG_LOAD = 2; + MCHP_WDG_CTL |= MCHP_WDT_CTL_ENABLE; + +} + +/* ISR for watchdog warning naked will keep SP & LR */ +void +IRQ_HANDLER(MCHP_IRQ_WDG)(void) __keep __attribute__((naked)); +void IRQ_HANDLER(MCHP_IRQ_WDG)(void) +{ + /* Naked call so we can extract raw LR and SP */ + asm volatile("mov r0, lr\n" + "mov r1, sp\n" + /* + * Must push registers in pairs to keep 64-bit aligned + * stack for ARM EABI. This also conveninently saves + * R0=LR so we can pass it to task_resched_if_needed. + */ + "push {r0, lr}\n" + "bl watchdog_check\n" + "pop {r0, lr}\n" + "b task_resched_if_needed\n"); +} +/* put the watchdog at the highest priority */ +const struct irq_priority __keep IRQ_PRIORITY(MCHP_IRQ_WDG) +__attribute__((section(".rodata.irqprio"))) += {MCHP_IRQ_WDG, 0}; + +#else +/* + * MEC1701 watchdog only resets. Use a 16-bit timer to fire in interrupt + * for saving watchdog trace. + */ +#ifdef CONFIG_WATCHDOG_HELP +void __keep watchdog_check(uint32_t excep_lr, uint32_t excep_sp) +{ /* Clear status */ MCHP_TMR16_STS(0) |= 1; /* clear aggregator status */ @@ -114,10 +186,10 @@ void IRQ_HANDLER(MCHP_IRQ_TIMER16_0)(void) "b task_resched_if_needed\n"); } -/* - * Put the watchdog at the highest interrupt priority. - */ -const struct irq_priority __keep IRQ_PRIORITY(MEC1322_IRQ_TIMER16_0) +/* Put the watchdog at the highest interrupt priority. */ +const struct irq_priority __keep IRQ_PRIORITY(MCHP_IRQ_TIMER16_0) __attribute__((section(".rodata.irqprio"))) = {MCHP_IRQ_TIMER16_0, 0}; -#endif + +#endif /* #ifdef CONFIG_WATCHDOG_HELP */ +#endif /* #if defined(CHIP_FAMILY_MEC152X) */ |