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;
 }

Reply via email to