You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/11/06 21:33:41 UTC

[incubator-nuttx] branch master updated: arch/arm/src/imxrt: adds support for WDOG1

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new c7a9b66  arch/arm/src/imxrt: adds support for WDOG1
c7a9b66 is described below

commit c7a9b66833258759b47afc117634880ffa67f9d9
Author: Nicholas Chin <ni...@gmail.com>
AuthorDate: Tue Nov 3 13:00:37 2020 -0500

    arch/arm/src/imxrt: adds support for WDOG1
    
    Based on work done by Jake Choy.
---
 arch/arm/src/imxrt/Kconfig      |   5 +
 arch/arm/src/imxrt/imxrt_wdog.c | 337 ++++++++++++++++++++++++++++++++++++++--
 arch/arm/src/imxrt/imxrt_wdog.h |  23 +++
 3 files changed, 355 insertions(+), 10 deletions(-)

diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig
index 8cb93b4..c2657bb 100644
--- a/arch/arm/src/imxrt/Kconfig
+++ b/arch/arm/src/imxrt/Kconfig
@@ -217,6 +217,11 @@ config IMXRT_LCD
 	default n
 	depends on IMXRT_HAVE_LCD
 
+config IMXRT_WDOG
+	bool "Watchdog 1"
+	default n
+	depends on WATCHDOG
+
 menu "FlexIO Peripherals"
 
 config IMXRT_FLEXIO1
diff --git a/arch/arm/src/imxrt/imxrt_wdog.c b/arch/arm/src/imxrt/imxrt_wdog.c
index a3dbb1b..9302afc 100644
--- a/arch/arm/src/imxrt/imxrt_wdog.c
+++ b/arch/arm/src/imxrt/imxrt_wdog.c
@@ -40,29 +40,347 @@
 #include <nuttx/config.h>
 
 #include <stdint.h>
-#include <fixedmath.h>
+#include <stdbool.h>
+
+#include <debug.h>
 #include <assert.h>
+#include <errno.h>
 
-#include "arm_arch.h"
+#include <nuttx/timers/watchdog.h>
 
+#include "arm_arch.h"
 #include "hardware/imxrt_wdog.h"
-#include "imxrt_config.h"
+#include "imxrt_wdog.h"
+
 #include <arch/board/board.h> /* Include last:  has dependencies */
 
