summaryrefslogtreecommitdiff
path: root/chip/mchp/watchdog.c
diff options
context:
space:
mode:
authorScott Worley <scott.worley@microchip.corp-partner.google.com>2020-12-19 10:30:25 -0500
committerCommit Bot <commit-bot@chromium.org>2021-02-10 02:27:46 +0000
commit9cf67b7e5bc8ba1660569f30ae4fa8da1c1c2cd5 (patch)
treeb3730bd68724c687459e830027d07d48a08197af /chip/mchp/watchdog.c
parentf690ffc357a4421d2b4a62e8cd774627aba0e022 (diff)
downloadchrome-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.c90
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) */