CI: https://dev.azure.com/sr0718/u-boot/_build/results?buildId=378&view=results

* watchdog: gpio_wdt: add support for stoppable devices (Rasmus)
* watchdog: Add DaVinci's watchdog support (Bastien)
* cyclic: disentangling cyclic API from schedule() (Rasmus)
* watchdog: introduce separate SPL symbol for WDT_GPIO (Rasmus)
This commit is contained in:
Tom Rini
2024-10-23 08:33:56 -06:00
21 changed files with 225 additions and 47 deletions

View File

@@ -9,6 +9,8 @@
*/ */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/types.h>
struct pt_regs { struct pt_regs {
ulong d0; ulong d0;
ulong d1; ulong d1;

View File

@@ -20,6 +20,7 @@
#include <video.h> #include <video.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "scene_internal.h" #include "scene_internal.h"
#include <u-boot/schedule.h>
enum { enum {
CMOS_MAX_BITS = 2048, CMOS_MAX_BITS = 2048,

View File

@@ -15,6 +15,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/list.h> #include <linux/list.h>
#include <asm/global_data.h> #include <asm/global_data.h>
#include <u-boot/schedule.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
@@ -44,7 +45,7 @@ void cyclic_unregister(struct cyclic_info *cyclic)
hlist_del(&cyclic->list); hlist_del(&cyclic->list);
} }
void cyclic_run(void) static void cyclic_run(void)
{ {
struct cyclic_info *cyclic; struct cyclic_info *cyclic;
struct hlist_node *tmp; struct hlist_node *tmp;

View File

@@ -49,8 +49,8 @@ executed all 10ms.
How is this cyclic functionality integrated / executed? How is this cyclic functionality integrated / executed?
-------------------------------------------------------- --------------------------------------------------------
The cyclic infrastructure integrates the main function responsible for The cyclic infrastructure integrates cyclic_run(), the main function
calling all registered cyclic functions cyclic_run() into the common responsible for calling all registered cyclic functions, into the
WATCHDOG_RESET macro. This guarantees that cyclic_run() is executed common schedule() function. This guarantees that cyclic_run() is
very often, which is necessary for the cyclic functions to get scheduled executed very often, which is necessary for the cyclic functions to
and executed at their configured periods. get scheduled and executed at their configured periods.

View File

@@ -22,6 +22,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <u-boot/schedule.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;

View File

@@ -24,6 +24,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <dm/device_compat.h> #include <dm/device_compat.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <u-boot/schedule.h>
#define PGTABLE_OFF 0x4000 #define PGTABLE_OFF 0x4000

View File

@@ -14,6 +14,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <reset.h> #include <reset.h>
#include <u-boot/schedule.h>
#include <wait_bit.h> #include <wait_bit.h>
#define RIIC_ICCR1 0x00 #define RIIC_ICCR1 0x00

View File

@@ -5,6 +5,7 @@
* Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
*/ */
#include <cyclic.h>
#include <dm.h> #include <dm.h>
#include <led.h> #include <led.h>
#include <time.h> #include <time.h>

View File

@@ -175,6 +175,13 @@ config WDT_DA9063
help help
Enable support for the watchdog timer in Dialog DA9063. Enable support for the watchdog timer in Dialog DA9063.
config WDT_DAVINCI
bool "DaVinci watchdog timer support"
depends on WDT
help
Select this to enable the watchdog timer for DaVinci SoCs such as the
OMAP-L138.
config WDT_GPIO config WDT_GPIO
bool "External gpio watchdog support" bool "External gpio watchdog support"
depends on WDT depends on WDT
@@ -184,6 +191,15 @@ config WDT_GPIO
doc/device-tree-bindings/watchdog/gpio-wdt.txt for doc/device-tree-bindings/watchdog/gpio-wdt.txt for
information on how to describe the watchdog in device tree. information on how to describe the watchdog in device tree.
config SPL_WDT_GPIO
bool "External gpio watchdog support in SPL"
depends on SPL_WDT
depends on SPL_DM_GPIO
depends on SPL_OF_REAL
default WDT_GPIO
help
Support for external watchdog fed by toggling a gpio in SPL.
config WDT_MAX6370 config WDT_MAX6370
bool "MAX6370 watchdog timer support" bool "MAX6370 watchdog timer support"
depends on WDT depends on WDT

View File

@@ -30,8 +30,9 @@ obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o
obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
obj-$(CONFIG_WDT_DA9063) += da9063-wdt.o obj-$(CONFIG_WDT_DA9063) += da9063-wdt.o
obj-$(CONFIG_WDT_DAVINCI) += davinci_wdt.o
obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o
obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o obj-$(CONFIG_$(SPL_TPL_)WDT_GPIO) += gpio_wdt.o
obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o
obj-$(CONFIG_WDT_MCF) += mcf_wdt.o obj-$(CONFIG_WDT_MCF) += mcf_wdt.o
obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o

View File

@@ -0,0 +1,131 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* DaVinci Watchdog driver
*
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <wdt.h>
/* Control Register */
#define DAVINCI_WDT_ID 0x00
#define DAVINCI_WDT_TIM12 0x10
#define DAVINCI_WDT_TIM34 0x14
#define DAVINCI_WDT_PRD12 0x18
#define DAVINCI_WDT_PRD34 0x1C
#define DAVINCI_WDT_TCR 0x20
#define DAVINCI_WDT_TGCR 0x24
#define DAVINCI_WDT_WDTCR 0x28
#define DAVINCI_TCR_CONT_EN BIT(7)
#define DAVINCI_TGCR_PLUSEN BIT(4)
#define DAVINCI_TGCR_WDT_MODE BIT(3)
#define DAVINCI_TGCR_TIM34RS BIT(1)
#define DAVINCI_TGCR_TIM12RS BIT(0)
#define DAVINCI_WDTCR_INVALID_KEY (0x5555 << 16)
#define DAVINCI_WDTCR_WDKEY0 (0xA5C6 << 16)
#define DAVINCI_WDTCR_WDKEY1 (0xDA7E << 16)
#define DAVINCI_WDTCR_WDFLAG BIT(15)
#define DAVINCI_WDTCR_WDEN BIT(14)
#define DEFAULT_THRESHOLD 0xA03200000
struct davinci_wdt_priv {
void __iomem *base;
struct clk *ref_clk;
};
static int davinci_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
struct davinci_wdt_priv *priv = dev_get_priv(dev);
ulong rate = clk_get_rate(priv->ref_clk);
u64 threshold;
if (!rate)
threshold = DEFAULT_THRESHOLD;
else
threshold = rate * timeout_ms / 1000;
/* Reset control registers */
writel(0, priv->base + DAVINCI_WDT_TCR);
writel(0, priv->base + DAVINCI_WDT_TGCR);
/* Enable watchdog mode and timers */
writel(DAVINCI_TGCR_WDT_MODE | DAVINCI_TGCR_TIM12RS | DAVINCI_TGCR_TIM34RS,
priv->base + DAVINCI_WDT_TGCR);
/* Reset counters */
writel(0, priv->base + DAVINCI_WDT_TIM12);
writel(0, priv->base + DAVINCI_WDT_TIM34);
/* Set timeout threshold */
writel(threshold & 0xFFFFFFFF, priv->base + DAVINCI_WDT_PRD12);
writel(threshold >> 32, priv->base + DAVINCI_WDT_PRD34);
/* Enable counter */
writel(DAVINCI_TCR_CONT_EN, priv->base + DAVINCI_WDT_TCR);
/* Go to watchdog's active state */
writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR);
writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR);
return 0;
}
static int davinci_wdt_expire_now(struct udevice *dev, ulong flags)
{
struct davinci_wdt_priv *priv = dev_get_priv(dev);
writel(DAVINCI_WDTCR_INVALID_KEY, priv->base + DAVINCI_WDT_WDTCR);
return 0;
}
static int davinci_wdt_restart(struct udevice *dev)
{
struct davinci_wdt_priv *priv = dev_get_priv(dev);
writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR);
writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR);
return 0;
}
static int davinci_wdt_probe(struct udevice *dev)
{
struct davinci_wdt_priv *priv = dev_get_priv(dev);
priv->base = dev_remap_addr_index(dev, 0);
if (!priv->base)
return -EFAULT;
priv->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(priv->ref_clk))
return PTR_ERR(priv->ref_clk);
return 0;
}
static const struct wdt_ops davinci_wdt_ops = {
.start = davinci_wdt_start,
.reset = davinci_wdt_restart,
.expire_now = davinci_wdt_expire_now,
};
static const struct udevice_id davinci_wdt_ids[] = {
{.compatible = "ti,davinci-wdt"},
{}
};
U_BOOT_DRIVER(davinci_wdt) = {
.name = "davinci_wdt",
.id = UCLASS_WDT,
.probe = davinci_wdt_probe,
.of_match = davinci_wdt_ids,
.ops = &davinci_wdt_ops,
.priv_auto = sizeof(struct davinci_wdt_priv),
};

