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 WWDT (wdt_xilinx_wwdt) driver stack: the application calls into the watchdog subsystem, which calls the driver setup / install-timeout / feed / disable callbacks, and the driver issues sys_write32 / sys_read32 register accesses to the hardware.

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

  1. Find timeout passed by user in milli-seconds.

  2. Find maximum timeout supported by hardware in milli-seconds.

  3. If the maximum limit of the window is passed from the user space, overwrite the timeout with this value.

  4. If timeout_ms > maximum_ms, it is invalid.

  5. 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.

  6. Calculate ticks for 1milli-second and timeout in ticks.

  7. closed_window_ms_ticks = cfg→window.min * ms_ticks.

  8. If closed window ms ticks exceeds 32bit, its invalid.

  9. Calculate open_window_ms_ticks = timeout_ms_ticks - closed_window_ms_ticks.

  10. If open_window_ms_ticks exceeds 32bit, its invalid.

  11. If the open window and closed window ticks are valid, write to FWR, SWR register.

wdt_xilinx_wwdt_setup

  1. Write to ESR_WEN to start the watchdog.

wdt_xilinx_wwdt_feed

  1. Enable write access for wwdt.

  2. Check if the watchdog is in closed or open window. If in closed window, return -ENOTSUP.

  3. Restart the watchdog by writing to ESR_WSW reg.

wdt_xilinx_wwdt_disable

  1. Disable in the second window.

  2. If watchdog is in second window, disable by writing to ESR.