This is a simple uclass for Watchdog Timers. It has four operations: start, restart, reset, stop. Drivers must implement start, restart and stop operations, while implementing reset is optional: It's default implementation expires watchdog timer in one clock tick. Signed-off-by: Maxim Sloyko <maxims@google.com> Reviewed-by: Simon Glass <sjg@chromium.org>master
parent
17c5fb1953
commit
0753bc2d30
@ -1,8 +1,26 @@ |
|||||||
menu "WATCHDOG support" |
menu "Watchdog Timer Support" |
||||||
|
|
||||||
config ULP_WATCHDOG |
config ULP_WATCHDOG |
||||||
bool "i.MX7ULP watchdog" |
bool "i.MX7ULP watchdog" |
||||||
help |
help |
||||||
Say Y here to enable i.MX7ULP watchdog driver. |
Say Y here to enable i.MX7ULP watchdog driver. |
||||||
|
|
||||||
|
config WDT |
||||||
|
bool "Enable driver model for watchdog timer drivers" |
||||||
|
depends on DM |
||||||
|
help |
||||||
|
Enable driver model for watchdog timer. At the moment the API |
||||||
|
is very simple and only supports four operations: |
||||||
|
start, restart, stop and reset (expire immediately). |
||||||
|
What exactly happens when the timer expires is up to a particular |
||||||
|
device/driver. |
||||||
|
|
||||||
|
config WDT_SANDBOX |
||||||
|
bool "Enable Watchdog Timer support for Sandbox" |
||||||
|
depends on SANDBOX && WDT |
||||||
|
help |
||||||
|
Enable Watchdog Timer support in Sandbox. This is a dummy device that |
||||||
|
can be probed and supports all of the methods of WDT, but does not |
||||||
|
really do anything. |
||||||
|
|
||||||
endmenu |
endmenu |
||||||
|
@ -0,0 +1,76 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google, Inc |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <dm.h> |
||||||
|
#include <asm/state.h> |
||||||
|
#include <wdt.h> |
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR; |
||||||
|
|
||||||
|
static int sandbox_wdt_start(struct udevice *dev, u64 timeout, ulong flags) |
||||||
|
{ |
||||||
|
struct sandbox_state *state = state_get_current(); |
||||||
|
|
||||||
|
state->wdt.counter = timeout; |
||||||
|
state->wdt.running = true; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int sandbox_wdt_stop(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct sandbox_state *state = state_get_current(); |
||||||
|
|
||||||
|
state->wdt.running = false; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int sandbox_wdt_reset(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct sandbox_state *state = state_get_current(); |
||||||
|
|
||||||
|
state->wdt.reset_count++; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int sandbox_wdt_expire_now(struct udevice *dev, ulong flags) |
||||||
|
{ |
||||||
|
sandbox_wdt_start(dev, 1, flags); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int sandbox_wdt_probe(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct sandbox_state *state = state_get_current(); |
||||||
|
|
||||||
|
memset(&state->wdt, 0, sizeof(state->wdt)); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static const struct wdt_ops sandbox_wdt_ops = { |
||||||
|
.start = sandbox_wdt_start, |
||||||
|
.reset = sandbox_wdt_reset, |
||||||
|
.stop = sandbox_wdt_stop, |
||||||
|
.expire_now = sandbox_wdt_expire_now, |
||||||
|
}; |
||||||
|
|
||||||
|
static const struct udevice_id sandbox_wdt_ids[] = { |
||||||
|
{ .compatible = "sandbox,wdt" }, |
||||||
|
{} |
||||||
|
}; |
||||||
|
|
||||||
|
U_BOOT_DRIVER(wdt_sandbox) = { |
||||||
|
.name = "wdt_sandbox", |
||||||
|
.id = UCLASS_WDT, |
||||||
|
.of_match = sandbox_wdt_ids, |
||||||
|
.ops = &sandbox_wdt_ops, |
||||||
|
.probe = sandbox_wdt_probe, |
||||||
|
}; |
@ -0,0 +1,72 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google, Inc |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <dm.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <wdt.h> |
||||||
|
#include <dm/device-internal.h> |
||||||
|
#include <dm/lists.h> |
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR; |
||||||
|
|
||||||
|
int wdt_start(struct udevice *dev, u64 timeout, ulong flags) |
||||||
|
{ |
||||||
|
const struct wdt_ops *ops = device_get_ops(dev); |
||||||
|
|
||||||
|
if (!ops->start) |
||||||
|
return -ENOSYS; |
||||||
|
|
||||||
|
return ops->start(dev, timeout, flags); |
||||||
|
} |
||||||
|
|
||||||
|
int wdt_stop(struct udevice *dev) |
||||||
|
{ |
||||||
|
const struct wdt_ops *ops = device_get_ops(dev); |
||||||
|
|
||||||
|
if (!ops->stop) |
||||||
|
return -ENOSYS; |
||||||
|
|
||||||
|
return ops->stop(dev); |
||||||
|
} |
||||||
|
|
||||||
|
int wdt_reset(struct udevice *dev) |
||||||
|
{ |
||||||
|
const struct wdt_ops *ops = device_get_ops(dev); |
||||||
|
|
||||||
|
if (!ops->reset) |
||||||
|
return -ENOSYS; |
||||||
|
|
||||||
|
return ops->reset(dev); |
||||||
|
} |
||||||
|
|
||||||
|
int wdt_expire_now(struct udevice *dev, ulong flags) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
const struct wdt_ops *ops; |
||||||
|
|
||||||
|
debug("WDT Resettting: %lu\n", flags); |
||||||
|
ops = device_get_ops(dev); |
||||||
|
if (ops->expire_now) { |
||||||
|
return ops->expire_now(dev, flags); |
||||||
|
} else { |
||||||
|
if (!ops->start) |
||||||
|
return -ENOSYS; |
||||||
|
|
||||||
|
ret = ops->start(dev, 1, flags); |
||||||
|
if (ret < 0) |
||||||
|
return ret; |
||||||
|
|
||||||
|
hang(); |
||||||
|
} |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
UCLASS_DRIVER(wdt) = { |
||||||
|
.id = UCLASS_WDT, |
||||||
|
.name = "wdt", |
||||||
|
}; |
@ -0,0 +1,107 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google, Inc |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _WDT_H_ |
||||||
|
#define _WDT_H_ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement a simple watchdog uclass. Watchdog is basically a timer that |
||||||
|
* is used to detect or recover from malfunction. During normal operation |
||||||
|
* the watchdog would be regularly reset to prevent it from timing out. |
||||||
|
* If, due to a hardware fault or program error, the computer fails to reset |
||||||
|
* the watchdog, the timer will elapse and generate a timeout signal. |
||||||
|
* The timeout signal is used to initiate corrective action or actions, |
||||||
|
* which typically include placing the system in a safe, known state. |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the timer |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @timeout: Number of ticks before timer expires |
||||||
|
* @flags: Driver specific flags. This might be used to specify |
||||||
|
* which action needs to be executed when the timer expires |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int wdt_start(struct udevice *dev, u64 timeout, ulong flags); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop the timer, thus disabling the Watchdog. Use wdt_start to start it again. |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int wdt_stop(struct udevice *dev); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the timer, typically restoring the counter to |
||||||
|
* the value configured by start() |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int wdt_reset(struct udevice *dev); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Expire the timer, thus executing its action immediately. |
||||||
|
* This is typically used to reset the board or peripherals. |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @flags: Driver specific flags |
||||||
|
* @return 0 if OK -ve on error. If wdt action is system reset, |
||||||
|
* this function may never return. |
||||||
|
*/ |
||||||
|
int wdt_expire_now(struct udevice *dev, ulong flags); |
||||||
|
|
||||||
|
/*
|
||||||
|
* struct wdt_ops - Driver model wdt operations |
||||||
|
* |
||||||
|
* The uclass interface is implemented by all wdt devices which use |
||||||
|
* driver model. |
||||||
|
*/ |
||||||
|
struct wdt_ops { |
||||||
|
/*
|
||||||
|
* Start the timer |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @timeout: Number of ticks before the timer expires |
||||||
|
* @flags: Driver specific flags. This might be used to specify |
||||||
|
* which action needs to be executed when the timer expires |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int (*start)(struct udevice *dev, u64 timeout, ulong flags); |
||||||
|
/*
|
||||||
|
* Stop the timer |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int (*stop)(struct udevice *dev); |
||||||
|
/*
|
||||||
|
* Reset the timer, typically restoring the counter to |
||||||
|
* the value configured by start() |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @return: 0 if OK, -ve on error |
||||||
|
*/ |
||||||
|
int (*reset)(struct udevice *dev); |
||||||
|
/*
|
||||||
|
* Expire the timer, thus executing the action immediately (optional) |
||||||
|
* |
||||||
|
* If this function is not provided, a default implementation |
||||||
|
* will be used, which sets the counter to 1 |
||||||
|
* and waits forever. This is good enough for system level |
||||||
|
* reset, where the function is not expected to return, but might not be |
||||||
|
* good enough for other use cases. |
||||||
|
* |
||||||
|
* @dev: WDT Device |
||||||
|
* @flags: Driver specific flags |
||||||
|
* @return 0 if OK -ve on error. May not return. |
||||||
|
*/ |
||||||
|
int (*expire_now)(struct udevice *dev, ulong flags); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif /* _WDT_H_ */ |
@ -0,0 +1,40 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google, Inc |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <dm.h> |
||||||
|
#include <wdt.h> |
||||||
|
#include <asm/state.h> |
||||||
|
#include <asm/test.h> |
||||||
|
#include <dm/test.h> |
||||||
|
#include <test/ut.h> |
||||||
|
|
||||||
|
/* Test that watchdog driver functions are called */ |
||||||
|
static int dm_test_wdt_base(struct unit_test_state *uts) |
||||||
|
{ |
||||||
|
struct sandbox_state *state = state_get_current(); |
||||||
|
struct udevice *dev; |
||||||
|
const u64 timeout = 42; |
||||||
|
|
||||||
|
ut_assertok(uclass_get_device(UCLASS_WDT, 0, &dev)); |
||||||
|
ut_asserteq(0, state->wdt.counter); |
||||||
|
ut_asserteq(false, state->wdt.running); |
||||||
|
|
||||||
|
ut_assertok(wdt_start(dev, timeout, 0)); |
||||||
|
ut_asserteq(timeout, state->wdt.counter); |
||||||
|
ut_asserteq(true, state->wdt.running); |
||||||
|
|
||||||
|
uint reset_count = state->wdt.reset_count; |
||||||
|
ut_assertok(wdt_reset(dev)); |
||||||
|
ut_asserteq(reset_count + 1, state->wdt.reset_count); |
||||||
|
ut_asserteq(true, state->wdt.running); |
||||||
|
|
||||||
|
ut_assertok(wdt_stop(dev)); |
||||||
|
ut_asserteq(false, state->wdt.running); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
DM_TEST(dm_test_wdt_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); |
Loading…
Reference in new issue