1 /***************************************************************************//**
2 * \file cyhal_wdt.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Watchdog Timer.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 *
11 ********************************************************************************
12 * \copyright
13 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or
14 * an affiliate of Cypress Semiconductor Corporation
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 *
18 * Licensed under the Apache License, Version 2.0 (the "License");
19 * you may not use this file except in compliance with the License.
20 * You may obtain a copy of the License at
21 *
22 *     http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Unless required by applicable law or agreed to in writing, software
25 * distributed under the License is distributed on an "AS IS" BASIS,
26 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27 * See the License for the specific language governing permissions and
28 * limitations under the License.
29 *******************************************************************************/
30 
31 
32 /**
33 * \addtogroup group_hal_impl_wdt WDT (Watchdog Timer)
34 * \ingroup group_hal_impl
35 * \{
36 *\section subsection_wdt_notes Notes
37 * WDT timeout values for Active and Hibernate modes are different.
38 * In Active mode, the timeout value is used to create a match count that is matched
39 * by the hardware twice, then triggers (ISR) on the third match.
40 * In Hibernate mode, the trigger (reset) happens on the first match. Depending on
41 * the timing of starting the WDT and entering Hibernate mode, this can lead to
42 * WDT reset occurring earlier than it would if the device had not entered Hibernate.
43 *
44 * \} group_hal_wdt
45 */
46 
47 #include <stdbool.h>
48 #include "cyhal_wdt.h"
49 #include "cyhal_wdt_impl.h"
50 #include "cy_wdt.h"
51 #include "cy_utils.h"
52 
53 #if (CYHAL_DRIVER_AVAILABLE_WDT)
54 
55 #if defined(__cplusplus)
56 extern "C" {
57 #endif
58 
59 #if defined(SRSS_NUM_WDT_A_BITS)
60 #define _CYHAL_WDT_MATCH_BITS     (SRSS_NUM_WDT_A_BITS)
61 #elif defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1C)
62 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION < 2)
63 #define _CYHAL_WDT_MATCH_BITS     (16)
64 #else /* CY_IP_MXS40SRSS_VERSION >= 2 */
65 #define _CYHAL_WDT_MATCH_BITS     (32)
66 #endif
67 #elif defined(COMPONENT_CAT1B)
68 #define _CYHAL_WDT_MATCH_BITS     (16)
69 #elif defined(COMPONENT_CAT2)
70 #define _CYHAL_WDT_MATCH_BITS     (16)
71 #else
72 #error Unhandled device type
73 #endif
74 
75 #if defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
76 #define _cyhal_wdt_lock()   Cy_WDT_Lock()
77 #define _cyhal_wdt_unlock() Cy_WDT_Unlock()
78 #else
79 #define _cyhal_wdt_lock()
80 #define _cyhal_wdt_unlock()
81 #endif
82 
83 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
84 // 2^32 * .030518 ms
85 /** Maximum WDT timeout in milliseconds */
86 #define _CYHAL_WDT_MAX_TIMEOUT_MS 131073812
87 #elif defined(CY_IP_MXS22SRSS) && (_CYHAL_WDT_MATCH_BITS == 22)
88 // ILO, PILO, BAK all run at 32768 Hz - Period is ~0.030518 ms
89 // Max WDT Reset Period = 3 * (2^_CYHAL_WDT_MATCH_BITS) * 0.030518 ms
90 #define _CYHAL_WDT_MAX_TIMEOUT_MS 384000
91 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits) + match)
92 // ignore_bits range: 0 -> (_CYHAL_WDT_MATCH_BITS - 4) (Bottom four bits cannot be ignored)
93 #define _CYHAL_WDT_MAX_IGNORE_BITS (_CYHAL_WDT_MATCH_BITS - 4)
94 // match range: 0 -> 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits)
95 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
96     {256000, 192001}, //  0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
97     {128000,  96001}, //  1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
98     { 64000,  48001}, //  2 bit(s): min period:  64000ms, max period:  96000ms, round up from 48001+ms
99     { 32000,  24001}, //  3 bit(s): min period:  32000ms, max period:  48000ms, round up from 24001+ms
100     { 16000,  12001}, //  4 bit(s): min period:  16000ms, max period:  24000ms, round up from 12001+ms
101     {  8000,   6001}, //  5 bit(s): min period:   8000ms, max period:  12000ms, round up from 6001+ms
102     {  4000,   3001}, //  6 bit(s): min period:   4000ms, max period:   6000ms, round up from 3001+ms
103     {  2000,   1501}, //  7 bit(s): min period:   2000ms, max period:   3000ms, round up from 1501+ms
104     {  1000,    751}, //  8 bit(s): min period:   1000ms, max period:   1500ms, round up from 751+ms
105     {   500,    376}, //  9 bit(s): min period:    500ms, max period:    750ms, round up from 376+ms
106     {   250,    188}, // 10 bit(s): min period:    250ms, max period:    375ms, round up from 188+ms
107     {   125,     94}, // 11 bit(s): min period:    125ms, max period:    187ms, round up from 94+ms
108     {    63,     47}, // 12 bit(s): min period:     63ms, max period:     93ms, round up from 47+ms
109     {    32,     24}, // 13 bit(s): min period:     32ms, max period:     46ms, round up from 24+ms
110     {    16,     12}, // 14 bit(s): min period:     16ms, max period:     23ms, round up from 12+ms
111     {     8,      6}, // 15 bit(s): min period:      8ms, max period:     11ms, round up from 6+ms
112     {     4,      3}, // 16 bit(s): min period:      4ms, max period:      5ms, round up from 3+ms
113     {     2,      2}, // 17 bit(s): min period:      2ms, max period:      2ms, round up from 2+ms
114     {     1,      1}, // 18 bit(s): min period:      1ms, max period:      1ms, round up from 1+ms
115 };
116 #elif defined(CY_IP_MXS40SRSS)
117 // ILO Frequency = 32768 Hz
118 // ILO Period = 1 / 32768 Hz = .030518 ms
119 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(16 - ignore_bits) + match)
120 // ignore_bits range: 0 - 12
121 // match range: 0 - 2^(16 - ignore_bits)
122 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
123     {4000, 3001}, //  0 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
124     {2000, 1501}, //  1 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
125     {1000,  751}, //  2 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
126     { 500,  376}, //  3 bit(s): min period:  500ms, max period:  750ms, round up from 376+ms
127     { 250,  188}, //  4 bit(s): min period:  250ms, max period:  375ms, round up from 188+ms
128     { 125,   94}, //  5 bit(s): min period:  125ms, max period:  187ms, round up from 94+ms
129     {  63,   47}, //  6 bit(s): min period:   63ms, max period:   93ms, round up from 47+ms
130     {  32,   24}, //  7 bit(s): min period:   32ms, max period:   46ms, round up from 24+ms
131     {  16,   12}, //  8 bit(s): min period:   16ms, max period:   23ms, round up from 12+ms
132     {   8,    6}, //  9 bit(s): min period:    8ms, max period:   11ms, round up from 6+ms
133     {   4,    3}, // 10 bit(s): min period:    4ms, max period:    5ms, round up from 3+ms
134     {   2,    2}, // 11 bit(s): min period:    2ms, max period:    2ms, round up from 2+ms
135     {   1,    1}, // 12 bit(s): min period:    1ms, max period:    1ms, round up from 1+ms
136 };
137 #elif defined(CY_IP_MXS40SSRSS)
138 // ILO Frequency = 32768 Hz
139 // ILO Period = 1 / 32768 Hz = .030518 ms
140 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MAX_IGNORE_BITS - ignore_bits) + match)
141 // ignore_bits range: 0 - 18
142 // match range: 0 - 2^(_CYHAL_WDT_MAX_IGNORE_BITS - ignore_bits)
143 
144 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
145     {256000, 192001}, //  0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
146     {128000,  96001}, //  1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
147     { 64000,  48001}, //  2 bit(s): min period:  64000ms, max period:  96000ms, round up from 48001+ms
148     { 32000,  24001}, //  3 bit(s): min period:  32000ms, max period:  48000ms, round up from 24001+ms
149     { 16000,  12001}, //  4 bit(s): min period:  16000ms, max period:  24000ms, round up from 12001+ms
150     {  8000,   6001}, //  5 bit(s): min period:   8000ms, max period:  12000ms, round up from 6001+ms
151     {  4000,   3001}, //  6 bit(s): min period:   4000ms, max period:   6000ms, round up from 3001+ms
152     {  2000,   1501}, //  7 bit(s): min period:   2000ms, max period:   3000ms, round up from 1501+ms
153     {  1000,    751}, //  8 bit(s): min period:   1000ms, max period:   1500ms, round up from 751+ms
154     {   500,    376}, //  9 bit(s): min period:    500ms, max period:    750ms, round up from 376+ms
155     {   250,    188}, // 10 bit(s): min period:    250ms, max period:    375ms, round up from 188+ms
156     {   125,     94}, // 11 bit(s): min period:    125ms, max period:    187ms, round up from 94+ms
157     {    63,     47}, // 12 bit(s): min period:     63ms, max period:     93ms, round up from 47+ms
158     {    32,     24}, // 13 bit(s): min period:     32ms, max period:     46ms, round up from 24+ms
159     {    16,     12}, // 14 bit(s): min period:     16ms, max period:     23ms, round up from 12+ms
160     {     8,      6}, // 15 bit(s): min period:      8ms, max period:     11ms, round up from 6+ms
161     {     4,      3}, // 16 bit(s): min period:      4ms, max period:      5ms, round up from 3+ms
162     {     2,      2}, // 17 bit(s): min period:      2ms, max period:      2ms, round up from 2+ms
163     {     1,      1}, // 18 bit(s): min period:      1ms, max period:      1ms, round up from 1+ms
164 };
165 #elif defined(COMPONENT_CAT2)
166 // ILO Frequency = 40000 Hz
167 // ILO Period = 1 / 40000 Hz = .025 ms
168 // WDT Reset Period (timeout_ms) = .025 ms * (2 * 2^(16 - ignore_bits) + match)
169 // ignore_bits range: 0 - 16 (only need up to 12)
170 // match range: 0 - 2^(16 - ignore_bits)
171 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
172     {3277, 2458}, //  0 bit(s): min period: 3277ms, max period: 4915ms, round up from 2458+ms
173     {1639, 1229}, //  1 bit(s): min period: 1639ms, max period: 2457ms, round up from 1229+ms
174     { 820,  615}, //  2 bit(s): min period:  820ms, max period: 1228ms, round up from 615+ms
175     { 410,  308}, //  3 bit(s): min period:  410ms, max period:  614ms, round up from 308+ms
176     { 205,  154}, //  4 bit(s): min period:  205ms, max period:  307ms, round up from 154+ms
177     { 103,   77}, //  5 bit(s): min period:  103ms, max period:  153ms, round up from 77+ms
178     {  52,   39}, //  6 bit(s): min period:   52ms, max period:   76ms, round up from 39+ms
179     {  26,   20}, //  7 bit(s): min period:   26ms, max period:   38ms, round up from 20+ms
180     {  13,   10}, //  8 bit(s): min period:   13ms, max period:   19ms, round up from 10+ms
181     {   7,    5}, //  9 bit(s): min period:    7ms, max period:    9ms, round up from 5+ms
182     {   4,    3}, // 10 bit(s): min period:    4ms, max period:    4ms, round up from 3+ms
183     {   2,    2}, // 11 bit(s): min period:    2ms, max period:    2ms, round up from 2+ms
184     {   1,    1}, // 12 bit(s): min period:    1ms, max period:    1ms, round up from 1+ms
185 };
186 #endif
187 
188 static bool _cyhal_wdt_initialized = false;
189 static uint32_t _cyhal_wdt_initial_timeout_ms = 0;
190 
191 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms)192 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms)
193 {
194     uint32_t timeout = ((uint64_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
195     return (uint32_t)(timeout + Cy_WDT_GetCount());
196 }
197 #else /* defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2) */
198 
199 static uint32_t _cyhal_wdt_rounded_timeout_ms = 0;
200 static uint32_t _cyhal_wdt_ignore_bits = 0;
201 
202 #define _CYHAL_DETERMINE_MATCH_BITS(bits)   ( (WDT_MAX_IGNORE_BITS) - (bits) )
203 #define _CYHAL_GET_COUNT_FROM_MATCH_BITS(bits)  (2UL << _CYHAL_DETERMINE_MATCH_BITS(bits) )
204 
_cyhal_wdt_timeout_to_match(uint32_t timeout_ms,uint32_t ignore_bits)205 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint32_t timeout_ms, uint32_t ignore_bits)
206 {
207     uint32_t wrap_count_for_ignore_bits = (_CYHAL_GET_COUNT_FROM_MATCH_BITS(ignore_bits) );
208     uint32_t timeout_count = ( (timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000UL);
209     /* handle multiple possible wraps of WDT counter */
210     timeout_count = ( (timeout_count + Cy_WDT_GetCount()) % wrap_count_for_ignore_bits);
211     return timeout_count;
212 }
213 
214 // Rounds up *timeout_ms if it's outside of the valid timeout range (_cyhal_wdt_ignore_data)
_cyhal_wdt_timeout_to_ignore_bits(uint32_t * timeout_ms)215 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_ignore_bits(uint32_t *timeout_ms)
216 {
217     for (uint32_t i = 0; i <= _CYHAL_WDT_MAX_IGNORE_BITS; i++)
218     {
219         if (*timeout_ms >= _cyhal_wdt_ignore_data[i].round_threshold_ms)
220         {
221             if (*timeout_ms < _cyhal_wdt_ignore_data[i].min_period_ms)
222             {
223                 *timeout_ms = _cyhal_wdt_ignore_data[i].min_period_ms;
224             }
225             return i;
226         }
227     }
228     return _CYHAL_WDT_MAX_IGNORE_BITS; // Ideally should never reach this
229 }
230 
231 #endif /* defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2) */
232 
cyhal_wdt_init(cyhal_wdt_t * obj,uint32_t timeout_ms)233 cy_rslt_t cyhal_wdt_init(cyhal_wdt_t *obj, uint32_t timeout_ms)
234 {
235     if ((timeout_ms == 0) || (timeout_ms > _CYHAL_WDT_MAX_TIMEOUT_MS))
236         return CY_RSLT_WDT_INVALID_TIMEOUT;
237     if (_cyhal_wdt_initialized)
238         return CY_RSLT_WDT_ALREADY_INITIALIZED;
239 
240     cyhal_wdt_stop(obj); // Stop and unlock before doing other work
241 
242     Cy_WDT_ClearInterrupt();
243     Cy_WDT_MaskInterrupt();
244 
245     _cyhal_wdt_initial_timeout_ms = timeout_ms;
246 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
247     Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
248     Cy_WDT_SetUpperAction(CY_WDT_LOW_UPPER_LIMIT_ACTION_RESET);
249 #else
250     _cyhal_wdt_ignore_bits = _cyhal_wdt_timeout_to_ignore_bits(&timeout_ms);
251     _cyhal_wdt_rounded_timeout_ms = timeout_ms;
252     #if defined(SRSS_NUM_WDT_A_BITS) && (SRSS_NUM_WDT_A_BITS == 22)
253     /* Cy_WDT_SetMatchBits configures the bit position above which the bits will be ignored for match,
254      * while _cyhal_wdt_timeout_to_ignore_bits returns number of timer MSB to ignore, so conversion
255      * is needed. */
256     Cy_WDT_SetMatchBits(_CYHAL_DETERMINE_MATCH_BITS(_cyhal_wdt_ignore_bits) );
257     #else
258     Cy_WDT_SetIgnoreBits(_cyhal_wdt_ignore_bits);
259     #endif
260 
261 #if defined(COMPONENT_CAT1) && (CY_WDT_DRV_VERSION_MAJOR > 1 ) && (CY_WDT_DRV_VERSION_MINOR > 6 )
262     /* Reset counter every time - large current counts in WDT can cause problems on some boards */
263     Cy_WDT_ResetCounter();
264     /* Twice, as reading back after 1 reset gives same value as before single reset */
265     Cy_WDT_ResetCounter();
266 #endif
267 
268     Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
269 #endif
270 
271     cyhal_wdt_start(obj);
272     _cyhal_wdt_initialized = true;
273 
274     return CY_RSLT_SUCCESS;
275 }
276 
cyhal_wdt_free(cyhal_wdt_t * obj)277 void cyhal_wdt_free(cyhal_wdt_t *obj)
278 {
279     CY_UNUSED_PARAMETER(obj);
280     cyhal_wdt_stop(obj);
281     _cyhal_wdt_initialized = false;
282 }
283 
cyhal_wdt_kick(cyhal_wdt_t * obj)284 void cyhal_wdt_kick(cyhal_wdt_t *obj)
285 {
286     CY_UNUSED_PARAMETER(obj);
287     _cyhal_wdt_unlock();
288     Cy_WDT_ClearWatchdog(); /* Clear to prevent reset from WDT */
289     #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 2)
290     Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
291     #else
292     Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
293     #endif
294     _cyhal_wdt_lock();
295 }
296 
cyhal_wdt_start(cyhal_wdt_t * obj)297 void cyhal_wdt_start(cyhal_wdt_t *obj)
298 {
299     CY_UNUSED_PARAMETER(obj);
300     _cyhal_wdt_unlock();
301     Cy_WDT_Enable();
302     _cyhal_wdt_lock();
303 }
304 
cyhal_wdt_stop(cyhal_wdt_t * obj)305 void cyhal_wdt_stop(cyhal_wdt_t *obj)
306 {
307     CY_UNUSED_PARAMETER(obj);
308     _cyhal_wdt_unlock();
309     Cy_WDT_Disable();
310 }
311 
cyhal_wdt_get_timeout_ms(cyhal_wdt_t * obj)312 uint32_t cyhal_wdt_get_timeout_ms(cyhal_wdt_t *obj)
313 {
314     CY_UNUSED_PARAMETER(obj);
315     return _cyhal_wdt_initial_timeout_ms;
316 }
317 
cyhal_wdt_get_max_timeout_ms(void)318 uint32_t cyhal_wdt_get_max_timeout_ms(void)
319 {
320     return _CYHAL_WDT_MAX_TIMEOUT_MS;
321 }
322 
cyhal_wdt_is_enabled(cyhal_wdt_t * obj)323 bool cyhal_wdt_is_enabled(cyhal_wdt_t *obj)
324 {
325     CY_UNUSED_PARAMETER(obj);
326     return Cy_WDT_IsEnabled();
327 }
328 
329 #if defined(__cplusplus)
330 }
331 #endif
332 
333 #endif // CYHAL_DRIVER_AVAILABLE_WDT
334