summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/arcada_ish/board.h4
-rw-r--r--chip/ish/config_chip.h11
-rw-r--r--chip/ish/registers.h18
-rw-r--r--chip/ish/watchdog.c84
-rw-r--r--core/minute-ia/interrupts.c1
5 files changed, 113 insertions, 5 deletions
diff --git a/board/arcada_ish/board.h b/board/arcada_ish/board.h
index 54676661e4..6ab130bb68 100644
--- a/board/arcada_ish/board.h
+++ b/board/arcada_ish/board.h
@@ -76,10 +76,6 @@
#undef CONFIG_FLASH
#undef CONFIG_FMAP
#undef CONFIG_SWITCH
-/* TODO: Watch Dog is supported but temporarily removed. Currently under
- * development on KBL and will be carried over to WHL.
- */
-#undef CONFIG_WATCHDOG
/* Modules we want to exclude */
#undef CONFIG_CMD_HASH
diff --git a/chip/ish/config_chip.h b/chip/ish/config_chip.h
index c595e825b9..d10ee650d6 100644
--- a/chip/ish/config_chip.h
+++ b/chip/ish/config_chip.h
@@ -67,6 +67,17 @@
#include "config_flash_layout.h"
+/*****************************************************************************/
+/* Watchdog Timer Configuration */
+/*****************************************************************************/
+#if defined(CHIP_FAMILY_ISH3) || defined(CHIP_FAMILY_ISH5)
+#define WDT_CLOCK_HZ (120000000) /* 120 MHz */
+#elif defined(CHIP_FAMILY_ISH4)
+#define WDT_CLOCK_HZ (100000000) /* 100 MHz */
+#else
+#error "CHIP_FAMILY_ISH(3|4|5) must be defined"
+#endif
+
/****************************************************************************/
/* Customize the build */
/* Optional features present on this chip */
diff --git a/chip/ish/registers.h b/chip/ish/registers.h
index 9106463356..834dc63b72 100644
--- a/chip/ish/registers.h
+++ b/chip/ish/registers.h
@@ -40,6 +40,7 @@ enum ish_i2c_port {
#define ISH_PMU_BASE 0x00800000
#define ISH_CCU_BASE 0x00900000
#define ISH_IPC_BASE 0x00B00000
+#define ISH_WDT_BASE 0xFDE00000
#define ISH_IOAPIC_BASE 0xFEC00000
#define ISH_HPET_BASE 0xFED00000
#define ISH_LAPIC_BASE 0xFEE00000
@@ -48,6 +49,7 @@ enum ish_i2c_port {
#define ISH_I2C0_IRQ 0
#define ISH_I2C1_IRQ 1
#define ISH_I2C2_IRQ 40
+#define ISH_WDT_IRQ 6
#define ISH_GPIO_IRQ 7
#define ISH_HPET_TIMER0_IRQ 55
#define ISH_HPET_TIMER1_IRQ 8
@@ -90,6 +92,7 @@ enum ish_i2c_port {
#define ISH_I2C0_VEC IRQ_TO_VEC(ISH_I2C0_IRQ)
#define ISH_I2C1_VEC IRQ_TO_VEC(ISH_I2C1_IRQ)
#define ISH_I2C2_VEC IRQ_TO_VEC(ISH_I2C2_IRQ)
+#define ISH_WDT_VEC IRQ_TO_VEC(ISH_WDT_IRQ)
#define ISH_GPIO_VEC IRQ_TO_VEC(ISH_GPIO_IRQ)
#define ISH_HPET_TIMER0_VEC IRQ_TO_VEC(ISH_HPET_TIMER0_IRQ)
#define ISH_HPET_TIMER1_VEC IRQ_TO_VEC(ISH_HPET_TIMER1_IRQ)
@@ -135,10 +138,17 @@ enum ish_i2c_port {
/* CCU Registers */
#define CCU_TCG_EN REG32(ISH_CCU_BASE + 0x0)
#define CCU_BCG_EN REG32(ISH_CCU_BASE + 0x4)
-#define CCU_RST_HST REG32(ISH_CCU_BASE + 0x34)
+#define CCU_WDT_CD REG32(ISH_CCU_BASE + 0x8)
+#define CCU_RST_HST REG32(ISH_CCU_BASE + 0x34) /* Reset history */
#define CCU_TCG_ENABLE REG32(ISH_CCU_BASE + 0x38)
#define CCU_BCG_ENABLE REG32(ISH_CCU_BASE + 0x3c)
+/* Bitmasks for CCU_RST_HST */
+#define CCU_SW_RST (1 << 0) /* Used to indicate SW reset */
+#define CCU_WDT_RST (1 << 1) /* Used to indicate WDT reset */
+#define CCU_MIASS_RST (1 << 2) /* Used to indicate UIA shutdown reset */
+#define CCU_SRECC_RST (1 << 3) /* Used to indicate SRAM ECC reset */
+
/* CSME Registers */
#define ISH_RST_REG REG32(ISH_IPC_BASE + 0x44)
@@ -158,6 +168,12 @@ enum ish_i2c_port {
#define IOAPIC_REDTBL_TRIGGER_LEVEL 0x00008000
#define IOAPIC_REDTBL_MASK 0x00010000
+/* WDT (Watchdog Timer) Registers */
+#define WDT_CONTROL REG32(ISH_WDT_BASE + 0x0)
+#define WDT_RELOAD REG32(ISH_WDT_BASE + 0x4)
+#define WDT_VALUES REG32(ISH_WDT_BASE + 0x8)
+#define WDT_CONTROL_ENABLE_BIT (1 << 17)
+
/* LAPIC registers */
#define LAPIC_EOI_REG 0xFEE000B0
#define LAPIC_ISR_REG 0xFEE00170
diff --git a/chip/ish/watchdog.c b/chip/ish/watchdog.c
new file mode 100644
index 0000000000..fd0ebcf247
--- /dev/null
+++ b/chip/ish/watchdog.c
@@ -0,0 +1,84 @@
+/* Copyright 2019 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 Timer
+ *
+ * In ISH, there is a watchdog timer available from the hardware. It is
+ * controlled by a few registers:
+ *
+ * - WDT_CONTROL (consists of enable bit, T1, and T2 values): When T1
+ * reaches 0, a warning is fired. After T2 then reaches 0, the system
+ * will reset.
+ * - WDT_RELOAD: Pet the watchdog by setting to 1
+ * - WDT_VALUES: Gives software access to T1 and T2 if needed
+ *
+ * For ISH implementation, we wish to reset only the ISH. Waiting until
+ * T2 expires will kill the whole system. The functionality of T2 is
+ * ignored, and we simply call system_reset when T1 expires. T2 will
+ * only be used if the system cannot reset when T1 expires.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "task.h"
+#include "registers.h"
+#include "system.h"
+#include "watchdog.h"
+
+/* Units are hundreds of milliseconds */
+#define WDT_T1_PERIOD (100) /* 10 seconds */
+#define WDT_T2_PERIOD (10) /* 1 second */
+
+int watchdog_init(void)
+{
+ /* Initialize WDT clock divider */
+ CCU_WDT_CD = WDT_CLOCK_HZ / 10; /* 10 Hz => 100 ms period */
+
+ /* Enable the watchdog timer and set initial T1/T2 values */
+ WDT_CONTROL = WDT_CONTROL_ENABLE_BIT
+ | (WDT_T2_PERIOD << 8)
+ | WDT_T1_PERIOD;
+
+ task_enable_irq(ISH_WDT_IRQ);
+
+ return EC_SUCCESS;
+}
+
+/* Parameters are pushed by hardware, we only care about %EIP */
+__attribute__ ((noreturn))
+void watchdog_warning(uint32_t errorcode,
+ uint32_t eip,
+ uint32_t cs,
+ uint32_t eflags)
+{
+ ccprintf("\nWDT Expired. EIP was 0x%08X. Resetting...\n", eip);
+ cflush();
+
+ system_reset(SYSTEM_RESET_AP_WATCHDOG);
+ __builtin_unreachable();
+}
+
+__attribute__ ((noreturn))
+void watchdog_warning_irq(void)
+{
+ /*
+ * Parameters to watchdog_warning were pushed by hardware, use
+ * asm here to re-use these parameters in the call.
+ */
+ __asm__ ("call watchdog_warning\n");
+ __builtin_unreachable();
+}
+DECLARE_IRQ(ISH_WDT_IRQ, watchdog_warning_irq);
+
+void watchdog_reload(void)
+{
+ /*
+ * ISH Supplemental Registers Info, 1.2.6.2:
+ * "When firmware writes a 1 to this bit, hardware reloads
+ * the values in WDT_T1 and WDT_T2..."
+ */
+ WDT_RELOAD = 1;
+}
+DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);
diff --git a/core/minute-ia/interrupts.c b/core/minute-ia/interrupts.c
index 98c6c3509d..dab6ab5e99 100644
--- a/core/minute-ia/interrupts.c
+++ b/core/minute-ia/interrupts.c
@@ -91,6 +91,7 @@ static const irq_desc_t system_irqs[] = {
LEVEL_INTR(ISH_I2C0_IRQ, ISH_I2C0_VEC),
LEVEL_INTR(ISH_I2C1_IRQ, ISH_I2C1_VEC),
LEVEL_INTR(ISH_I2C2_IRQ, ISH_I2C2_VEC),
+ LEVEL_INTR(ISH_WDT_IRQ, ISH_WDT_VEC),
LEVEL_INTR(ISH_GPIO_IRQ, ISH_GPIO_VEC),
LEVEL_INTR(ISH_IPC_HOST2ISH_IRQ, ISH_IPC_VEC),
LEVEL_INTR(ISH_IPC_ISH2HOST_CLR_IRQ, ISH_IPC_ISH2HOST_CLR_VEC),