diff --git a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts index 6eb8c2e155e..19f56f8b289 100644 --- a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts +++ b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts @@ -17,6 +17,10 @@ zephyr,sram = &ram0; }; + aliases { + watchdog0 = &wdt0; + }; + ram0: memory@40000000 { device_type = "memory"; reg = <0x40000000 0x10000000>; @@ -36,6 +40,10 @@ status = "okay"; }; +&wdt0 { + status = "okay"; +}; + &mdio0 { status = "okay"; }; diff --git a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml index 6d96923354e..b0dcc5b14a1 100644 --- a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml +++ b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml @@ -12,8 +12,12 @@ toolchain: - zephyr ram: 262144 supported: + - gpio + - uart - spi - i2s + - i2c + - watchdog testing: ignore_tags: - bluetooth diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 6ade11bd398..87dc99d76e7 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -18,6 +18,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_ESP32 wdt_esp32.c) zephyr_library_sources_ifdef(CONFIG_WDT_XT_ESP32 xt_wdt_esp32.c) zephyr_library_sources_ifdef(CONFIG_WDT_GECKO wdt_gecko.c) zephyr_library_sources_ifdef(CONFIG_WDT_ITE_IT8XXX2 wdt_ite_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_WDT_LITEX wdt_litex.c) zephyr_library_sources_ifdef(CONFIG_WDT_MAX32 wdt_max32.c) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_IMX_WDOG wdt_mcux_imx_wdog.c) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WDOG wdt_mcux_wdog.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d40f5f6bd51..95eaf31216d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -132,4 +132,6 @@ source "drivers/watchdog/Kconfig.numaker" source "drivers/watchdog/Kconfig.ene" +source "drivers/watchdog/Kconfig.litex" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.litex b/drivers/watchdog/Kconfig.litex new file mode 100644 index 00000000000..3853f81dab9 --- /dev/null +++ b/drivers/watchdog/Kconfig.litex @@ -0,0 +1,12 @@ +# LiteX WDT configuration + +# Copyright (C) 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +config WDT_LITEX + bool "LiteX Watchdog (WDT) Driver" + default y + depends on DT_HAS_LITEX_WATCHDOG_ENABLED + select HAS_WDT_DISABLE_AT_BOOT + help + Enable WDT driver for LiteX. diff --git a/drivers/watchdog/wdt_litex.c b/drivers/watchdog/wdt_litex.c new file mode 100644 index 00000000000..469c13aef8d --- /dev/null +++ b/drivers/watchdog/wdt_litex.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2024 Vogl Electronic GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT litex_watchdog + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(wdt_litex, CONFIG_WDT_LOG_LEVEL); + +#include + +struct wdt_litex_data { + wdt_callback_t callback; + uint32_t timeout; + bool reset_soc_mode; + bool pause_halted; +}; + +struct wdt_litex_config { + uint32_t control_addr; + uint32_t cycles_addr; + uint32_t cycles_size; + uint32_t remaining_addr; + uint32_t ev_status_addr; + uint32_t ev_pending_addr; + uint32_t ev_enable_addr; + void (*irq_cfg_func)(void); +}; + +#define CONTROL_FEED_BIT BIT(0) +#define CONTROL_ENABLE_BIT BIT(8) +#define CONTROL_RESET_BIT BIT(16) +#define CONTROL_PAUSE_HALTED_BIT BIT(24) + +static bool wdt_litex_is_enabled(const struct device *dev) +{ + const struct wdt_litex_config *config = dev->config; + + return litex_read8(config->control_addr) & BIT(0); +} + +static void wdt_litex_irq_enable(const struct device *dev) +{ + const struct wdt_litex_config *config = dev->config; + struct wdt_litex_data *data = dev->data; + + if (!data->callback) { + return; + } + + litex_write8(BIT(0), config->ev_pending_addr); + + litex_write8(BIT(0), config->ev_enable_addr); +} + +static void wdt_litex_enable(const struct device *dev) +{ + const struct wdt_litex_config *config = dev->config; + struct wdt_litex_data *data = dev->data; + uint32_t control; + + if (config->cycles_size <= 4) { + litex_write32(k_ms_to_cyc_floor32(data->timeout), config->cycles_addr); + } else { + litex_write64(k_ms_to_cyc_floor64(data->timeout), config->cycles_addr); + } + + control = CONTROL_FEED_BIT | CONTROL_ENABLE_BIT; + + if (data->reset_soc_mode) { + control |= CONTROL_RESET_BIT; + } + if (data->pause_halted) { + control |= CONTROL_PAUSE_HALTED_BIT; + } + + litex_write32(control, config->control_addr); + + wdt_litex_irq_enable(dev); +} + +static int wdt_litex_disable(const struct device *dev) +{ + const struct wdt_litex_config *config = dev->config; + + litex_write8(0, config->ev_enable_addr); + + if (!wdt_litex_is_enabled(dev)) { + return -EFAULT; + } + litex_write16(CONTROL_ENABLE_BIT, config->control_addr); + + return 0; +} + +static int wdt_litex_feed(const struct device *dev, int channel_id) +{ + const struct wdt_litex_config *config = dev->config; + + if (channel_id != 0) { + return -EINVAL; + } + + litex_write8(CONTROL_FEED_BIT, config->control_addr); + + return 0; +} + +static int wdt_litex_setup(const struct device *dev, uint8_t options) +{ + struct wdt_litex_data *data = dev->data; + + data->pause_halted = !!(options & WDT_OPT_PAUSE_HALTED_BY_DBG); + + if (options & WDT_OPT_PAUSE_IN_SLEEP) { + return -ENOTSUP; + } + + if (wdt_litex_is_enabled(dev)) { + return -EBUSY; + } + + wdt_litex_enable(dev); + wdt_litex_feed(dev, 0); + + return 0; +} + +static int wdt_litex_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg) +{ + const struct wdt_litex_config *config = dev->config; + struct wdt_litex_data *data = dev->data; + + if (cfg->window.min != 0U || cfg->window.max == 0U) { + return -EINVAL; + } + + if (cfg->window.max > (config->cycles_size <= 4 ? k_cyc_to_ms_floor32(UINT32_MAX) + : k_cyc_to_ms_floor64(UINT64_MAX))) { + return -EINVAL; + } + + if (wdt_litex_is_enabled(dev)) { + return -EBUSY; + } + + data->timeout = cfg->window.max; + data->callback = cfg->callback; + + /* Set mode of watchdog and callback */ + switch (cfg->flags) { + case WDT_FLAG_RESET_SOC: + LOG_DBG("Configuring reset SOC mode"); + data->reset_soc_mode = true; + break; + + case WDT_FLAG_RESET_NONE: + LOG_DBG("Configuring non-reset mode"); + data->reset_soc_mode = false; + break; + + default: + LOG_ERR("Unsupported watchdog config flag"); + return -EINVAL; + } + + return 0; +} + +static void wdt_litex_isr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + const struct wdt_litex_config *config = dev->config; + struct wdt_litex_data *data = dev->data; + unsigned int key = irq_lock(); + + if (data->callback) { + data->callback(dev, 0); + } + + litex_write8(BIT(0), config->ev_pending_addr); + + irq_unlock(key); +} + +static int wdt_litex_init(const struct device *dev) +{ + const struct wdt_litex_config *const config = dev->config; + + config->irq_cfg_func(); + +#ifndef CONFIG_WDT_DISABLE_AT_BOOT + wdt_litex_enable(dev); +#endif + + return 0; +} + +static const struct wdt_driver_api wdt_api = { + .setup = wdt_litex_setup, + .disable = wdt_litex_disable, + .install_timeout = wdt_litex_install_timeout, + .feed = wdt_litex_feed, +}; + +#define LITEX_WDT_INIT(n) \ + static void wdt_litex_cfg_func_##n(void); \ + \ + static struct wdt_litex_data wdt_litex_data##n; \ + static struct wdt_litex_config wdt_litex_config##n = { \ + .control_addr = DT_INST_REG_ADDR_BY_NAME(n, control), \ + .cycles_addr = DT_INST_REG_ADDR_BY_NAME(n, cycles), \ + .cycles_size = DT_INST_REG_SIZE_BY_NAME(n, cycles), \ + .remaining_addr = DT_INST_REG_ADDR_BY_NAME(n, remaining), \ + .ev_status_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_status), \ + .ev_pending_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_pending), \ + .ev_enable_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_enable), \ + .irq_cfg_func = wdt_litex_cfg_func_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, wdt_litex_init, NULL, &wdt_litex_data##n, &wdt_litex_config##n, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_api) \ + \ + static void wdt_litex_cfg_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), wdt_litex_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(LITEX_WDT_INIT) diff --git a/dts/bindings/watchdog/litex,watchdog.yaml b/dts/bindings/watchdog/litex,watchdog.yaml new file mode 100644 index 00000000000..8ad78cb4676 --- /dev/null +++ b/dts/bindings/watchdog/litex,watchdog.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: LiteX watchdog. + +compatible: "litex,watchdog" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index bf93141b1c9..8557d2ecb83 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -144,6 +144,23 @@ "uptime_cycles"; status = "disabled"; }; + wdt0: watchdog@e000d000 { + compatible = "litex,watchdog"; + interrupt-parent = <&intc0>; + reg = <0xe000d000 0x4>, + <0xe000d004 0x4>, + <0xe000d008 0x4>, + <0xe000d00c 0x4>, + <0xe000d010 0x4>, + <0xe000d014 0x4>; + reg-names = "control", + "cycles", + "remaining", + "ev_status", + "ev_pending", + "ev_enable"; + interrupts = <8 15>; + }; mdio0: mdio@e0008000 { compatible = "litex,liteeth-mdio"; reg = <0xe0008000 0x4>,