diff options
-rw-r--r-- | board/arcada_ish/board.h | 4 | ||||
-rw-r--r-- | chip/ish/config_chip.h | 11 | ||||
-rw-r--r-- | chip/ish/registers.h | 18 | ||||
-rw-r--r-- | chip/ish/watchdog.c | 84 | ||||
-rw-r--r-- | core/minute-ia/interrupts.c | 1 |
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), |