watchdog: Implement generic watchdog_reset() version

This patch tries to implement a generic watchdog_reset() function that
can be used by all boards that want to service the watchdog device in
U-Boot. This watchdog servicing is enabled via CONFIG_WATCHDOG.

Without this approach, new boards or platforms needed to implement a
board specific version of this functionality, mostly copy'ing the same
code over and over again into their board or platforms code base.

With this new generic function, the scattered other functions are now
removed to be replaced by the generic one. The new version also enables
the configuration of the watchdog timeout via the DT "timeout-sec"
property (if enabled via CONFIG_OF_CONTROL).

This patch also adds a new flag to the GD flags, to flag that the
watchdog is ready to use and adds the pointer to the watchdog device
to the GD. This enables us to remove the global "watchdog_dev"
variable, which was prone to cause problems because of its potentially
very early use in watchdog_reset(), even before the BSS is cleared.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Heiko Schocher <hs@denx.de>
Cc: Tom Rini <trini@konsulko.com>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: "Marek Behún" <marek.behun@nic.cz>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Cc: Maxim Sloyko <maxims@google.com>
Cc: Erik van Luijk <evanluijk@interact.nl>
Cc: Ryder Lee <ryder.lee@mediatek.com>
Cc: Weijie Gao <weijie.gao@mediatek.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: "Álvaro Fernández Rojas" <noltari@gmail.com>
Cc: Philippe Reynes <philippe.reynes@softathome.com>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Michal Simek <michal.simek@xilinx.com>
Tested-by: Michal Simek <michal.simek@xilinx.com> (on zcu100)
This commit is contained in:
Stefan Roese 2019-04-11 15:58:44 +02:00
parent 5edb9b2d71
commit 06985289d4
14 changed files with 82 additions and 259 deletions

View file

@ -69,28 +69,6 @@ int print_cpuinfo(void)
return 0; return 0;
} }
#ifdef CONFIG_WATCHDOG
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
static ulong next_reset;
ulong now;
if (!watchdog_dev)
return;
now = get_timer(0);
/* Do not reset the watchdog too often */
if (now > next_reset) {
next_reset = now + 1000; /* reset every 1000ms */
wdt_reset(watchdog_dev);
}
}
#endif
int arch_misc_init(void) int arch_misc_init(void)
{ {
/* /*
@ -103,19 +81,5 @@ int arch_misc_init(void)
flush_dcache_range(gd->bd->bi_memstart, flush_dcache_range(gd->bd->bi_memstart,
gd->bd->bi_memstart + gd->ram_size - 1); gd->bd->bi_memstart + gd->ram_size - 1);
#ifdef CONFIG_WATCHDOG
/* Init watchdog */
if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
debug("Watchdog: Not found by seq!\n");
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
puts("Watchdog: Not found!\n");
return 0;
}
}
wdt_start(watchdog_dev, 60000, 0); /* 60 seconds */
printf("Watchdog: Started\n");
#endif
return 0; return 0;
} }

View file

@ -119,41 +119,11 @@ int board_fix_fdt(void *blob)
} }
#endif #endif
#ifdef CONFIG_WDT_ARMADA_37XX
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
void watchdog_reset(void)
{
static ulong next_reset;
ulong now;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 100000;
}
}
#endif
int board_init(void) int board_init(void)
{ {
/* address of boot parameters */ /* address of boot parameters */
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
#ifdef CONFIG_WDT_ARMADA_37XX
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
printf("Cannot find Armada 3720 watchdog!\n");
} else {
printf("Enabling Armada 3720 watchdog (3 minutes timeout).\n");
wdt_start(watchdog_dev, 180000, 0);
}
#endif
return 0; return 0;
} }

View file

