From d1acf70afd376b45a73b325ee30c0532a142c4f2 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 16 Sep 2020 13:25:36 -0700 Subject: [PATCH] Add WDT to u-boot to cover booting failures This commit enables WDT1 in early u-boot and before loading kernel image to make BMC reset to cover booting failures. If BMC meets any failure or if kernel can't initiate watchdog timer properly, BMC will be reset by this watchdog. Signed-off-by: Jae Hyun Yoo --- arch/arm/mach-aspeed/ast2600/platform.S | 15 +++++ board/aspeed/ast2600_intel/intel.c | 50 ++++++++++++++-- common/board_f.c | 1 + common/image.c | 3 +- drivers/mtd/spi/spi-nor-core.c | 5 ++ drivers/watchdog/ast_wdt.c | 78 ++++++++++++++----------- include/configs/aspeed-common.h | 2 + 7 files changed, 116 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S index 937ea0d7b9a0..c65adff0d69a 100644 --- a/arch/arm/mach-aspeed/ast2600/platform.S +++ b/arch/arm/mach-aspeed/ast2600/platform.S @@ -65,6 +65,9 @@ #define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058) #define AST_WDT1_BASE 0x1E785000 +#define AST_WDT1_RELOAD_VAL (AST_WDT1_BASE + 0x004) +#define AST_WDT1_RESTART_CTRL (AST_WDT1_BASE + 0x008) +#define AST_WDT1_CTRL (AST_WDT1_BASE + 0x00C) #define AST_WDT1_RESET_MASK1 (AST_WDT1_BASE + 0x01C) #define AST_WDT1_RESET_MASK2 (AST_WDT1_BASE + 0x020) @@ -348,6 +351,18 @@ wait_lock: ldr r1, =AST_SCU_CA7_PARITY_CHK str r0, [r1] +#ifdef CONFIG_HW_WATCHDOG + /* Enable WDT1 to recover u-boot hang */ + ldr r0, =AST_WDT1_RELOAD_VAL + ldr r1, =0x00500000 @ ~5 seconds + str r1, [r0] + ldr r0, =AST_WDT1_RESTART_CTRL + ldr r1, =0x00004755 + str r1, [r0] + ldr r0, =AST_WDT1_CTRL + ldr r1, =0x00000013 + str r1, [r0] +#endif #if 0 ldr r1, =AST_FMC_WDT2_CTRL_MODE str r0, [r1] diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c index 03eff62ce04b..88d9384faf2d 100644 --- a/board/aspeed/ast2600_intel/intel.c +++ b/board/aspeed/ast2600_intel/intel.c @@ -7,6 +7,7 @@ #include #include #include +#include #define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */ #define WATCHDOG_RESET_BIT BIT(20) @@ -584,13 +585,54 @@ void board_preboot_os(void) led_set_state(dev, LEDST_ON); } -#ifdef CONFIG_WATCHDOG -/* watchdog stuff */ -void watchdog_init(void) +#ifdef CONFIG_HW_WATCHDOG +#define WDT_TIMEOUT_DEFAULT 0x6000000 /* ~100 seconds */ + +void hw_watchdog_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_WDT, &dev); + if (ret) { + debug("Can't find a WDT: %d\n", ret); + return; + } + + ret = wdt_start(dev, WDT_TIMEOUT_DEFAULT, 0); + if (ret) + debug("WDT start failed: %d\n", ret); +} + +void hw_watchdog_reset(void) { + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_WDT, &dev); + if (ret) { + debug("Can't find a WDT: %d\n", ret); + return; + } + + ret = wdt_reset(dev); + if (ret) + debug("WDT reset failed: %d\n", ret); } -void watchdog_reset(void) +void hw_watchdog_disable(void) { + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_WDT, &dev); + if (ret) { + debug("Can't find a WDT: %d\n", ret); + return; + } + + ret = wdt_stop(dev); + if (ret) + debug("WDT stop failed: %d\n", ret); } #endif diff --git a/common/board_f.c b/common/board_f.c index 149a7229e8fa..fe3e8e59d93e 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -94,6 +94,7 @@ static int init_func_watchdog_init(void) { # if defined(CONFIG_HW_WATCHDOG) && \ (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ + defined(CONFIG_ASPEED_AST2600) || \ defined(CONFIG_SH) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ defined(CONFIG_IMX_WATCHDOG)) diff --git a/common/image.c b/common/image.c index 4d4248f234fb..90687092e1ae 100644 --- a/common/image.c +++ b/common/image.c @@ -528,7 +528,8 @@ void memmove_wd(void *to, void *from, size_t len, ulong chunksz) if (to == from) return; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(CONFIG_ASPEED_SPI_DMA) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) if (to > from) { from += len; to += len; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e1fe91712e24..13f499a90272 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "sf_internal.h" @@ -429,6 +430,10 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, unsigned long timebase; int ret; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + WATCHDOG_RESET(); +#endif + timebase = get_timer(0); while (get_timer(timebase) < timeout) { diff --git a/drivers/watchdog/ast_wdt.c b/drivers/watchdog/ast_wdt.c index c2dc3cf548d2..811ead41bb95 100644 --- a/drivers/watchdog/ast_wdt.c +++ b/drivers/watchdog/ast_wdt.c @@ -19,10 +19,11 @@ #define WDT_CTRL_RESET_MODE_SHIFT 5 #define WDT_CTRL_RESET_MODE_MASK 3 -#define WDT_CTRL_EN (1 << 0) -#define WDT_CTRL_RESET (1 << 1) -#define WDT_CTRL_CLK1MHZ (1 << 4) -#define WDT_CTRL_2ND_BOOT (1 << 7) +#define WDT_CTRL_EN BIT(0) +#define WDT_CTRL_RESET BIT(1) +#define WDT_CTRL_CLK1MHZ BIT(4) /* AST2400/2500 */ +#define WDT_CTRL_WDT_RST_BY_SOC_RST BIT(4) /* AST2600 */ +#define WDT_CTRL_2ND_BOOT BIT(7) /* Values for Reset Mode */ #define WDT_CTRL_RESET_SOC 0 @@ -31,32 +32,32 @@ #define WDT_CTRL_RESET_MASK 3 /* Reset Mask register */ -#define WDT_RESET_ARM (1 << 0) -#define WDT_RESET_COPROC (1 << 1) -#define WDT_RESET_SDRAM (1 << 2) -#define WDT_RESET_AHB (1 << 3) -#define WDT_RESET_I2C (1 << 4) -#define WDT_RESET_MAC1 (1 << 5) -#define WDT_RESET_MAC2 (1 << 6) -#define WDT_RESET_GCRT (1 << 7) -#define WDT_RESET_USB20 (1 << 8) -#define WDT_RESET_USB11_HOST (1 << 9) -#define WDT_RESET_USB11_EHCI2 (1 << 10) -#define WDT_RESET_VIDEO (1 << 11) -#define WDT_RESET_HAC (1 << 12) -#define WDT_RESET_LPC (1 << 13) -#define WDT_RESET_SDSDIO (1 << 14) -#define WDT_RESET_MIC (1 << 15) -#define WDT_RESET_CRT2C (1 << 16) -#define WDT_RESET_PWM (1 << 17) -#define WDT_RESET_PECI (1 << 18) -#define WDT_RESET_JTAG (1 << 19) -#define WDT_RESET_ADC (1 << 20) -#define WDT_RESET_GPIO (1 << 21) -#define WDT_RESET_MCTP (1 << 22) -#define WDT_RESET_XDMA (1 << 23) -#define WDT_RESET_SPI (1 << 24) -#define WDT_RESET_MISC (1 << 25) +#define WDT_RESET_ARM BIT(0) +#define WDT_RESET_COPROC BIT(1) +#define WDT_RESET_SDRAM BIT(2) +#define WDT_RESET_AHB BIT(3) +#define WDT_RESET_I2C BIT(4) +#define WDT_RESET_MAC1 BIT(5) +#define WDT_RESET_MAC2 BIT(6) +#define WDT_RESET_GCRT BIT(7) +#define WDT_RESET_USB20 BIT(8) +#define WDT_RESET_USB11_HOST BIT(9) +#define WDT_RESET_USB11_EHCI2 BIT(10) +#define WDT_RESET_VIDEO BIT(11) +#define WDT_RESET_HAC BIT(12) +#define WDT_RESET_LPC BIT(13) +#define WDT_RESET_SDSDIO BIT(14) +#define WDT_RESET_MIC BIT(15) +#define WDT_RESET_CRT2C BIT(16) +#define WDT_RESET_PWM BIT(17) +#define WDT_RESET_PECI BIT(18) +#define WDT_RESET_JTAG BIT(19) +#define WDT_RESET_ADC BIT(20) +#define WDT_RESET_GPIO BIT(21) +#define WDT_RESET_MCTP BIT(22) +#define WDT_RESET_XDMA BIT(23) +#define WDT_RESET_SPI BIT(24) +#define WDT_RESET_MISC BIT(25) #define WDT_RESET_DEFAULT \ (WDT_RESET_ARM | WDT_RESET_COPROC | WDT_RESET_I2C | \ @@ -98,12 +99,18 @@ struct ast_wdt_priv { static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct ast_wdt_priv *priv = dev_get_priv(dev); + ulong driver_data = dev_get_driver_data(dev); writel((u32) timeout, &priv->regs->counter_reload_val); writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart); - writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl); + if (driver_data == WDT_AST2600) { + writel(WDT_CTRL_EN | WDT_CTRL_RESET | + WDT_CTRL_WDT_RST_BY_SOC_RST, &priv->regs->ctrl); + } else { + writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl); + } return 0; } @@ -115,12 +122,15 @@ static int ast_wdt_stop(struct udevice *dev) clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN); +#if !defined(CONFIG_TARGET_AST2600_INTEL) if(driver_data == WDT_AST2600) { writel(0x030f1ff1, &priv->regs->reset_mask1); writel(0x3fffff1, &priv->regs->reset_mask2); - } else + } else { writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask1); - + } +#endif + return 0; } @@ -168,7 +178,9 @@ static const struct wdt_ops ast_wdt_ops = { static int ast_wdt_probe(struct udevice *dev) { debug("%s() wdt%u\n", __func__, dev->seq); +#if !defined(CONFIG_TARGET_AST2600_INTEL) ast_wdt_stop(dev); +#endif return 0; } diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h index 183a7a502e9c..d5befb185b6a 100644 --- a/include/configs/aspeed-common.h +++ b/include/configs/aspeed-common.h @@ -20,6 +20,8 @@ #define CONFIG_STANDALONE_LOAD_ADDR 0x83000000 +#define CONFIG_HW_WATCHDOG + /* Misc CPU related */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS -- 2.17.1