1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_wwdt.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.wwdt"
14 #endif
15
16 #define FREQUENCY_3MHZ (3000000U)
17 /*******************************************************************************
18 * Prototypes
19 ******************************************************************************/
20
21 /*!
22 * @brief Gets the instance from the base address
23 *
24 * @param base WWDT peripheral base address
25 *
26 * @return The WWDT instance
27 */
28 static uint32_t WWDT_GetInstance(WWDT_Type *base);
29
30 /*******************************************************************************
31 * Variables
32 ******************************************************************************/
33 /*! @brief Pointers to WWDT bases for each instance. */
34 static WWDT_Type *const s_wwdtBases[] = WWDT_BASE_PTRS;
35
36 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
37 /*! @brief Pointers to WWDT clocks for each instance. */
38 static const clock_ip_name_t s_wwdtClocks[] = WWDT_CLOCKS;
39 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
40
41 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
42 #if !(defined(FSL_FEATURE_WWDT_HAS_NO_RESET) && FSL_FEATURE_WWDT_HAS_NO_RESET)
43 /*! @brief Pointers to WWDT resets for each instance. */
44 static const reset_ip_name_t s_wwdtResets[] = WWDT_RSTS;
45 #endif
46 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
47
48 /*******************************************************************************
49 * Code
50 ******************************************************************************/
WWDT_GetInstance(WWDT_Type * base)51 static uint32_t WWDT_GetInstance(WWDT_Type *base)
52 {
53 uint32_t instance;
54 uint32_t wwdtArrayCount = (sizeof(s_wwdtBases) / sizeof(s_wwdtBases[0]));
55
56 /* Find the instance index from base address mappings. */
57 for (instance = 0; instance < wwdtArrayCount; instance++)
58 {
59 if (MSDK_REG_SECURE_ADDR(s_wwdtBases[instance]) == MSDK_REG_SECURE_ADDR(base))
60 {
61 break;
62 }
63 }
64
65 assert(instance < wwdtArrayCount);
66
67 return instance;
68 }
69
70 /*******************************************************************************
71 * Code
72 ******************************************************************************/
73
74 /*!
75 * brief Initializes WWDT configure structure.
76 *
77 * This function initializes the WWDT configure structure to default value. The default
78 * value are:
79 * code
80 * config->enableWwdt = true;
81 * config->enableWatchdogReset = false;
82 * config->enableWatchdogProtect = false;
83 * config->enableLockOscillator = false;
84 * config->windowValue = 0xFFFFFFU;
85 * config->timeoutValue = 0xFFFFFFU;
86 * config->warningValue = 0;
87 * endcode
88 *
89 * param config Pointer to WWDT config structure.
90 * see wwdt_config_t
91 */
WWDT_GetDefaultConfig(wwdt_config_t * config)92 void WWDT_GetDefaultConfig(wwdt_config_t *config)
93 {
94 assert(NULL != config);
95
96 /* Initializes the configure structure to zero. */
97 (void)memset(config, 0, sizeof(*config));
98
99 /* Enable the watch dog */
100 config->enableWwdt = true;
101 /* Disable the watchdog timeout reset */
102 config->enableWatchdogReset = false;
103 /* Disable the watchdog protection for updating the timeout value */
104 config->enableWatchdogProtect = false;
105 #if !(defined(FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK) && FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK)
106 /* Do not lock the watchdog oscillator */
107 config->enableLockOscillator = false;
108 #endif
109 /* Windowing is not in effect */
110 config->windowValue = 0xFFFFFFU;
111 /* Set the timeout value to the max */
112 config->timeoutValue = 0xFFFFFFU;
113 /* No warning is provided */
114 config->warningValue = 0;
115 /* Set clock frequency. */
116 config->clockFreq_Hz = 0U;
117 }
118
119 /*!
120 * brief Initializes the WWDT.
121 *
122 * This function initializes the WWDT. When called, the WWDT runs according to the configuration.
123 *
124 * Example:
125 * code
126 * wwdt_config_t config;
127 * WWDT_GetDefaultConfig(&config);
128 * config.timeoutValue = 0x7ffU;
129 * WWDT_Init(wwdt_base,&config);
130 * endcode
131 *
132 * param base WWDT peripheral base address
133 * param config The configuration of WWDT
134 */
WWDT_Init(WWDT_Type * base,const wwdt_config_t * config)135 void WWDT_Init(WWDT_Type *base, const wwdt_config_t *config)
136 {
137 assert(NULL != config);
138
139 uint32_t value = 0U;
140 uint32_t DelayUs = 0U;
141 uint32_t primaskValue = 0U;
142
143 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
144 /* Enable the WWDT clock */
145 CLOCK_EnableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
146 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
147
148 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
149 #if !(defined(FSL_FEATURE_WWDT_HAS_NO_RESET) && FSL_FEATURE_WWDT_HAS_NO_RESET)
150 /* Reset the module. */
151 RESET_PeripheralReset(s_wwdtResets[WWDT_GetInstance(base)]);
152 #endif
153
154 #if defined(FSL_FEATURE_WWDT_WDTRESET_FROM_PMC) && (FSL_FEATURE_WWDT_WDTRESET_FROM_PMC)
155 /* PMC RESETCAUSE: set bit to clear it by write 1. */
156 PMC->RESETCAUSE = PMC_RESETCAUSE_WDTRESET_MASK;
157 /* Enable the watchdog reset event to affect the system in the Power Management Controller */
158 PMC->CTRL |= PMC_CTRL_WDTRESETENABLE_MASK;
159 #endif /*FSL_FEATURE_WWDT_WDTRESET_FROM_PMC*/
160
161 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
162
163 #if !(defined(FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK) && FSL_FEATURE_WWDT_HAS_NO_OSCILLATOR_LOCK)
164 value = WWDT_MOD_WDEN(config->enableWwdt) | WWDT_MOD_WDRESET(config->enableWatchdogReset) |
165 WWDT_MOD_LOCK(config->enableLockOscillator);
166 #else
167 value = WWDT_MOD_WDEN(config->enableWwdt) | WWDT_MOD_WDRESET(config->enableWatchdogReset);
168 #endif
169 /* Clear legacy flag in the MOD register by software writing a "1" to this bit field.. */
170 if (0U != (base->MOD & WWDT_MOD_WDINT_MASK))
171 {
172 value |= WWDT_MOD_WDINT_MASK;
173 }
174 /* Set configuration */
175 primaskValue = DisableGlobalIRQ();
176 base->TC = WWDT_TC_COUNT(config->timeoutValue);
177 base->MOD = value;
178 base->WINDOW = WWDT_WINDOW_WINDOW(config->windowValue);
179 base->WARNINT = WWDT_WARNINT_WARNINT(config->warningValue);
180 /* Refreshes the WWDT timer. */
181 base->FEED = WWDT_FIRST_WORD_OF_REFRESH;
182 base->FEED = WWDT_SECOND_WORD_OF_REFRESH;
183 EnableGlobalIRQ(primaskValue);
184 /* Read counter value to wait wwdt timer start*/
185 if (config->enableWwdt)
186 {
187 while (base->TV == 0xFFUL)
188 {
189 }
190 }
191
192 /* This WDPROTECT bit can be set once by software and is only cleared by a reset */
193 if (config->enableWatchdogProtect && (0U == (base->MOD & WWDT_MOD_WDPROTECT_MASK)))
194 {
195 /* The config->clockFreq_Hz must be set in order to config the delay time. */
196 assert(0U != config->clockFreq_Hz);
197
198 /* Set the WDPROTECT bit after the Feed Sequence (0xAA, 0x55) with 3 WDCLK delay */
199 DelayUs = FREQUENCY_3MHZ / config->clockFreq_Hz + 1U;
200 SDK_DelayAtLeastUs(DelayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
201
202 base->MOD |= WWDT_MOD_WDPROTECT(1U);
203 }
204 }
205
206 /*!
207 * brief Shuts down the WWDT.
208 *
209 * This function shuts down the WWDT.
210 *
211 * param base WWDT peripheral base address
212 */
WWDT_Deinit(WWDT_Type * base)213 void WWDT_Deinit(WWDT_Type *base)
214 {
215 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
216 /* Disable the WWDT clock */
217 CLOCK_DisableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
218 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
219 }
220
221 /*!
222 * brief Refreshes the WWDT timer.
223 *
224 * This function feeds the WWDT.
225 * This function should be called before WWDT timer is in timeout. Otherwise, a reset is asserted.
226 *
227 * param base WWDT peripheral base address
228 */
WWDT_Refresh(WWDT_Type * base)229 void WWDT_Refresh(WWDT_Type *base)
230 {
231 uint32_t primaskValue = 0U;
232
233 /* Disable the global interrupt to protect refresh sequence */
234 primaskValue = DisableGlobalIRQ();
235 base->FEED = WWDT_FIRST_WORD_OF_REFRESH;
236 base->FEED = WWDT_SECOND_WORD_OF_REFRESH;
237 EnableGlobalIRQ(primaskValue);
238 }
239
240 /*!
241 * brief Clear WWDT flag.
242 *
243 * This function clears WWDT status flag.
244 *
245 * Example for clearing warning flag:
246 * code
247 * WWDT_ClearStatusFlags(wwdt_base, kWWDT_WarningFlag);
248 * endcode
249 * param base WWDT peripheral base address
250 * param mask The status flags to clear. This is a logical OR of members of the
251 * enumeration ::_wwdt_status_flags_t
252 */
WWDT_ClearStatusFlags(WWDT_Type * base,uint32_t mask)253 void WWDT_ClearStatusFlags(WWDT_Type *base, uint32_t mask)
254 {
255 /* Clear the WDINT bit so that we don't accidentally clear it */
256 uint32_t reg = (base->MOD & (~WWDT_MOD_WDINT_MASK));
257
258 /* Clear timeout by writing a zero */
259 if (0U != (mask & (uint32_t)kWWDT_TimeoutFlag))
260 {
261 reg &= ~WWDT_MOD_WDTOF_MASK;
262 #if defined(FSL_FEATURE_WWDT_WDTRESET_FROM_PMC) && (FSL_FEATURE_WWDT_WDTRESET_FROM_PMC)
263 /* PMC RESETCAUSE: set bit to clear it */
264 PMC->RESETCAUSE = PMC_RESETCAUSE_WDTRESET_MASK;
265 #endif /*FSL_FEATURE_WWDT_WDTRESET_FROM_PMC*/
266 }
267
268 /* Clear warning interrupt flag by writing a one */
269 if (0U != (mask & (uint32_t)kWWDT_WarningFlag))
270 {
271 reg |= WWDT_MOD_WDINT_MASK;
272 }
273
274 base->MOD = reg;
275 }
276