mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-11-29 14:41:26 +01:00
Merge branch 'next' of https://gitlab.denx.de/u-boot/custodians/u-boot-marvell into next
- Handling all DM watchdogs in watchdog_reset() (Rasmus)
This commit is contained in:
commit
e2e5eec6ce
@ -793,6 +793,13 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gpio-wdt {
|
||||||
|
gpios = <&gpio_a 7 0>;
|
||||||
|
compatible = "linux,wdt-gpio";
|
||||||
|
hw_margin_ms = <100>;
|
||||||
|
always-running;
|
||||||
|
};
|
||||||
|
|
||||||
mbox: mbox {
|
mbox: mbox {
|
||||||
compatible = "sandbox,mbox";
|
compatible = "sandbox,mbox";
|
||||||
#mbox-cells = <1>;
|
#mbox-cells = <1>;
|
||||||
@ -1272,6 +1279,7 @@
|
|||||||
|
|
||||||
wdt0: wdt@0 {
|
wdt0: wdt@0 {
|
||||||
compatible = "sandbox,wdt";
|
compatible = "sandbox,wdt";
|
||||||
|
hw_margin_ms = <200>;
|
||||||
};
|
};
|
||||||
|
|
||||||
axi: axi@0 {
|
axi: axi@0 {
|
||||||
|
|||||||
@ -121,9 +121,8 @@ int board_init(void)
|
|||||||
|
|
||||||
void arch_preboot_os(void)
|
void arch_preboot_os(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_WATCHDOG
|
if (CONFIG_IS_ENABLED(WDT))
|
||||||
wdt_stop(gd->watchdog_dev);
|
wdt_stop_all();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int led_7seg_init(unsigned int segments)
|
static int led_7seg_init(unsigned int segments)
|
||||||
|
|||||||
@ -225,7 +225,9 @@ CONFIG_OSD=y
|
|||||||
CONFIG_SANDBOX_OSD=y
|
CONFIG_SANDBOX_OSD=y
|
||||||
CONFIG_SPLASH_SCREEN_ALIGN=y
|
CONFIG_SPLASH_SCREEN_ALIGN=y
|
||||||
CONFIG_VIDEO_BMP_RLE8=y
|
CONFIG_VIDEO_BMP_RLE8=y
|
||||||
|
# CONFIG_WATCHDOG_AUTOSTART is not set
|
||||||
CONFIG_WDT=y
|
CONFIG_WDT=y
|
||||||
|
CONFIG_WDT_GPIO=y
|
||||||
CONFIG_WDT_SANDBOX=y
|
CONFIG_WDT_SANDBOX=y
|
||||||
CONFIG_FS_CBFS=y
|
CONFIG_FS_CBFS=y
|
||||||
CONFIG_FS_CRAMFS=y
|
CONFIG_FS_CRAMFS=y
|
||||||
|
|||||||
@ -283,7 +283,9 @@ CONFIG_W1=y
|
|||||||
CONFIG_W1_GPIO=y
|
CONFIG_W1_GPIO=y
|
||||||
CONFIG_W1_EEPROM=y
|
CONFIG_W1_EEPROM=y
|
||||||
CONFIG_W1_EEPROM_SANDBOX=y
|
CONFIG_W1_EEPROM_SANDBOX=y
|
||||||
|
# CONFIG_WATCHDOG_AUTOSTART is not set
|
||||||
CONFIG_WDT=y
|
CONFIG_WDT=y
|
||||||
|
CONFIG_WDT_GPIO=y
|
||||||
CONFIG_WDT_SANDBOX=y
|
CONFIG_WDT_SANDBOX=y
|
||||||
CONFIG_FS_CBFS=y
|
CONFIG_FS_CBFS=y
|
||||||
CONFIG_FS_CRAMFS=y
|
CONFIG_FS_CRAMFS=y
|
||||||
|
|||||||
19
doc/device-tree-bindings/watchdog/gpio-wdt.txt
Normal file
19
doc/device-tree-bindings/watchdog/gpio-wdt.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
GPIO watchdog timer
|
||||||
|
|
||||||
|
Describes a simple watchdog timer which is reset by toggling a gpio.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: Must be "linux,wdt-gpio".
|
||||||
|
- gpios: gpio to toggle when wdt driver reset method is called.
|
||||||
|
- always-running: Boolean property indicating that the watchdog cannot
|
||||||
|
be disabled. At present, U-Boot only supports this kind of GPIO
|
||||||
|
watchdog.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
gpio-wdt {
|
||||||
|
gpios = <&gpio0 1 0>;
|
||||||
|
compatible = "linux,wdt-gpio";
|
||||||
|
always-running;
|
||||||
|
};
|
||||||
@ -147,6 +147,15 @@ config WDT_CORTINA
|
|||||||
This driver support all CPU ISAs supported by Cortina
|
This driver support all CPU ISAs supported by Cortina
|
||||||
Access CAxxxx SoCs.
|
Access CAxxxx SoCs.
|
||||||
|
|
||||||
|
config WDT_GPIO
|
||||||
|
bool "External gpio watchdog support"
|
||||||
|
depends on WDT
|
||||||
|
depends on DM_GPIO
|
||||||
|
help
|
||||||
|
Support for external watchdog fed by toggling a gpio. See
|
||||||
|
doc/device-tree-bindings/watchdog/gpio-wdt.txt for
|
||||||
|
information on how to describe the watchdog in device tree.
|
||||||
|
|
||||||
config WDT_MPC8xx
|
config WDT_MPC8xx
|
||||||
bool "MPC8xx watchdog timer support"
|
bool "MPC8xx watchdog timer support"
|
||||||
depends on WDT && MPC8xx
|
depends on WDT && MPC8xx
|
||||||
|
|||||||
@ -25,6 +25,7 @@ obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o
|
|||||||
obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
|
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_GPIO) += gpio_wdt.o
|
||||||
obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
|
obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
|
||||||
obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o
|
obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o
|
||||||
obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
|
obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
|
||||||
|
|||||||
68
drivers/watchdog/gpio_wdt.c
Normal file
68
drivers/watchdog/gpio_wdt.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dm/device_compat.h>
|
||||||
|
#include <wdt.h>
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
|
||||||
|
struct gpio_wdt_priv {
|
||||||
|
struct gpio_desc gpio;
|
||||||
|
bool always_running;
|
||||||
|
int state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int gpio_wdt_reset(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct gpio_wdt_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
priv->state = !priv->state;
|
||||||
|
|
||||||
|
return dm_gpio_set_value(&priv->gpio, priv->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
||||||
|
{
|
||||||
|
struct gpio_wdt_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
if (priv->always_running)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct gpio_wdt_priv *priv = dev_get_priv(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv->always_running = dev_read_bool(dev, "always-running");
|
||||||
|
ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "Request for wdt gpio failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->always_running)
|
||||||
|
ret = gpio_wdt_reset(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wdt_ops gpio_wdt_ops = {
|
||||||
|
.start = gpio_wdt_start,
|
||||||
|
.reset = gpio_wdt_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct udevice_id gpio_wdt_ids[] = {
|
||||||
|
{ .compatible = "linux,wdt-gpio" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(wdt_gpio) = {
|
||||||
|
.name = "wdt_gpio",
|
||||||
|
.id = UCLASS_WDT,
|
||||||
|
.of_match = gpio_wdt_ids,
|
||||||
|
.ops = &gpio_wdt_ops,
|
||||||
|
.probe = dm_probe,
|
||||||
|
.priv_auto = sizeof(struct gpio_wdt_priv),
|
||||||
|
};
|
||||||
@ -20,53 +20,67 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||||||
|
|
||||||
#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
|
#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
|
||||||
|
|
||||||
/*
|
struct wdt_priv {
|
||||||
* Reset every 1000ms, or however often is required as indicated by a
|
/* Timeout, in seconds, to configure this device to. */
|
||||||
* hw_margin_ms property.
|
u32 timeout;
|
||||||
|
/*
|
||||||
|
* Time, in milliseconds, between calling the device's ->reset()
|
||||||
|
* method from watchdog_reset().
|
||||||
*/
|
*/
|
||||||
static ulong reset_period = 1000;
|
ulong reset_period;
|
||||||
|
/*
|
||||||
|
* Next time (as returned by get_timer(0)) to call
|
||||||
|
* ->reset().
|
||||||
|
*/
|
||||||
|
ulong next_reset;
|
||||||
|
/* Whether watchdog_start() has been called on the device. */
|
||||||
|
bool running;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init_watchdog_dev(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct wdt_priv *priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv = dev_get_uclass_priv(dev);
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) {
|
||||||
|
printf("WDT: Not starting %s\n", dev->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wdt_start(dev, priv->timeout * 1000, 0);
|
||||||
|
if (ret != 0) {
|
||||||
|
printf("WDT: Failed to start %s\n", dev->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("WDT: Started %s with%s servicing (%ds timeout)\n", dev->name,
|
||||||
|
IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", priv->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
int initr_watchdog(void)
|
int initr_watchdog(void)
|
||||||
{
|
{
|
||||||
u32 timeout = WATCHDOG_TIMEOUT_SECS;
|
struct udevice *dev;
|
||||||
|
struct uclass *uc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
ret = uclass_get(UCLASS_WDT, &uc);
|
||||||
* Init watchdog: This will call the probe function of the
|
if (ret) {
|
||||||
* watchdog driver, enabling the use of the device
|
log_debug("Error getting UCLASS_WDT: %d\n", ret);
|
||||||
*/
|
|
||||||
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) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
|
||||||
timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec",
|
|
||||||
WATCHDOG_TIMEOUT_SECS);
|
|
||||||
reset_period = dev_read_u32_default(gd->watchdog_dev,
|
|
||||||
"hw_margin_ms",
|
|
||||||
4 * reset_period) / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) {
|
|
||||||
printf("WDT: Not starting\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wdt_start(gd->watchdog_dev, timeout * 1000, 0);
|
uclass_foreach_dev(dev, uc) {
|
||||||
if (ret != 0) {
|
ret = device_probe(dev);
|
||||||
printf("WDT: Failed to start\n");
|
if (ret) {
|
||||||
return 0;
|
log_debug("Error probing %s: %d\n", dev->name, ret);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
init_watchdog_dev(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("WDT: Started with%s servicing (%ds timeout)\n",
|
gd->flags |= GD_FLG_WDT_READY;
|
||||||
IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,8 +93,11 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
|
|||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
||||||
ret = ops->start(dev, timeout_ms, flags);
|
ret = ops->start(dev, timeout_ms, flags);
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
gd->flags |= GD_FLG_WDT_READY;
|
struct wdt_priv *priv = dev_get_uclass_priv(dev);
|
||||||
|
|
||||||
|
priv->running = true;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -94,8 +111,36 @@ int wdt_stop(struct udevice *dev)
|
|||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
||||||
ret = ops->stop(dev);
|
ret = ops->stop(dev);
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
gd->flags &= ~GD_FLG_WDT_READY;
|
struct wdt_priv *priv = dev_get_uclass_priv(dev);
|
||||||
|
|
||||||
|
priv->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wdt_stop_all(void)
|
||||||
|
{
|
||||||
|
struct wdt_priv *priv;
|
||||||
|
struct udevice *dev;
|
||||||
|
struct uclass *uc;
|
||||||
|
int ret, err;
|
||||||
|
|
||||||
|
ret = uclass_get(UCLASS_WDT, &uc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
uclass_foreach_dev(dev, uc) {
|
||||||
|
if (!device_active(dev))
|
||||||
|
continue;
|
||||||
|
priv = dev_get_uclass_priv(dev);
|
||||||
|
if (!priv->running)
|
||||||
|
continue;
|
||||||
|
err = wdt_stop(dev);
|
||||||
|
if (!ret)
|
||||||
|
ret = err;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -120,10 +165,8 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
|
|||||||
if (ops->expire_now) {
|
if (ops->expire_now) {
|
||||||
return ops->expire_now(dev, flags);
|
return ops->expire_now(dev, flags);
|
||||||
} else {
|
} else {
|
||||||
if (!ops->start)
|
ret = wdt_start(dev, 1, flags);
|
||||||
return -ENOSYS;
|
|
||||||
|
|
||||||
ret = ops->start(dev, 1, flags);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -141,18 +184,36 @@ int wdt_expire_now(struct udevice *dev, ulong flags)
|
|||||||
*/
|
*/
|
||||||
void watchdog_reset(void)
|
void watchdog_reset(void)
|
||||||
{
|
{
|
||||||
static ulong next_reset;
|
struct wdt_priv *priv;
|
||||||
|
struct udevice *dev;
|
||||||
|
struct uclass *uc;
|
||||||
ulong now;
|
ulong now;
|
||||||
|
|
||||||
/* Exit if GD is not ready or watchdog is not initialized yet */
|
/* Exit if GD is not ready or watchdog is not initialized yet */
|
||||||
if (!gd || !(gd->flags & GD_FLG_WDT_READY))
|
if (!gd || !(gd->flags & GD_FLG_WDT_READY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (uclass_get(UCLASS_WDT, &uc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All devices bound to the wdt uclass should have been probed
|
||||||
|
* in initr_watchdog(). But just in case something went wrong,
|
||||||
|
* check device_active() before accessing the uclass private
|
||||||
|
* data.
|
||||||
|
*/
|
||||||
|
uclass_foreach_dev(dev, uc) {
|
||||||
|
if (!device_active(dev))
|
||||||
|
continue;
|
||||||
|
priv = dev_get_uclass_priv(dev);
|
||||||
|
if (!priv->running)
|
||||||
|
continue;
|
||||||
/* Do not reset the watchdog too often */
|
/* Do not reset the watchdog too often */
|
||||||
now = get_timer(0);
|
now = get_timer(0);
|
||||||
if (time_after_eq(now, next_reset)) {
|
if (time_after_eq(now, priv->next_reset)) {
|
||||||
next_reset = now + reset_period;
|
priv->next_reset = now + priv->reset_period;
|
||||||
wdt_reset(gd->watchdog_dev);
|
wdt_reset(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -179,9 +240,38 @@ static int wdt_post_bind(struct udevice *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wdt_pre_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
u32 timeout = WATCHDOG_TIMEOUT_SECS;
|
||||||
|
/*
|
||||||
|
* Reset every 1000ms, or however often is required as
|
||||||
|
* indicated by a hw_margin_ms property.
|
||||||
|
*/
|
||||||
|
ulong reset_period = 1000;
|
||||||
|
struct wdt_priv *priv;
|
||||||
|
|
||||||
|
if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||||
|
timeout = dev_read_u32_default(dev, "timeout-sec", timeout);
|
||||||
|
reset_period = dev_read_u32_default(dev, "hw_margin_ms",
|
||||||
|
4 * reset_period) / 4;
|
||||||
|
}
|
||||||
|
priv = dev_get_uclass_priv(dev);
|
||||||
|
priv->timeout = timeout;
|
||||||
|
priv->reset_period = reset_period;
|
||||||
|
/*
|
||||||
|
* Pretend this device was last reset "long" ago so the first
|
||||||
|
* watchdog_reset will actually call its ->reset method.
|
||||||
|
*/
|
||||||
|
priv->next_reset = get_timer(0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
UCLASS_DRIVER(wdt) = {
|
UCLASS_DRIVER(wdt) = {
|
||||||
.id = UCLASS_WDT,
|
.id = UCLASS_WDT,
|
||||||
.name = "watchdog",
|
.name = "watchdog",
|
||||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||||
.post_bind = wdt_post_bind,
|
.post_bind = wdt_post_bind,
|
||||||
|
.pre_probe = wdt_pre_probe,
|
||||||
|
.per_device_auto = sizeof(struct wdt_priv),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -447,12 +447,6 @@ struct global_data {
|
|||||||
*/
|
*/
|
||||||
fdt_addr_t translation_offset;
|
fdt_addr_t translation_offset;
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_IS_ENABLED(WDT)
|
|
||||||
/**
|
|
||||||
* @watchdog_dev: watchdog device
|
|
||||||
*/
|
|
||||||
struct udevice *watchdog_dev;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_GENERATE_ACPI_TABLE
|
#ifdef CONFIG_GENERATE_ACPI_TABLE
|
||||||
/**
|
/**
|
||||||
* @acpi_ctx: ACPI context pointer
|
* @acpi_ctx: ACPI context pointer
|
||||||
|
|||||||
@ -37,6 +37,14 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags);
|
|||||||
*/
|
*/
|
||||||
int wdt_stop(struct udevice *dev);
|
int wdt_stop(struct udevice *dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop all registered watchdog devices.
|
||||||
|
*
|
||||||
|
* @return: 0 if ok, first error encountered otherwise (but wdt_stop()
|
||||||
|
* is still called on following devices)
|
||||||
|
*/
|
||||||
|
int wdt_stop_all(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the timer, typically restoring the counter to
|
* Reset the timer, typically restoring the counter to
|
||||||
* the value configured by start()
|
* the value configured by start()
|
||||||
|
|||||||
@ -6,11 +6,14 @@
|
|||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <wdt.h>
|
#include <wdt.h>
|
||||||
|
#include <asm/gpio.h>
|
||||||
#include <asm/state.h>
|
#include <asm/state.h>
|
||||||
#include <asm/test.h>
|
#include <asm/test.h>
|
||||||
#include <dm/test.h>
|
#include <dm/test.h>
|
||||||
#include <test/test.h>
|
#include <test/test.h>
|
||||||
#include <test/ut.h>
|
#include <test/ut.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <watchdog.h>
|
||||||
|
|
||||||
/* Test that watchdog driver functions are called */
|
/* Test that watchdog driver functions are called */
|
||||||
static int dm_test_wdt_base(struct unit_test_state *uts)
|
static int dm_test_wdt_base(struct unit_test_state *uts)
|
||||||
@ -19,7 +22,8 @@ static int dm_test_wdt_base(struct unit_test_state *uts)
|
|||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
const u64 timeout = 42;
|
const u64 timeout = 42;
|
||||||
|
|
||||||
ut_assertok(uclass_get_device(UCLASS_WDT, 0, &dev));
|
ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
|
||||||
|
DM_DRIVER_GET(wdt_sandbox), &dev));
|
||||||
ut_assertnonnull(dev);
|
ut_assertnonnull(dev);
|
||||||
ut_asserteq(0, state->wdt.counter);
|
ut_asserteq(0, state->wdt.counter);
|
||||||
ut_asserteq(false, state->wdt.running);
|
ut_asserteq(false, state->wdt.running);
|
||||||
@ -39,3 +43,87 @@ static int dm_test_wdt_base(struct unit_test_state *uts)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DM_TEST(dm_test_wdt_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
DM_TEST(dm_test_wdt_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
static int dm_test_wdt_gpio(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The sandbox wdt gpio is "connected" to gpio bank a, offset
|
||||||
|
* 7. Use the sandbox back door to verify that the gpio-wdt
|
||||||
|
* driver behaves as expected.
|
||||||
|
*/
|
||||||
|
struct udevice *wdt, *gpio;
|
||||||
|
const u64 timeout = 42;
|
||||||
|
const int offset = 7;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
|
||||||
|
DM_DRIVER_GET(wdt_gpio), &wdt));
|
||||||
|
ut_assertnonnull(wdt);
|
||||||
|
|
||||||
|
ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
|
||||||
|
ut_assertnonnull(gpio);
|
||||||
|
ut_assertok(wdt_start(wdt, timeout, 0));
|
||||||
|
|
||||||
|
val = sandbox_gpio_get_value(gpio, offset);
|
||||||
|
ut_assertok(wdt_reset(wdt));
|
||||||
|
ut_asserteq(!val, sandbox_gpio_get_value(gpio, offset));
|
||||||
|
ut_assertok(wdt_reset(wdt));
|
||||||
|
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
|
||||||
|
|
||||||
|
ut_asserteq(-ENOSYS, wdt_stop(wdt));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_wdt_gpio, UT_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct sandbox_state *state = state_get_current();
|
||||||
|
struct udevice *gpio_wdt, *sandbox_wdt;
|
||||||
|
struct udevice *gpio;
|
||||||
|
const u64 timeout = 42;
|
||||||
|
const int offset = 7;
|
||||||
|
uint reset_count;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
|
||||||
|
DM_DRIVER_GET(wdt_gpio), &gpio_wdt));
|
||||||
|
ut_assertnonnull(gpio_wdt);
|
||||||
|
ut_assertok(uclass_get_device_by_driver(UCLASS_WDT,
|
||||||
|
DM_DRIVER_GET(wdt_sandbox), &sandbox_wdt));
|
||||||
|
ut_assertnonnull(sandbox_wdt);
|
||||||
|
ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
|
||||||
|
ut_assertnonnull(gpio);
|
||||||
|
|
||||||
|
/* Neither device should be "started", so watchdog_reset() should be a no-op. */
|
||||||
|
reset_count = state->wdt.reset_count;
|
||||||
|
val = sandbox_gpio_get_value(gpio, offset);
|
||||||
|
watchdog_reset();
|
||||||
|
ut_asserteq(reset_count, state->wdt.reset_count);
|
||||||
|
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
|
||||||
|
|
||||||
|
/* Start both devices. */
|
||||||
|
ut_assertok(wdt_start(gpio_wdt, timeout, 0));
|
||||||
|
ut_assertok(wdt_start(sandbox_wdt, timeout, 0));
|
||||||
|
|
||||||
|
/* Make sure both devices have just been pinged. */
|
||||||
|
timer_test_add_offset(100);
|
||||||
|
watchdog_reset();
|
||||||
|
reset_count = state->wdt.reset_count;
|
||||||
|
val = sandbox_gpio_get_value(gpio, offset);
|
||||||
|
|
||||||
|
/* The gpio watchdog should be pinged, the sandbox one not. */
|
||||||
|
timer_test_add_offset(30);
|
||||||
|
watchdog_reset();
|
||||||
|
ut_asserteq(reset_count, state->wdt.reset_count);
|
||||||
|
ut_asserteq(!val, sandbox_gpio_get_value(gpio, offset));
|
||||||
|
|
||||||
|
/* After another ~30ms, both devices should get pinged. */
|
||||||
|
timer_test_add_offset(30);
|
||||||
|
watchdog_reset();
|
||||||
|
ut_asserteq(reset_count + 1, state->wdt.reset_count);
|
||||||
|
ut_asserteq(val, sandbox_gpio_get_value(gpio, offset));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_wdt_watchdog_reset, UT_TESTF_SCAN_FDT);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user