watchdog: Implement generic watchdog_reset() version
authorStefan Roese <sr@denx.de>
Thu, 11 Apr 2019 13:58:44 +0000 (15:58 +0200)
committerStefan Roese <sr@denx.de>
Fri, 26 Apr 2019 07:16:32 +0000 (09:16 +0200)
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)
14 files changed:
arch/mips/mach-mt7620/cpu.c
board/CZ.NIC/turris_mox/turris_mox.c
board/CZ.NIC/turris_omnia/turris_omnia.c
board/alliedtelesis/x530/x530.c
board/xilinx/microblaze-generic/microblaze-generic.c
board/xilinx/zynq/board.c
board/xilinx/zynqmp/zynqmp.c
common/board_r.c
common/spl/spl.c
drivers/watchdog/Kconfig
drivers/watchdog/wdt-uclass.c
include/asm-generic/global_data.h
include/configs/turris_omnia.h
include/wdt.h

index fe74f26a545dd6cb1789c0b83719f9291350f2e1..fcd0484a6d871685a0e455ecdbbf3687f37c0022 100644 (file)
@@ -69,28 +69,6 @@ int print_cpuinfo(void)
        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)
 {
        /*
@@ -103,19 +81,5 @@ int arch_misc_init(void)
        flush_dcache_range(gd->bd->bi_memstart,
                           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;
 }
index 96cb9c7e5c6e2543e7084b7228c7f374b63c3384..8a4872343b65d634edbc3751889e4372324716f4 100644 (file)
@@ -119,41 +119,11 @@ int board_fix_fdt(void *blob)
 }
 #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)
 {
        /* address of boot parameters */
        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;
 }
 
index 0287f232834901b0ee799efd1b14d6a1c18dbea1..4c08f810a240712245cad9e2f1adfe33c6b5c537 100644 (file)
@@ -364,25 +364,12 @@ static bool disable_mcu_watchdog(void)
 }
 #endif
 
-#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
-static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
-#endif
-
 int board_init(void)
 {
        /* adress of boot parameters */
        gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
 
 #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())
                puts("Disabled MCU startup watchdog.\n");
 
@@ -392,28 +379,6 @@ int board_init(void)
        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)
 {
 #ifndef CONFIG_SPL_BUILD
index 6934fd80173072c8ef5d1bf0624ff8819d7845ed..97dbed79dd662710ef090075f8d4bb228bc97e1e 100644 (file)
@@ -25,10 +25,6 @@ DECLARE_GLOBAL_DATA_PTR;
 #define CONFIG_NVS_LOCATION            0xf4800000
 #define CONFIG_NVS_SIZE                        (512 << 10)
 
-#ifdef CONFIG_WATCHDOG
-static struct udevice *watchdog_dev;
-#endif
-
 static struct serdes_map board_serdes_map[] = {
        {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 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)
 {
-#ifdef CONFIG_WATCHDOG
-       watchdog_dev = NULL;
-#endif
-
        /* Configure MPP */
        writel(0x00001111, MVEBU_MPP_BASE + 0x00);
        writel(0x00000000, MVEBU_MPP_BASE + 0x04);
@@ -99,13 +91,6 @@ int board_early_init_f(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)
@@ -128,29 +113,10 @@ int board_init(void)
 void arch_preboot_os(void)
 {
 #ifdef CONFIG_WATCHDOG
-       wdt_stop(watchdog_dev);
+       wdt_stop(gd->watchdog_dev);
 #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)
 {
        int node;
index 28c9efa3a2e0714e7df9d04ef44a3dad9f303bb8..ba82292e35ac75c26083324831da43e946c7e351 100644 (file)
 
 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;
 
 int dram_init_banksize(void)
@@ -43,44 +39,8 @@ int dram_init(void)
        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)
 {
-#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)
        int ret;
 
index ea26aad16f841ab7170bf057c266dbb1051a1053..6857f2c0b8469cb6e2c52af7dcb5790f3ce57c2a 100644 (file)
 
 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)
 int board_early_init_f(void)
 {
@@ -31,19 +27,6 @@ int board_early_init_f(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;
 }
 
@@ -127,25 +110,3 @@ int dram_init(void)
        return 0;
 }
 #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
index 5189925beb3aaea657635f9d12e8b466f59f4102..c840e92d9c42e5aca559828d6af75fef0af09022 100644 (file)
 
 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) && \
     !defined(CONFIG_SPL_BUILD)
 static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
@@ -344,44 +340,9 @@ int board_init(void)
        }
 #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;
 }
 
-#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)
 {
        u32 val;
index 1ad44bbe3f719e62c19690d621822a8b3c81093d..150e8cd424f64b6ebe435bf817f0483492d9a153 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <efi_loader.h>
+#include <wdt.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -677,6 +678,9 @@ static init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_DM
        initr_dm,
 #endif
+#if defined(CONFIG_WDT)
+       initr_watchdog,
+#endif
 #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
        defined(CONFIG_SANDBOX)
        board_init,     /* Setup chipselects */
index 88d4b8a9bf15b70e990758cd33ea5b984ef93f11..0a6a47c202019c1885c25173d6520a95f467886a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/compiler.h>
 #include <fdt_support.h>
 #include <bootcount.h>
+#include <wdt.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -600,6 +601,10 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
        spl_board_init();
 #endif
 
+#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && defined(CONFIG_WDT)
+       initr_watchdog();
+#endif
+
        if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF))
                dram_init_banksize();
 