View File

@@ -45,14 +45,32 @@ static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
if (priv->always_running) if (priv->always_running)
return 0; return 0;
return -ENOSYS; dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_OUT);
gpio_wdt_reset(dev);
return 0;
}
static int gpio_wdt_stop(struct udevice *dev)
{
struct gpio_wdt_priv *priv = dev_get_priv(dev);
if (priv->always_running)
return -EOPNOTSUPP;
if (priv->hw_algo == HW_ALGO_TOGGLE)
dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_IN);
else
dm_gpio_set_value(&priv->gpio, 1);
return 0;
} }
static int dm_probe(struct udevice *dev) static int dm_probe(struct udevice *dev)
{ {
struct gpio_wdt_priv *priv = dev_get_priv(dev); struct gpio_wdt_priv *priv = dev_get_priv(dev);
int ret;
const char *algo = dev_read_string(dev, "hw_algo"); const char *algo = dev_read_string(dev, "hw_algo");
int ret, flags;
if (!algo) if (!algo)
return -EINVAL; return -EINVAL;
@@ -64,7 +82,9 @@ static int dm_probe(struct udevice *dev)
return -EINVAL; return -EINVAL;
priv->always_running = dev_read_bool(dev, "always-running"); priv->always_running = dev_read_bool(dev, "always-running");
ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); flags = priv->always_running || priv->hw_algo == HW_ALGO_LEVEL ?
GPIOD_IS_OUT : GPIOD_IS_IN;
ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Request for wdt gpio failed: %d\n", ret); dev_err(dev, "Request for wdt gpio failed: %d\n", ret);
return ret; return ret;
@@ -78,6 +98,7 @@ static int dm_probe(struct udevice *dev)
static const struct wdt_ops gpio_wdt_ops = { static const struct wdt_ops gpio_wdt_ops = {
.start = gpio_wdt_start, .start = gpio_wdt_start,
.stop = gpio_wdt_stop,
.reset = gpio_wdt_reset, .reset = gpio_wdt_reset,
}; };

View File

@@ -21,9 +21,9 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <cyclic.h>
#include <malloc.h> #include <malloc.h>
#include <watchdog.h> #include <watchdog.h>
#include <u-boot/schedule.h>
#include <u-boot/zlib.h> #include <u-boot/zlib.h>
static z_stream stream; static z_stream stream;
@@ -63,7 +63,7 @@ int cramfs_uncompress_init (void)
stream.avail_in = 0; stream.avail_in = 0;
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
stream.outcb = (cb_func)cyclic_run; stream.outcb = (cb_func)schedule;
#else #else
stream.outcb = Z_NULL; stream.outcb = Z_NULL;
#endif /* CONFIG_HW_WATCHDOG */ #endif /* CONFIG_HW_WATCHDOG */

View File

@@ -21,7 +21,6 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <board_f.h> #include <board_f.h>
#include <cyclic.h>
#include <event_internal.h> #include <event_internal.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <membuff.h> #include <membuff.h>

View File

@@ -13,6 +13,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <asm/types.h> #include <asm/types.h>
#include <u-boot/schedule.h> // to be removed later
/** /**
* struct cyclic_info - Information about cyclic execution function * struct cyclic_info - Information about cyclic execution function
@@ -86,21 +87,6 @@ int cyclic_unregister_all(void);
*/ */
struct hlist_head *cyclic_get_list(void); struct hlist_head *cyclic_get_list(void);
/**
* cyclic_run() - Interate over all registered cyclic functions
*
* Interate over all registered cyclic functions and if the it's function
* needs to be executed, then call into these registered functions.
*/
void cyclic_run(void);
/**
* schedule() - Schedule all potentially waiting tasks
*
* Basically a wrapper for cyclic_run(), pontentially enhanced by some
* other parts, that need to get handled periodically.
*/
void schedule(void);
#else #else
static inline void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func, static inline void cyclic_register(struct cyclic_info *cyclic, cyclic_func_t func,
@@ -112,14 +98,6 @@ static inline void cyclic_unregister(struct cyclic_info *cyclic)
{ {
} }
static inline void cyclic_run(void)
{
}
static inline void schedule(void)
{
}
static inline int cyclic_unregister_all(void) static inline int cyclic_unregister_all(void)
{ {
return 0; return 0;

24
include/u-boot/schedule.h Normal file
View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef _U_BOOT_SCHEDULE_H
#define _U_BOOT_SCHEDULE_H
#if CONFIG_IS_ENABLED(CYCLIC)
/**
* schedule() - Schedule all potentially waiting tasks
*
* Run all pending tasks registered via the cyclic framework, and
* potentially perform other actions that need to be done
* periodically.
*/
void schedule(void);
#else
static inline void schedule(void)
{
}
#endif
#endif

View File

@@ -10,7 +10,7 @@
#ifndef _WATCHDOG_H_ #ifndef _WATCHDOG_H_
#define _WATCHDOG_H_ #define _WATCHDOG_H_
#include <cyclic.h> #include <u-boot/schedule.h> // to be removed later
/* /*
* Reset the watchdog timer, always returns 0 * Reset the watchdog timer, always returns 0

View File

@@ -17,7 +17,7 @@
#endif #endif
#ifndef USE_HOSTCC #ifndef USE_HOSTCC
#include <cyclic.h> #include <u-boot/schedule.h>
#endif /* USE_HOSTCC */ #endif /* USE_HOSTCC */
#include <string.h> #include <string.h>
#include <u-boot/sha1.h> #include <u-boot/sha1.h>

View File

@@ -6,7 +6,7 @@
*/ */
#ifndef USE_HOSTCC #ifndef USE_HOSTCC
#include <cyclic.h> #include <u-boot/schedule.h>
#endif /* USE_HOSTCC */ #endif /* USE_HOSTCC */
#include <string.h> #include <string.h>
#include <u-boot/sha256.h> #include <u-boot/sha256.h>

View File

@@ -11,7 +11,7 @@
*/ */
#ifndef USE_HOSTCC #ifndef USE_HOSTCC
#include <cyclic.h> #include <u-boot/schedule.h>
#endif /* USE_HOSTCC */ #endif /* USE_HOSTCC */
#include <compiler.h> #include <compiler.h>
#include <u-boot/sha512.h> #include <u-boot/sha512.h>

View File

@@ -3,7 +3,6 @@
* Copyright 2017 Google, Inc * Copyright 2017 Google, Inc
*/ */
#include <cyclic.h>
#include <dm.h> #include <dm.h>
#include <time.h> #include <time.h>
#include <wdt.h> #include <wdt.h>
@@ -14,6 +13,7 @@
#include <test/test.h> #include <test/test.h>
#include <test/ut.h> #include <test/ut.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <u-boot/schedule.h>
#include <watchdog.h> #include <watchdog.h>
/* Test that watchdog driver functions are called */ /* Test that watchdog driver functions are called */
@@ -71,7 +71,7 @@ static int dm_test_wdt_gpio_toggle(struct unit_test_state *uts)
ut_assertok(wdt_reset(wdt)); ut_assertok(wdt_reset(wdt));
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset)); ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(-ENOSYS, wdt_stop(wdt)); ut_asserteq(-EOPNOTSUPP, wdt_stop(wdt));
return 0; return 0;
} }
@@ -103,7 +103,7 @@ static int dm_test_wdt_gpio_level(struct unit_test_state *uts)
ut_assertok(wdt_reset(wdt)); ut_assertok(wdt_reset(wdt));
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset)); ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(-ENOSYS, wdt_stop(wdt)); ut_asserteq(-EOPNOTSUPP, wdt_stop(wdt));
return 0; return 0;
} }
@@ -131,7 +131,7 @@ static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
/* Neither device should be "started", so watchdog_reset() should be a no-op. */ /* Neither device should be "started", so watchdog_reset() should be a no-op. */
reset_count = state->wdt.reset_count; reset_count = state->wdt.reset_count;
val = sandbox_gpio_get_value(gpio, offset); val = sandbox_gpio_get_value(gpio, offset);
cyclic_run(); schedule();
ut_asserteq(reset_count, state->wdt.reset_count); ut_asserteq(reset_count, state->wdt.reset_count);
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset)); ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
@@ -141,19 +141,19 @@ static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
/* Make sure both devices have just been pinged. */ /* Make sure both devices have just been pinged. */
timer_test_add_offset(100); timer_test_add_offset(100);
cyclic_run(); schedule();
reset_count = state->wdt.reset_count; reset_count = state->wdt.reset_count;
val = sandbox_gpio_get_value(gpio, offset); val = sandbox_gpio_get_value(gpio, offset);
/* The gpio watchdog should be pinged, the sandbox one not. */ /* The gpio watchdog should be pinged, the sandbox one not. */
timer_test_add_offset(30); timer_test_add_offset(30);
cyclic_run(); schedule();
ut_asserteq(reset_count, state->wdt.reset_count); ut_asserteq(reset_count, state->wdt.reset_count);
ut_asserteq(!val, sandbox_gpio_get_value(gpio, offset)); ut_asserteq(!val, sandbox_gpio_get_value(gpio, offset));
/* After another ~30ms, both devices should get pinged. */ /* After another ~30ms, both devices should get pinged. */
timer_test_add_offset(30); timer_test_add_offset(30);
cyclic_run(); schedule();
ut_asserteq(reset_count + 1, state->wdt.reset_count); ut_asserteq(reset_count + 1, state->wdt.reset_count);
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset)); ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));