+#if defined(CONFIG_WATCHDOG) && defined(CONFIG_IMXRT_WDOG)
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
-/* Configuration ************************************************************/
+
+/* Select the path to the registered watchdog timer device */
+
+#ifdef CONFIG_WATCHDOG_DEVPATH
+#define DEVPATH CONFIG_WATCHDOG_DEVPATH
+#else
+#define DEVPATH "/dev/watchdog0"
+#endif
+
+/* Time out range is from 0 to 128 seconds in 0.5s intervals */
+
+#define WDOG_MIN              (500)
+#define WDOG_MAX              (128000)
+
+#define WDOG_KEEP_ALIVE_KEY1  (0x5555u)
+#define WDOG_KEEP_ALIVE_KEY2  (0xaaaau)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct imxrt_wdog_lower
+{
+  FAR const struct watchdog_ops_s  *ops;  /* Lower half operations */
+  uint32_t     timeout;
+  uint32_t     enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Timeout to register field helper */
+
+uint32_t imxrt_wdog_ms_to_reg(uint32_t timeout);
+
+/* Lower half driver methods */
+
+static int      imxrt_wdog_start(FAR struct watchdog_lowerhalf_s *lower);
+static int      imxrt_wdog_stop(FAR struct watchdog_lowerhalf_s *lower);
+static int      imxrt_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower);
+static int      imxrt_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower,
+                  FAR struct watchdog_status_s *status);
+static int      imxrt_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower,
+                  uint32_t timeout);
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
+/* "Lower half" driver ops */
+
+static const struct watchdog_ops_s g_wdgops =
+{
+  .start      = imxrt_wdog_start,
+  .stop       = imxrt_wdog_stop,
+  .keepalive  = imxrt_wdog_keepalive,
+  .getstatus  = imxrt_wdog_getstatus,
+  .settimeout = imxrt_wdog_settimeout,
+  .capture    = NULL,
+  .ioctl      = NULL,
+};
+
+/* "Lower half" driver state */
+
+static struct imxrt_wdog_lower g_wdgdev;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imxrt_wdog_ms_to_reg
+ *
+ * Description:
+ *   Start the watchdog timer, resetting the time to the current timeout,
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           lower-half driver state structure.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+uint32_t imxrt_wdog_ms_to_reg(uint32_t ms)
+{
+  uint32_t reg = ms / 500; /* This gives the value needed for
+                            * ms rounded up to the nearest 500ms of timeout
+                            */
+
+  if (reg != 0 && ms % 500 == 0)
+    {
+      /* If the number is divisible by 500ms we subtract 1.
+       * Else we will set the timeout to the smallest achievable timeout
+       * that is greater than the requested value.
+       */
+
+      reg--;
+    }
+
+  return reg;
+}
+
+/****************************************************************************
+ * Name: imxrt_wdog
+ *
+ * Description:
+ *   Start the watchdog timer, setting the time to the current timeout,
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           lower-half driver state structure.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int imxrt_wdog_start(FAR struct watchdog_lowerhalf_s *lower)
+{
+  FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower;
+  uint16_t regval;
+
+  if (priv->enabled == false)
+    {
+      priv->enabled = true;
+
+      regval  = getreg16(IMXRT_WDOG1_WCR);
+      regval |= WDOG_WCR_WT(imxrt_wdog_ms_to_reg(priv->timeout));
+      putreg16(regval, IMXRT_WDOG1_WCR);
+
+      /* Now that the timeout field is properly set, start the watchdog. */
+
+      regval |= WDOG_WCR_WDE;
+      putreg16(regval, IMXRT_WDOG1_WCR);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: imxrt_wdog_stop
+ *
+ * Description:
+ *   Exists since it is a required function for the watchdog lower-half
+ *   driver. On the IMXRT you cannot disable the watchdog once it is started.
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           lower-half driver state structure.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int imxrt_wdog_stop(FAR struct watchdog_lowerhalf_s *lower)
+{
+  FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower;
+
+  if (priv->enabled)
+    {
+      /* We cannot disable the watchdog once it is enabled. */
+
+      wderr("ERROR: Cannot stop Wdog once started\n");
+      return -ENOSYS;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: imxrt_wdog_keepalive
+ *
+ * Description:
+ *   Reset the watchdog timer to the current timeout value, prevent any
+ *   imminent watchdog timeouts.  This is sometimes referred as "pinging"
+ *   the watchdog timer or "petting the dog".
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           lower-half driver state structure.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int imxrt_wdog_keepalive(FAR struct watchdog_lowerhalf_s *lower)
+{
+  irqstate_t flags = spin_lock_irqsave();
+
+  putreg16(WDOG_KEEP_ALIVE_KEY1, IMXRT_WDOG1_WSR);
+  putreg16(WDOG_KEEP_ALIVE_KEY2, IMXRT_WDOG1_WSR);
+
+  spin_unlock_irqrestore(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: imxrt_wdog_getstatus
+ *
+ * Description:
+ *   Get the current watchdog timer status
+ *
+ * Input Parameters:
+ *   lower  - A pointer the publicly visible representation of the
+ *            lower-half driver state structure.
+ *   status - The location to return the watchdog status information.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int imxrt_wdog_getstatus(FAR struct watchdog_lowerhalf_s *lower,
+                           FAR struct watchdog_status_s *status)
+{
+  FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower;
+
+  status->flags = WDFLAGS_RESET;
+
+  if (priv->enabled)
+    {
+      status->flags |= WDFLAGS_ACTIVE;
+    }
+
+  status->timeout = priv->timeout;
+  status->timeleft = 0; /* not supported for WDOG1 */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: imxrt_wdog_settimeout
+ *
+ * Description:
+ *   Set a new timeout value (and reset the watchdog timer)
+ *
+ * Input Parameters:
+ *   lower   - A pointer the publicly visible representation of the
+ *             "lower-half" driver state structure.
+ *   timeout - The new timeout value in milliseconds.
+ *
+ * Returned Values:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int imxrt_wdog_settimeout(FAR struct watchdog_lowerhalf_s *lower,
+                            uint32_t timeout)
+{
+  uint32_t regval;
+  FAR struct imxrt_wdog_lower *priv = (FAR struct imxrt_wdog_lower *)lower;
+
+  if (timeout < WDOG_MIN || timeout > WDOG_MAX)
+    {
+      wderr("ERROR: Cannot represent timeout=%d. Range=[%d, %d]\n",
+            timeout, WDOG_MIN, WDOG_MAX);
+      return -ERANGE;
+    }
+
+  priv->timeout = timeout;
+
+  irqstate_t flags = spin_lock_irqsave();
+
+  /* write timer value to WCR WT register */
+
+  regval  = getreg16(IMXRT_WDOG1_WCR);
+  regval &= ~WDOG_WCR_WT_MASK;  /* clear previous count value */
+  regval |= WDOG_WCR_WT(priv->timeout);
+  putreg16(regval, IMXRT_WDOG1_WCR);
+
+  /* reload the Wdog counter by petting it */
+
+  putreg16(WDOG_KEEP_ALIVE_KEY1, IMXRT_WDOG1_WSR);
+  putreg16(WDOG_KEEP_ALIVE_KEY2, IMXRT_WDOG1_WSR);
+
+  spin_unlock_irqrestore(flags);
+
+  return OK;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: imxrt_wdog_initialize
+ *
+ * Description:
+ *   Initialize the watchdog time.  The watchdog timer is initialized and
+ *   registered at devpath.  The initial state of the watchdog time is
+ *   disabled.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+void imxrt_wdog_initialize(void)
+{
+  FAR struct imxrt_wdog_lower *priv = &g_wdgdev;
+
+  priv->ops = &g_wdgops;
+  priv->timeout = WDOG_MIN;
+
+  /* Register the watchdog driver at the path */
+
+  wdinfo("Entry: devpath=%s\n", DEVPATH);
+  watchdog_register(DEVPATH, (FAR struct watchdog_lowerhalf_s *)priv);
+}
+
+#endif /* CONFIG_WATCHDOG && CONFIG_IMXRT_WDOG */
+
+/****************************************************************************
  * Name: imxrt_wdog_disable
  *
  * Description:
@@ -84,15 +402,14 @@ void imxrt_wdog_disable_all(void)
 
   reg = getreg16(IMXRT_WDOG2_WCR);
   if (reg & WDOG_WCR_WDE)
-  {
-    reg &= ~WDOG_WCR_WDE;
-    putreg16(reg, IMXRT_WDOG2_WCR);
-  }
+    {
+      reg &= ~WDOG_WCR_WDE;
+      putreg16(reg, IMXRT_WDOG2_WCR);
+    }
 
   flags = enter_critical_section();
   putreg32(RTWDOG_UPDATE_KEY, IMXRT_RTWDOG_CNT);
-  putreg32(0xFFFF, IMXRT_RTWDOG_TOVAL);
+  putreg32(0xffff, IMXRT_RTWDOG_TOVAL);
   modifyreg32(IMXRT_RTWDOG_CS, RTWDOG_CS_EN, RTWDOG_CS_UPDATE);
   leave_critical_section(flags);
-
 }
diff --git a/arch/arm/src/imxrt/imxrt_wdog.h b/arch/arm/src/imxrt/imxrt_wdog.h
index 6db8dad..8bf2a0c 100644
--- a/arch/arm/src/imxrt/imxrt_wdog.h
+++ b/arch/arm/src/imxrt/imxrt_wdog.h
@@ -59,6 +59,29 @@
  * Public Function Prototypes
  ****************************************************************************/
 
+#if defined(CONFIG_WATCHDOG) && defined(CONFIG_IMXRT_WDOG)
+
+/****************************************************************************
+ * Name: imxrt_wdog_initialize
+ *
+ * Description:
+ *   Initialize the watchdog time.  The watchdog timer is initialized and
+ *   registered at devpath.  The initial state of the watchdog time is
+ *   disabled.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the watchdog.  This should be of the form
+ *     /dev/watchdog0
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+void imxrt_wdog_initialize(void);
+
+#endif /* CONFIG_WATCHDOG && CONFIG_IMXRT_WDOG */
+
 /****************************************************************************
  * Name: imxrt_wdog_disable
  *