@ -364,25 +364,12 @@ static bool disable_mcu_watchdog(void)
} }
#endif #endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
#endif
int board_init(void) int board_init(void)
{ {
/* adress of boot parameters */ /* adress of boot parameters */
gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
#ifndef CONFIG_SPL_BUILD #ifndef CONFIG_SPL_BUILD
# ifdef CONFIG_WDT_ORION
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
puts("Cannot find Armada 385 watchdog!\n");
} else {
puts("Enabling Armada 385 watchdog.\n");
wdt_start(watchdog_dev, 120000, 0);
}
# endif
if (disable_mcu_watchdog()) if (disable_mcu_watchdog())
puts("Disabled MCU startup watchdog.\n"); puts("Disabled MCU startup watchdog.\n");
@ -392,28 +379,6 @@ int board_init(void)
return 0; return 0;
} }
#ifdef CONFIG_WATCHDOG
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
# if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
static ulong next_reset = 0;
ulong now;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 1000;
}
# endif
}
#endif
int board_late_init(void) int board_late_init(void)
{ {
#ifndef CONFIG_SPL_BUILD #ifndef CONFIG_SPL_BUILD

View file

@ -25,10 +25,6 @@ DECLARE_GLOBAL_DATA_PTR;
#define CONFIG_NVS_LOCATION 0xf4800000 #define CONFIG_NVS_LOCATION 0xf4800000
#define CONFIG_NVS_SIZE (512 << 10) #define CONFIG_NVS_SIZE (512 << 10)
#ifdef CONFIG_WATCHDOG
static struct udevice *watchdog_dev;
#endif
static struct serdes_map board_serdes_map[] = { static struct serdes_map board_serdes_map[] = {
{PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0}, {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
{DEFAULT_SERDES, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, {DEFAULT_SERDES, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
@ -80,10 +76,6 @@ struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
int board_early_init_f(void) int board_early_init_f(void)
{ {
#ifdef CONFIG_WATCHDOG
watchdog_dev = NULL;
#endif
/* Configure MPP */ /* Configure MPP */
writel(0x00001111, MVEBU_MPP_BASE + 0x00); writel(0x00001111, MVEBU_MPP_BASE + 0x00);
writel(0x00000000, MVEBU_MPP_BASE + 0x04); writel(0x00000000, MVEBU_MPP_BASE + 0x04);
@ -99,13 +91,6 @@ int board_early_init_f(void)
void spl_board_init(void) void spl_board_init(void)
{ {
#ifdef CONFIG_WATCHDOG
int ret;
ret = uclass_get_device(UCLASS_WDT, 0, &watchdog_dev);
if (!ret)
wdt_start(watchdog_dev, 120000, 0);
#endif
} }
int board_init(void) int board_init(void)
@ -128,29 +113,10 @@ int board_init(void)
void arch_preboot_os(void) void arch_preboot_os(void)
{ {
#ifdef CONFIG_WATCHDOG #ifdef CONFIG_WATCHDOG
wdt_stop(watchdog_dev); wdt_stop(gd->watchdog_dev);
#endif #endif
} }
#ifdef CONFIG_WATCHDOG
void watchdog_reset(void)
{
static ulong next_reset = 0;
ulong now;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 1000;
}
}
#endif
static int led_7seg_init(unsigned int segments) static int led_7seg_init(unsigned int segments)
{ {
int node; int node;

View file

@ -24,10 +24,6 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
#endif /* !CONFIG_SPL_BUILD && CONFIG_WDT */
ulong ram_base; ulong ram_base;
int dram_init_banksize(void) int dram_init_banksize(void)
@ -43,44 +39,8 @@ int dram_init(void)
return 0; return 0;
}; };
#ifdef CONFIG_WDT
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
#if !defined(CONFIG_SPL_BUILD)
ulong now;
static ulong next_reset;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 1000;
}
#endif /* !CONFIG_SPL_BUILD */
}
#endif /* CONFIG_WDT */
int board_late_init(void) int board_late_init(void)
{ {
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
watchdog_dev = NULL;
if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
debug("Watchdog: Not found by seq!\n");
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
puts("Watchdog: Not found!\n");
return 0;
}
}
wdt_start(watchdog_dev, 0, 0);
puts("Watchdog: Started\n");
#endif /* !CONFIG_SPL_BUILD && CONFIG_WDT */
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE) #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE)
int ret; int ret;

View file

@ -18,10 +18,6 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
#endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOARD_EARLY_INIT_F) #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOARD_EARLY_INIT_F)
int board_early_init_f(void) int board_early_init_f(void)
{ {
@ -31,19 +27,6 @@ int board_early_init_f(void)
int board_init(void) int board_init(void)
{ {
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
debug("Watchdog: Not found by seq!\n");
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
puts("Watchdog: Not found!\n");
return 0;
}
}
wdt_start(watchdog_dev, 0, 0);
puts("Watchdog: Started\n");
# endif
return 0; return 0;
} }
@ -127,25 +110,3 @@ int dram_init(void)
return 0; return 0;
} }
#endif #endif
#if defined(CONFIG_WATCHDOG)
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
# if !defined(CONFIG_SPL_BUILD)
static ulong next_reset;
ulong now;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 1000;
}
# endif
}
#endif

View file

@ -24,10 +24,6 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
#endif
#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
!defined(CONFIG_SPL_BUILD) !defined(CONFIG_SPL_BUILD)
static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC; static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
@ -344,44 +340,9 @@ int board_init(void)
} }
#endif #endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
debug("Watchdog: Not found by seq!\n");
if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
puts("Watchdog: Not found!\n");
return 0;
}
}
wdt_start(watchdog_dev, 0, 0);
puts("Watchdog: Started\n");
#endif
return 0; return 0;
} }
#ifdef CONFIG_WATCHDOG
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
# if !defined(CONFIG_SPL_BUILD)
static ulong next_reset;
ulong now;
if (!watchdog_dev)
return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(watchdog_dev);
next_reset = now + 1000;
}
# endif
}
#endif
int board_early_init_r(void) int board_early_init_r(void)
{ {
u32 val; u32 val;

View file

@ -48,6 +48,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/err.h> #include <linux/err.h>
#include <efi_loader.h> #include <efi_loader.h>
#include <wdt.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
@ -677,6 +678,9 @@ static init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_DM #ifdef CONFIG_DM
initr_dm, initr_dm,
#endif #endif
#if defined(CONFIG_WDT)
initr_watchdog,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \ #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
defined(CONFIG_SANDBOX) defined(CONFIG_SANDBOX)
board_init, /* Setup chipselects */ board_init, /* Setup chipselects */

View file

@ -22,6 +22,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <fdt_support.h> #include <fdt_support.h>
#include <bootcount.h> #include <bootcount.h>
#include <wdt.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
@ -600,6 +601,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
spl_board_init(); spl_board_init();
#endif #endif
#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && defined(CONFIG_WDT)
initr_watchdog();
#endif
if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF)) if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF))
dram_init_banksize(); dram_init_banksize();

