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