};
};
};
+
+ wdt0: wdt@0 {
+ compatible = "sandbox,wdt";
+ };
};
#include "sandbox_pmic.dtsi"
struct udevice *emul;
};
+struct sandbox_wdt_info {
+ unsigned long long counter;
+ uint reset_count;
+ bool running;
+};
+
/* The complete state of the test system */
struct sandbox_state {
const char *cmd; /* Command to execute */
/* Pointer to information for each SPI bus/cs */
struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS]
[CONFIG_SANDBOX_SPI_MAX_CS];
+
+ /* Information about Watchdog */
+ struct sandbox_wdt_info wdt;
};
/* Minimum space we guarantee in the state FDT when calling read/write*/
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
CONFIG_UT_ENV=y
+CONFIG_WDT=y
+CONFIG_WDT_SANDBOX=y
-menu "WATCHDOG support"
+menu "Watchdog Timer Support"
config ULP_WATCHDOG
bool "i.MX7ULP watchdog"
help
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
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
+obj-$(CONFIG_WDT) += wdt-uclass.o
+obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+/*
+ * 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",
+};
UCLASS_VIDEO, /* Video or LCD device */
UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */
+ UCLASS_WDT, /* Watchdot Timer driver */
UCLASS_COUNT,
UCLASS_INVALID = -1,
--- /dev/null
+/*
+ * 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_ */
obj-$(CONFIG_DM_VIDEO) += video.o
obj-$(CONFIG_ADC) += adc.o
obj-$(CONFIG_SPMI) += spmi.o
+obj-$(CONFIG_WDT) += wdt.o
endif
--- /dev/null
+/*
+ * 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);