index 9d7f503b698dc560eb67fd8958b16b1f8f21a0a7..aa8e7255735f6621c7ce3602a2b91921ec9b85eb 100644 (file)
@@ -51,6 +51,7 @@ config ULP_WATCHDOG
 config WDT
        bool "Enable driver model for watchdog timer drivers"
        depends on DM
+       imply WATCHDOG
        help
          Enable driver model for watchdog timer. At the moment the API
          is very simple and only supports four operations:
index 23b7e3360d32fa0cd896b98583aeb5f514db79b9..bbfac4f0f9b4a189b39a55c176a540a46e0cbc19 100644 (file)
@@ -10,6 +10,8 @@
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
        const struct wdt_ops *ops = device_get_ops(dev);
@@ -63,6 +65,30 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
        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)
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
index 65ee3e5d5a0ade4c1e654bebac29d5c72c641f73..02a3ed683821fa1af7d16296c472e4033526e5a5 100644 (file)
@@ -137,6 +137,9 @@ typedef struct global_data {
 #if defined(CONFIG_TRANSLATION_OFFSET)
        fdt_addr_t translation_offset;  /* optional translation offset */
 #endif
+#if defined(CONFIG_WDT)
+       struct udevice *watchdog_dev;
+#endif
 } gd_t;
 #endif
 
@@ -165,5 +168,6 @@ typedef struct global_data {
 #define GD_FLG_ENV_DEFAULT     0x02000 /* Default variable flag           */
 #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_WDT_READY       0x10000 /* Watchdog is ready for use       */
 
 #endif /* __ASM_GENERIC_GBL_DATA_H */
index c7805cf36bf2c142cb974853dcd3cd1bd5b51ca1..0e65a12345da92fc1dba9fd8f57cd89f4c5edbfc 100644 (file)
 #define CONFIG_SPL_I2C_MUX
 #define CONFIG_SYS_I2C_MVTWSI
 
-/* Watchdog support */
-#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
-# define CONFIG_WATCHDOG
-#endif
-
 /*
  * SDIO/MMC Card Configuration
  */
index e9a7c5355a64e0fea55cdecfffb895d5a5615d6d..aa77d3e9b40368af889b67e81fa411d9c66d42e4 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef _WDT_H_
 #define _WDT_H_
 
+#include <dm.h>
+#include <dm/read.h>
+
 /*
  * Implement a simple watchdog uclass. Watchdog is basically a timer that
  * 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);
 };
 
+#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_ */