/**************************************************************************** * arch/arm/src/imxrt/imxrt_wdog.c * * 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 #include #include #include #include #include #include #include #include "arm_arch.h" #include "hardware/imxrt_wdog.h" #include "imxrt_wdog.h" #include /* Include last: has dependencies */ #if defined(CONFIG_WATCHDOG) && defined(CONFIG_IMXRT_WDOG) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* 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(NULL); putreg16(WDOG_KEEP_ALIVE_KEY1, IMXRT_WDOG1_WSR); putreg16(WDOG_KEEP_ALIVE_KEY2, IMXRT_WDOG1_WSR); spin_unlock_irqrestore(NULL, 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(NULL); /* 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(NULL, 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: * Disables all watchdogs * ****************************************************************************/ void imxrt_wdog_disable_all(void) { uint32_t reg; irqstate_t flags; reg = getreg16(IMXRT_WDOG1_WCR); if (reg & WDOG_WCR_WDE) { reg &= ~WDOG_WCR_WDE; putreg16(reg, IMXRT_WDOG1_WCR); } reg = getreg16(IMXRT_WDOG2_WCR); if (reg & WDOG_WCR_WDE) { 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); modifyreg32(IMXRT_RTWDOG_CS, RTWDOG_CS_EN, RTWDOG_CS_UPDATE); leave_critical_section(flags); }