This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 078e7099b75 arch/risc-v/k210: Add Watchdog Timer (WDT) driver support.
078e7099b75 is described below
commit 078e7099b7545517274a369f6681a32cb8dd159d
Author: Huang Qi <[email protected]>
AuthorDate: Sun Mar 15 21:42:24 2026 +0800
arch/risc-v/k210: Add Watchdog Timer (WDT) driver support.
Add WDT driver for K210 with support for both WDT0 and WDT1 peripherals.
This includes:
- Add k210_wdt.c and k210_wdt.h driver files with interrupt-based
watchdog timer functionality
- Add hardware register definitions in k210_wdt.h
- Add K210_WDT, K210_WDT0, K210_WDT1 Kconfig options
- Add memory map definitions for WDT0 (0x50400000) and WDT1 (0x50410000)
- Reorder WDT IRQ definitions (IRQ 21, 22) before UART0 (IRQ 33) in irq.h
- Add WDT initialization in board bringup for maix-bit
Signed-off-by: Huang Qi <[email protected]>
---
Documentation/platforms/risc-v/k210/index.rst | 14 +
arch/risc-v/include/k210/irq.h | 2 +
arch/risc-v/src/k210/CMakeLists.txt | 4 +
arch/risc-v/src/k210/Kconfig | 14 +
arch/risc-v/src/k210/Make.defs | 4 +
arch/risc-v/src/k210/hardware/k210_memorymap.h | 3 +
arch/risc-v/src/k210/hardware/k210_wdt.h | 54 +++
arch/risc-v/src/k210/k210_wdt.c | 516 +++++++++++++++++++++
.../{include/k210/irq.h => src/k210/k210_wdt.h} | 42 +-
boards/risc-v/k210/maix-bit/src/k210_bringup.c | 23 +
10 files changed, 662 insertions(+), 14 deletions(-)
diff --git a/Documentation/platforms/risc-v/k210/index.rst
b/Documentation/platforms/risc-v/k210/index.rst
index 7dfc61b80cc..584c704fff4 100644
--- a/Documentation/platforms/risc-v/k210/index.rst
+++ b/Documentation/platforms/risc-v/k210/index.rst
@@ -22,6 +22,20 @@ The driver supports querying clock frequencies for:
CPU frequency can be configured at build time using the ``K210_CPU_FREQ``
Kconfig option (default: 400 MHz, range: 40-600 MHz).
+Watchdog Timers
+===============
+
+The K210 has two independent watchdog timers (WDT0 and WDT1) for system
+reliability. Both are accessible as character drivers via the standard
+NuttX watchdog interface.
+
+* **WDT0**: Base address ``0x50400000``, IRQ 21
+* **WDT1**: Base address ``0x50410000``, IRQ 22
+* **Timeout range**: Programmable based on 16-bit counter
+
+Enable via Kconfig: ``CONFIG_K210_WDT`` (automatically selects
+``CONFIG_WATCHDOG``). Devices are ``/dev/watchdog0`` and ``/dev/watchdog1``.
+
Supported Boards
================
diff --git a/arch/risc-v/include/k210/irq.h b/arch/risc-v/include/k210/irq.h
index 9d4fc6de75d..728da5b5fa6 100644
--- a/arch/risc-v/include/k210/irq.h
+++ b/arch/risc-v/include/k210/irq.h
@@ -36,6 +36,8 @@
#ifdef CONFIG_K210_WITH_QEMU
#define K210_IRQ_UART0 (RISCV_IRQ_MEXT + 4)
#else
+#define K210_IRQ_WDT0 (RISCV_IRQ_MEXT + 21)
+#define K210_IRQ_WDT1 (RISCV_IRQ_MEXT + 22)
#define K210_IRQ_UART0 (RISCV_IRQ_MEXT + 33)
#endif
diff --git a/arch/risc-v/src/k210/CMakeLists.txt
b/arch/risc-v/src/k210/CMakeLists.txt
index 4df61aab560..dbb7909e00b 100644
--- a/arch/risc-v/src/k210/CMakeLists.txt
+++ b/arch/risc-v/src/k210/CMakeLists.txt
@@ -32,4 +32,8 @@ if(CONFIG_BUILD_PROTECTED)
list(APPEND SRCS k210_userspace.c)
endif()
+if(CONFIG_K210_WDT)
+ list(APPEND SRCS k210_wdt.c)
+endif()
+
target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/risc-v/src/k210/Kconfig b/arch/risc-v/src/k210/Kconfig
index 4416e294c20..385fc6843c4 100644
--- a/arch/risc-v/src/k210/Kconfig
+++ b/arch/risc-v/src/k210/Kconfig
@@ -25,6 +25,20 @@ config K210_UART0
select ARCH_HAVE_SERIAL_TERMIOS
select K210_UART
+config K210_WDT
+ bool
+ select WATCHDOG
+
+config K210_WDT0
+ bool "WDT0"
+ default n
+ select K210_WDT
+
+config K210_WDT1
+ bool "WDT1"
+ default n
+ select K210_WDT
+
endmenu
config K210_CPU_FREQ
diff --git a/arch/risc-v/src/k210/Make.defs b/arch/risc-v/src/k210/Make.defs
index 42d2d705140..38f8d842fd9 100644
--- a/arch/risc-v/src/k210/Make.defs
+++ b/arch/risc-v/src/k210/Make.defs
@@ -35,3 +35,7 @@ CHIP_CSRCS += k210_start.c k210_timerisr.c k210_gpiohs.c
k210_sysctl.c
ifeq ($(CONFIG_BUILD_PROTECTED),y)
CHIP_CSRCS += k210_userspace.c
endif
+
+ifeq ($(CONFIG_K210_WDT),y)
+CHIP_CSRCS += k210_wdt.c
+endif
diff --git a/arch/risc-v/src/k210/hardware/k210_memorymap.h
b/arch/risc-v/src/k210/hardware/k210_memorymap.h
index 612fe99d667..59f6ab15a17 100644
--- a/arch/risc-v/src/k210/hardware/k210_memorymap.h
+++ b/arch/risc-v/src/k210/hardware/k210_memorymap.h
@@ -40,6 +40,9 @@
#define K210_GPIOHS_BASE 0x38001000
#define K210_FPIOA_BASE 0x502B0000
+#define K210_WDT0_BASE 0x50400000
+#define K210_WDT1_BASE 0x50410000
+
#define K210_SYSCTL_BASE 0x50440000
#endif /* __ARCH_RISCV_SRC_K210_HARDWARE_K210_MEMORYMAP_H */
diff --git a/arch/risc-v/src/k210/hardware/k210_wdt.h
b/arch/risc-v/src/k210/hardware/k210_wdt.h
new file mode 100644
index 00000000000..636c7f4f72d
--- /dev/null
+++ b/arch/risc-v/src/k210/hardware/k210_wdt.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * arch/risc-v/src/k210/hardware/k210_wdt.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_K210_HARDWARE_K210_WDT_H
+#define __ARCH_RISCV_SRC_K210_HARDWARE_K210_WDT_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define K210_WDT_CR_OFFSET 0x0000
+#define K210_WDT_TORR_OFFSET 0x0004
+#define K210_WDT_CCVR_OFFSET 0x0008
+#define K210_WDT_CRR_OFFSET 0x000c
+#define K210_WDT_STAT_OFFSET 0x0010
+#define K210_WDT_EOI_OFFSET 0x0014
+#define K210_WDT_PROT_LEVEL_OFFSET 0x001c
+
+#define K210_WDT_CR(base) ((base) + K210_WDT_CR_OFFSET)
+#define K210_WDT_TORR(base) ((base) + K210_WDT_TORR_OFFSET)
+#define K210_WDT_CCVR(base) ((base) + K210_WDT_CCVR_OFFSET)
+#define K210_WDT_CRR(base) ((base) + K210_WDT_CRR_OFFSET)
+#define K210_WDT_STAT(base) ((base) + K210_WDT_STAT_OFFSET)
+#define K210_WDT_EOI(base) ((base) + K210_WDT_EOI_OFFSET)
+
+#define K210_WDT_CR_ENABLE 0x00000001u
+#define K210_WDT_CR_RMOD_MASK 0x00000002u
+#define K210_WDT_CR_RMOD_RESET 0x00000000u
+#define K210_WDT_CR_RMOD_INTERRUPT 0x00000002u
+
+#define K210_WDT_TORR_TOP(n) (((n) << 4) | ((n) << 0))
+
+#define K210_WDT_CRR_RESTART 0x00000076u
+
+#endif /* __ARCH_RISCV_SRC_K210_HARDWARE_K210_WDT_H */
diff --git a/arch/risc-v/src/k210/k210_wdt.c b/arch/risc-v/src/k210/k210_wdt.c
new file mode 100644
index 00000000000..f4abcc8617a
--- /dev/null
+++ b/arch/risc-v/src/k210/k210_wdt.c
@@ -0,0 +1,516 @@
+/****************************************************************************
+ * arch/risc-v/src/k210/k210_wdt.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#if defined(CONFIG_K210_WDT0) || defined(CONFIG_K210_WDT1)
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/timers/watchdog.h>
+
+#include "riscv_internal.h"
+#include "k210.h"
+#include "k210_sysctl.h"
+#include "k210_wdt.h"
+#include "hardware/k210_sysctl.h"
+#include "hardware/k210_wdt.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define K210_WDT_IN0_FREQ 26000000u
+#define K210_WDT_DEFAULT_PCLK (K210_WDT_IN0_FREQ / 2u)
+#define K210_WDT_MAX_TOP 0x0f
+#define K210_WDT_BASE_COUNT (1ull << 16)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct k210_wdt_lowerhalf_s
+{
+ const struct watchdog_ops_s *ops;
+ uintptr_t base;
+ int irq;
+ k210_clockid_t clkid;
+ k210_rstidx_t rstidx;
+ xcpt_t handler;
+ void *upper;
+ uint32_t timeout;
+ uint8_t top;
+ bool started;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int k210_wdt_start(struct watchdog_lowerhalf_s *lower);
+static int k210_wdt_stop(struct watchdog_lowerhalf_s *lower);
+static int k210_wdt_keepalive(struct watchdog_lowerhalf_s *lower);
+static int k210_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
+ struct watchdog_status_s *status);
+static int k210_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
+ uint32_t timeout);
+static xcpt_t k210_wdt_capture(struct watchdog_lowerhalf_s *lower,
+ xcpt_t handler);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct watchdog_ops_s g_k210_wdt_ops =
+{
+ .start = k210_wdt_start,
+ .stop = k210_wdt_stop,
+ .keepalive = k210_wdt_keepalive,
+ .getstatus = k210_wdt_getstatus,
+ .settimeout = k210_wdt_settimeout,
+ .capture = k210_wdt_capture,
+ .ioctl = NULL,
+};
+
+#ifdef CONFIG_K210_WDT0
+static struct k210_wdt_lowerhalf_s g_k210_wdt0_lowerhalf =
+{
+ .ops = &g_k210_wdt_ops,
+ .base = K210_WDT0_BASE,
+ .irq = K210_IRQ_WDT0,
+ .clkid = K210_CLOCK_WDT0,
+ .rstidx = K210_RESET_WDT0,
+ .timeout = 0,
+ .top = K210_WDT_MAX_TOP,
+};
+#endif
+
+#ifdef CONFIG_K210_WDT1
+static struct k210_wdt_lowerhalf_s g_k210_wdt1_lowerhalf =
+{
+ .ops = &g_k210_wdt_ops,
+ .base = K210_WDT1_BASE,
+ .irq = K210_IRQ_WDT1,
+ .clkid = K210_CLOCK_WDT1,
+ .rstidx = K210_RESET_WDT1,
+ .timeout = 0,
+ .top = K210_WDT_MAX_TOP,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t k210_wdt_get_pclk(struct k210_wdt_lowerhalf_s *priv)
+{
+ uint32_t pclk;
+
+ if (!priv->started)
+ {
+ return K210_WDT_DEFAULT_PCLK;
+ }
+
+ pclk = k210_sysctl_clock_get_freq(priv->clkid);
+
+ if (pclk == 0)
+ {
+ pclk = K210_WDT_DEFAULT_PCLK;
+ }
+
+ return pclk;
+}
+
+static void k210_wdt_set_threshold_zero(struct k210_wdt_lowerhalf_s *priv)
+{
+ uint32_t clearbits = (priv->clkid == K210_CLOCK_WDT0) ?
+ CLK_TH6_WDT0_MASK : CLK_TH6_WDT1_MASK;
+
+ modifyreg32(K210_SYSCTL_CLK_TH6, clearbits, 0);
+}
+
+static void k210_wdt_enable(struct k210_wdt_lowerhalf_s *priv)
+{
+ uint32_t regval;
+
+ putreg32(K210_WDT_CRR_RESTART, K210_WDT_CRR(priv->base));
+ regval = getreg32(K210_WDT_CR(priv->base));
+ regval |= K210_WDT_CR_ENABLE;
+ putreg32(regval, K210_WDT_CR(priv->base));
+}
+
+static void k210_wdt_disable(struct k210_wdt_lowerhalf_s *priv)
+{
+ uint32_t regval;
+
+ putreg32(K210_WDT_CRR_RESTART, K210_WDT_CRR(priv->base));
+ regval = getreg32(K210_WDT_CR(priv->base));
+ regval &= ~K210_WDT_CR_ENABLE;
+ putreg32(regval, K210_WDT_CR(priv->base));
+}
+
+static void k210_wdt_feed_internal(struct k210_wdt_lowerhalf_s *priv)
+{
+ putreg32(K210_WDT_CRR_RESTART, K210_WDT_CRR(priv->base));
+}
+
+static void k210_wdt_clear_interrupt(struct k210_wdt_lowerhalf_s *priv)
+{
+ uint32_t regval;
+
+ regval = getreg32(K210_WDT_EOI(priv->base));
+ putreg32(regval, K210_WDT_EOI(priv->base));
+}
+
+static void k210_wdt_set_timeout_top(struct k210_wdt_lowerhalf_s *priv,
+ uint8_t top)
+{
+ putreg32(K210_WDT_TORR_TOP(top), K210_WDT_TORR(priv->base));
+}
+
+static void k210_wdt_set_response_mode(struct k210_wdt_lowerhalf_s *priv,
+ uint32_t mode)
+{
+ uint32_t regval;
+
+ regval = getreg32(K210_WDT_CR(priv->base));
+ regval &= ~K210_WDT_CR_RMOD_MASK;
+ regval |= mode;
+ putreg32(regval, K210_WDT_CR(priv->base));
+}
+
+static uint8_t k210_wdt_get_top(struct k210_wdt_lowerhalf_s *priv,
+ uint32_t timeout_ms)
+{
+ uint64_t counts;
+ uint64_t level;
+ uint8_t top = 0;
+
+ counts = ((uint64_t)timeout_ms * (uint64_t)k210_wdt_get_pclk(priv) +
+ 999u) / 1000u;
+
+ level = (counts + K210_WDT_BASE_COUNT - 1) / K210_WDT_BASE_COUNT;
+
+ if (level == 0)
+ {
+ level = 1;
+ }
+
+ while ((1ull << top) < level && top < K210_WDT_MAX_TOP)
+ {
+ top++;
+ }
+
+ return top;
+}
+
+static uint32_t k210_wdt_top_to_timeout(struct k210_wdt_lowerhalf_s *priv,
+ uint8_t top)
+{
+ uint64_t timeout;
+ uint32_t pclk = k210_wdt_get_pclk(priv);
+
+ timeout = (K210_WDT_BASE_COUNT << top) * 1000ull;
+ timeout /= (uint64_t)pclk;
+
+ return (uint32_t)timeout;
+}
+
+static int k210_wdt_interrupt(int irq, void *context, void *arg)
+{
+ struct k210_wdt_lowerhalf_s *priv = arg;
+
+ if (priv->handler != NULL)
+ {
+ priv->handler(irq, context, priv->upper);
+ }
+
+ k210_wdt_clear_interrupt(priv);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_start
+ ****************************************************************************/
+
+static int k210_wdt_start(struct watchdog_lowerhalf_s *lower)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+ irqstate_t flags;
+ int ret;
+
+ if (priv->started)
+ {
+ return -EBUSY;
+ }
+
+ flags = enter_critical_section();
+
+ ret = k210_sysctl_reset(priv->rstidx);
+ if (ret < 0)
+ {
+ leave_critical_section(flags);
+ return ret;
+ }
+
+ k210_wdt_set_threshold_zero(priv);
+
+ ret = k210_sysctl_clock_enable(priv->clkid);
+ if (ret < 0)
+ {
+ leave_critical_section(flags);
+ return ret;
+ }
+
+ putreg32(1, K210_PLIC_PRIORITY +
+ ((priv->irq - RISCV_IRQ_MEXT) * sizeof(uint32_t)));
+
+ if (priv->handler != NULL)
+ {
+ k210_wdt_set_response_mode(priv, K210_WDT_CR_RMOD_INTERRUPT);
+ up_enable_irq(priv->irq);
+ }
+ else
+ {
+ k210_wdt_set_response_mode(priv, K210_WDT_CR_RMOD_RESET);
+ up_disable_irq(priv->irq);
+ }
+
+ k210_wdt_set_timeout_top(priv, priv->top);
+ k210_wdt_enable(priv);
+ priv->started = true;
+
+ leave_critical_section(flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_stop
+ ****************************************************************************/
+
+static int k210_wdt_stop(struct watchdog_lowerhalf_s *lower)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+ irqstate_t flags;
+
+ flags = enter_critical_section();
+ up_disable_irq(priv->irq);
+ k210_wdt_disable(priv);
+ priv->started = false;
+ leave_critical_section(flags);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_keepalive
+ ****************************************************************************/
+
+static int k210_wdt_keepalive(struct watchdog_lowerhalf_s *lower)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+
+ if (!priv->started)
+ {
+ return -EIO;
+ }
+
+ k210_wdt_feed_internal(priv);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_getstatus
+ ****************************************************************************/
+
+static int k210_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
+ struct watchdog_status_s *status)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+ uint64_t timeleft = priv->timeout;
+
+ status->flags = 0;
+
+ if (priv->started)
+ {
+ status->flags |= WDFLAGS_ACTIVE;
+ timeleft = ((uint64_t)getreg32(K210_WDT_CCVR(priv->base)) * 1000ull) /
+ (uint64_t)k210_wdt_get_pclk(priv);
+ if (timeleft > priv->timeout)
+ {
+ timeleft = priv->timeout;
+ }
+ }
+
+ if (priv->handler != NULL)
+ {
+ status->flags |= WDFLAGS_CAPTURE;
+ }
+ else
+ {
+ status->flags |= WDFLAGS_RESET;
+ }
+
+ status->timeout = priv->timeout;
+ status->timeleft = (uint32_t)timeleft;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_settimeout
+ ****************************************************************************/
+
+static int k210_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
+ uint32_t timeout)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+ irqstate_t flags;
+
+ if (timeout == 0)
+ {
+ return -EINVAL;
+ }
+
+ if (timeout > k210_wdt_top_to_timeout(priv, K210_WDT_MAX_TOP))
+ {
+ return -ERANGE;
+ }
+
+ priv->top = k210_wdt_get_top(priv, timeout);
+ priv->timeout = k210_wdt_top_to_timeout(priv, priv->top);
+
+ if (!priv->started)
+ {
+ return OK;
+ }
+
+ flags = enter_critical_section();
+ k210_wdt_set_timeout_top(priv, priv->top);
+ k210_wdt_feed_internal(priv);
+ leave_critical_section(flags);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: k210_wdt_capture
+ ****************************************************************************/
+
+static xcpt_t k210_wdt_capture(struct watchdog_lowerhalf_s *lower,
+ xcpt_t handler)
+{
+ struct k210_wdt_lowerhalf_s *priv =
+ (struct k210_wdt_lowerhalf_s *)lower;
+ irqstate_t flags;
+ xcpt_t oldhandler;
+
+ flags = enter_critical_section();
+ oldhandler = priv->handler;
+ priv->handler = handler;
+
+ if (priv->started)
+ {
+ if (handler != NULL)
+ {
+ putreg32(1, K210_PLIC_PRIORITY +
+ ((priv->irq - RISCV_IRQ_MEXT) * sizeof(uint32_t)));
+ k210_wdt_set_response_mode(priv, K210_WDT_CR_RMOD_INTERRUPT);
+ up_enable_irq(priv->irq);
+ }
+ else
+ {
+ up_disable_irq(priv->irq);
+ k210_wdt_set_response_mode(priv, K210_WDT_CR_RMOD_RESET);
+ }
+ }
+
+ leave_critical_section(flags);
+ return oldhandler;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: k210_wdt_initialize
+ ****************************************************************************/
+
+int k210_wdt_initialize(const char *devpath, k210_wdt_id_t id)
+{
+ struct k210_wdt_lowerhalf_s *priv;
+ void *handle;
+ int ret;
+
+ switch (id)
+ {
+#ifdef CONFIG_K210_WDT0
+ case K210_WDT_DEVICE0:
+ priv = &g_k210_wdt0_lowerhalf;
+ break;
+#endif
+#ifdef CONFIG_K210_WDT1
+ case K210_WDT_DEVICE1:
+ priv = &g_k210_wdt1_lowerhalf;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ if (priv->timeout == 0)
+ {
+ priv->timeout = k210_wdt_top_to_timeout(priv, priv->top);
+ }
+
+ ret = irq_attach(priv->irq, k210_wdt_interrupt, priv);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ up_disable_irq(priv->irq);
+
+ handle = watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv);
+ if (handle == NULL)
+ {
+ return -EEXIST;
+ }
+
+ priv->upper = handle;
+ return OK;
+}
+
+#endif /* CONFIG_K210_WDT0 || CONFIG_K210_WDT1 */
diff --git a/arch/risc-v/include/k210/irq.h b/arch/risc-v/src/k210/k210_wdt.h
similarity index 70%
copy from arch/risc-v/include/k210/irq.h
copy to arch/risc-v/src/k210/k210_wdt.h
index 9d4fc6de75d..19c28c22a80 100644
--- a/arch/risc-v/include/k210/irq.h
+++ b/arch/risc-v/src/k210/k210_wdt.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/risc-v/include/k210/irq.h
+ * arch/risc-v/src/k210/k210_wdt.h
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -20,27 +20,41 @@
*
****************************************************************************/
-#ifndef __ARCH_RISCV_INCLUDE_K210_IRQ_H
-#define __ARCH_RISCV_INCLUDE_K210_IRQ_H
+#ifndef __ARCH_RISCV_SRC_K210_K210_WDT_H
+#define __ARCH_RISCV_SRC_K210_K210_WDT_H
/****************************************************************************
- * Included Files
+ * Public Types
****************************************************************************/
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+typedef enum
+{
+ K210_WDT_DEVICE0 = 0,
+ K210_WDT_DEVICE1,
+ K210_WDT_DEVICE_MAX
+} k210_wdt_id_t;
-/* Map RISC-V exception code to NuttX IRQ */
+#ifndef __ASSEMBLY__
-#ifdef CONFIG_K210_WITH_QEMU
-#define K210_IRQ_UART0 (RISCV_IRQ_MEXT + 4)
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
#else
-#define K210_IRQ_UART0 (RISCV_IRQ_MEXT + 33)
+#define EXTERN extern
#endif
-/* Total number of IRQs */
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
-#define NR_IRQS (K210_IRQ_UART0 + 1)
+int k210_wdt_initialize(const char *devpath, k210_wdt_id_t id);
+
+#undef EXTERN
+
+#if defined(__cplusplus)
+}
+#endif
-#endif /* __ARCH_RISCV_INCLUDE_K210_IRQ_H */
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_K210_K210_WDT_H */
diff --git a/boards/risc-v/k210/maix-bit/src/k210_bringup.c
b/boards/risc-v/k210/maix-bit/src/k210_bringup.c
index e84e7332f16..7f0441ff2f8 100644
--- a/boards/risc-v/k210/maix-bit/src/k210_bringup.c
+++ b/boards/risc-v/k210/maix-bit/src/k210_bringup.c
@@ -35,6 +35,7 @@
#include <nuttx/fs/fs.h>
#include "k210.h"
+#include "k210_wdt.h"
#include "maix-bit.h"
/****************************************************************************
@@ -68,5 +69,27 @@ int k210_bringup(void)
}
#endif
+#ifdef CONFIG_K210_WDT0
+ ret = k210_wdt_initialize(CONFIG_WATCHDOG_DEVPATH, K210_WDT_DEVICE0);
+ if (ret < 0)
+ {
+ syslog(LOG_WARNING, "WARNING: Failed to initialize WDT0: %d\n", ret);
+ }
+#endif
+
+#ifdef CONFIG_K210_WDT1
+ ret = k210_wdt_initialize(
+#ifdef CONFIG_K210_WDT0
+ "/dev/watchdog1",
+#else
+ CONFIG_WATCHDOG_DEVPATH,
+#endif
+ K210_WDT_DEVICE1);
+ if (ret < 0)
+ {
+ syslog(LOG_WARNING, "WARNING: Failed to initialize WDT1: %d\n", ret);
+ }
+#endif
+
return ret;
}