Zephyr WWDT Driver Implementation
This page provides details on the implementation of the WWDT Zephyr driver.
Watchdog Subsystem
Watchdog subsystem has a structure where drivers need to register their APIs by following the same protocol used in the structure mentioned.
Zephyr Window Watchdog Timer driver stack.
Data structures
/** * @brief Watchdog timeout window. * * Each installed timeout needs feeding within the specified time window, * otherwise the watchdog will trigger. If the watchdog instance does not * support window timeouts then min value must be equal to 0. * * @note If specified values can not be precisely set they are always rounded * up. */ struct wdt_window { /** Lower limit of watchdog feed timeout in milliseconds. */ uint32_t min; /** Upper limit of watchdog feed timeout in milliseconds. */ uint32_t max; }; /** @brief Watchdog timeout configuration. */ struct wdt_timeout_cfg { /** Timing parameters of watchdog timeout. */ struct wdt_window window; /** Timeout callback (can be `NULL`). */ wdt_callback_t callback; #if defined(CONFIG_WDT_MULTISTAGE) || defined(__DOXYGEN__) /** * Pointer to the next timeout configuration. * * This field is only available if @kconfig{CONFIG_WDT_MULTISTAGE} is * enabled (watchdogs with staged timeouts functionality). Value must be * `NULL` for single stage timeout. */ struct wdt_timeout_cfg *next; #endif /** Flags (see @ref WDT_FLAGS). */ uint8_t flags; };
Typedefs
/** * @brief Watchdog callback. * * @param dev Watchdog device instance. * @param channel_id Channel identifier. */ typedef void (*wdt_callback_t)(const struct device *dev, int channel_id);
Subsystem wdt_driver_api
__subsystem struct wdt_driver_api { wdt_api_setup setup; wdt_api_disable disable; wdt_api_install_timeout install_timeout; wdt_api_feed feed; };
Watchdog Options
#define WDT_OPT_PAUSE_IN_SLEEP BIT(0) /* Pause watchdog timer when CPU is in sleep state. */ #define WDT_OPT_PAUSE_HALTED_BY_DBG BIT(1) /* Pause watchdog timer when CPU is halted by the debugger. */
Watchdog Behavior Flags
#define WDT_FLAG_RESET_NONE (0 << WDT_FLAG_RESET_SHIFT) Reset: none. #define WDT_FLAG_RESET_CPU_CORE (1 << WDT_FLAG_RESET_SHIFT) Reset: CPU core. #define WDT_FLAG_RESET_SOC (2 << WDT_FLAG_RESET_SHIFT) Reset: SoC.
wdt_setup()
int wdt_setup(const struct device *dev, uint8_t options);
Setup the watchdog instance.
This function is used for configuring global watchdog settings that affect all timeouts. Call it after installing timeouts. After successful return, all installed timeouts are valid and must be serviced periodically by calling wdt_feed().
Parameters
dev |
Watchdog device instance. |
options |
Configuration options (see Watchdog Options). |
Return Values for wdt_setup()
0 |
If successful. |
-ENOTSUP |
If any of the set options is not supported. |
-EBUSY |
If the watchdog instance is already set up. |
-errno |
In case of any other failure. |
wdt_install_timeout()
static int wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
Install a new timeout.
Note: This function must be used before wdt_setup(). Changes applied here have no effects until wdt_setup() is called.
Parameters
dev |
Watchdog device instance |
cfg |
Timeout configuration |
Return Values for wdt_install_timeout()
channel_id |
If successful, a non-negative value indicating the index of the channel to which the timeout was assigned. This value is supposed to be used as the parameter in calls to wdt_feed(). |
-EBUSY |
If timeout can not be installed while watchdog has already been setup. |
-ENOMEM |
If no more timeouts can be installed. |
-ENOTSUP |
If any of the set flags is not supported. |
-EINVAL |
If any of the window timeout value is out of possible range. This value is also returned if watchdog supports only one timeout value for all timeouts and the supplied timeout window differs from windows for alarms installed so far. |
-errno |
In case of any other failure. |
wdt_feed()
int wdt_feed (const struct device *dev, int channel_id)
Feed specified watchdog timeout.
Parameters
dev |
Watchdog device instance. |
channel_id |
Channel index. |
Return Values for wdt_feed()
0 |
If successful. |
-EAGAIN |
If completing the feed operation stalls the caller, for example due to an in-progress watchdog operation such as a previous wdt_feed() call. |
-EINVAL |
If there is no installed timeout for supplied channel. |
-errno |
In case of any other failure. |
wdt_disable()
int wdt_disable (const struct device *dev)
Disable watchdog instance.
This function disables the watchdog instance and automatically uninstalls all timeouts. To set up a new watchdog, install timeouts and call wdt_setup() again.
Not all watchdogs can be restarted after they are disabled.
Parameters
dev |
Watchdog device instance. |
Return Values for wdt_disable()
0 |
If successful. |
-EFAULT |
If watchdog instance is not enabled. |
-EPERM |
If the watchdog cannot be disabled directly by application code. |
-errno |
In case of any other failure. |
Wwdt Node
DT Node
wwdt0: watchdog@ecc10000 { compatible = "xlnx,versal-wwdt"; status = "okay"; reg = <0xecc10000 0x10000>; timeout-sec = <30>; clocks = <&wwdtclk>; };
zephyr/drivers/watchdog/CMakeLists.txt
zephyr_library_sources_ifdef(CONFIG_XILINX_WINDOW_WATCHDOG wdt_xilinx_wwdt.c)
zephyr/drivers/watchdog/Kconfig
source "drivers/watchdog/Kconfig.xilinx_wwdt"
zephyr/drivers/watchdog/Kconfig.xilinx_wwdt
# # # License info config XILINX_WINDOW_WATCHDOG bool "Xilinx window watchdog driver" default y depends on DT_HAS_XLNX_VERSAL_WWDT_ENABLED help Enable Window watchdog driver for the versal_wwdt IP core. Window watchdog timer(WWDT) contains closed(first) and open(second) window with 32 bit width. Write to the watchdog timer within predefined window periods of time. This means a period that is not too soon and a period that is not too late. The WWDT has to be restarted within the open window time. If software tries to restart WWDT outside of the open window time period, it generates a SOC reset.
zephyr/dts/bindings/watchdog/xlnx,versal-wwdt.yaml
# #License description: Xilinx window watchdog compatible: "xlnx,versal-wwdt" include: base.yaml properties: reg: required: true timeout-sec: type: int required: true description: Timeout value in seconds. clocks: required: true description: Reference to clock for window watchdog core.
Probe
#define WDT_XILINX_WWDT_INIT(inst) \ static struct xilinx_wwdt_data wdt_xilinx_wwdt_##inst##_dev_data; \ \ static const struct xilinx_wwdt_config wdt_xilinx_wwdt_##inst##_cfg = { \ .base = DT_INST_REG_ADDR(inst), \ .timeout_sec = DT_INST_PROP(inst, timeout_sec), \ .wdt_clock_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency), \ }; \ \ DEVICE_DT_INST_DEFINE(inst, &wdt_xilinx_wwdt_init, NULL, \ &wdt_xilinx_wwdt_##inst##_dev_data, \ &wdt_xilinx_wwdt_##inst##_cfg, PRE_KERNEL_1, \ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_xilinx_wwdt_api); DT_INST_FOREACH_STATUS_OKAY(WDT_XILINX_WWDT_INIT)
Functional Implementation
wdt_xilinx_wwdt_install_timeout
Find timeout passed by user in milli-seconds.
Find maximum timeout supported by hardware in milli-seconds.
If the maximum limit of the window is passed from the user space, overwrite the timeout with this value.
If timeout_ms > maximum_ms, it is invalid.
The config→window.max passed by user is upper limit of watchdog feed timeout in ms. It must not be greater than the timeout passed by the user.
Calculate ticks for 1milli-second and timeout in ticks.
closed_window_ms_ticks = cfg→window.min * ms_ticks.
If closed window ms ticks exceeds 32bit, its invalid.
Calculate open_window_ms_ticks = timeout_ms_ticks - closed_window_ms_ticks.
If open_window_ms_ticks exceeds 32bit, its invalid.
If the open window and closed window ticks are valid, write to FWR, SWR register.
wdt_xilinx_wwdt_setup
Write to ESR_WEN to start the watchdog.
wdt_xilinx_wwdt_feed
Enable write access for wwdt.
Check if the watchdog is in closed or open window. If in closed window, return -ENOTSUP.
Restart the watchdog by writing to ESR_WSW reg.
wdt_xilinx_wwdt_disable
Disable in the second window.
If watchdog is in second window, disable by writing to ESR.