View file

@ -51,6 +51,7 @@ config ULP_WATCHDOG
config WDT config WDT
bool "Enable driver model for watchdog timer drivers" bool "Enable driver model for watchdog timer drivers"
depends on DM depends on DM
imply WATCHDOG
help help
Enable driver model for watchdog timer. At the moment the API Enable driver model for watchdog timer. At the moment the API
is very simple and only supports four operations: is very simple and only supports four operations:

View file

@ -10,6 +10,8 @@
#include <dm/device-internal.h> #include <dm/device-internal.h>
#include <dm/lists.h> #include <dm/lists.h>
DECLARE_GLOBAL_DATA_PTR;
int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{ {
const struct wdt_ops *ops = device_get_ops(dev); const struct wdt_ops *ops = device_get_ops(dev);
@ -63,6 +65,30 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
return ret; return ret;
} }
#if defined(CONFIG_WATCHDOG)
/*
* Called by macro WATCHDOG_RESET. This function be called *very* early,
* so we need to make sure, that the watchdog driver is ready before using
* it in this function.
*/
void watchdog_reset(void)
{
static ulong next_reset;
ulong now;
/* Exit if GD is not ready or watchdog is not initialized yet */
if (!gd || !(gd->flags & GD_FLG_WDT_READY))
return;
/* Do not reset the watchdog too often */
now = get_timer(0);
if (now > next_reset) {
next_reset = now + 1000; /* reset every 1000ms */
wdt_reset(gd->watchdog_dev);
}
}
#endif
static int wdt_post_bind(struct udevice *dev) static int wdt_post_bind(struct udevice *dev)
{ {
#if defined(CONFIG_NEEDS_MANUAL_RELOC) #if defined(CONFIG_NEEDS_MANUAL_RELOC)

View file

@ -137,6 +137,9 @@ typedef struct global_data {
#if defined(CONFIG_TRANSLATION_OFFSET) #if defined(CONFIG_TRANSLATION_OFFSET)
fdt_addr_t translation_offset; /* optional translation offset */ fdt_addr_t translation_offset; /* optional translation offset */
#endif #endif
#if defined(CONFIG_WDT)
struct udevice *watchdog_dev;
#endif
} gd_t; } gd_t;
#endif #endif
@ -165,5 +168,6 @@ typedef struct global_data {
#define GD_FLG_ENV_DEFAULT 0x02000 /* Default variable flag */ #define GD_FLG_ENV_DEFAULT 0x02000 /* Default variable flag */
#define GD_FLG_SPL_EARLY_INIT 0x04000 /* Early SPL init is done */ #define GD_FLG_SPL_EARLY_INIT 0x04000 /* Early SPL init is done */
#define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */ #define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */
#define GD_FLG_WDT_READY 0x10000 /* Watchdog is ready for use */
#endif /* __ASM_GENERIC_GBL_DATA_H */ #endif /* __ASM_GENERIC_GBL_DATA_H */

View file

@ -29,11 +29,6 @@
#define CONFIG_SPL_I2C_MUX #define CONFIG_SPL_I2C_MUX
#define CONFIG_SYS_I2C_MVTWSI #define CONFIG_SYS_I2C_MVTWSI
/* Watchdog support */
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
# define CONFIG_WATCHDOG
#endif
/* /*
* SDIO/MMC Card Configuration * SDIO/MMC Card Configuration
*/ */

View file

@ -6,6 +6,9 @@
#ifndef _WDT_H_ #ifndef _WDT_H_
#define _WDT_H_ #define _WDT_H_
#include <dm.h>
#include <dm/read.h>
/* /*
* Implement a simple watchdog uclass. Watchdog is basically a timer that * Implement a simple watchdog uclass. Watchdog is basically a timer that
* is used to detect or recover from malfunction. During normal operation * is used to detect or recover from malfunction. During normal operation
@ -103,4 +106,42 @@ struct wdt_ops {
int (*expire_now)(struct udevice *dev, ulong flags); int (*expire_now)(struct udevice *dev, ulong flags);
}; };
#if defined(CONFIG_WDT)
#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
#define CONFIG_WATCHDOG_TIMEOUT_MSECS (60 * 1000)
#endif
#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
static inline int initr_watchdog(void)
{
u32 timeout = WATCHDOG_TIMEOUT_SECS;
/*
* Init watchdog: This will call the probe function of the
* watchdog driver, enabling the use of the device
*/
if (uclass_get_device_by_seq(UCLASS_WDT, 0,
(struct udevice **)&gd->watchdog_dev)) {
debug("WDT: Not found by seq!\n");
if (uclass_get_device(UCLASS_WDT, 0,
(struct udevice **)&gd->watchdog_dev)) {
printf("WDT: Not found!\n");
return 0;
}
}
if (CONFIG_IS_ENABLED(OF_CONTROL)) {
timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec",
WATCHDOG_TIMEOUT_SECS);
}
wdt_start(gd->watchdog_dev, timeout * 1000, 0);
gd->flags |= GD_FLG_WDT_READY;
printf("WDT: Started with%s servicing (%ds timeout)\n",
IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout);
return 0;
}
#endif
#endif /* _WDT_H_ */ #endif /* _WDT_H_ */