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 #include <stdbool.h>
32 #include "cyhal_wdt.h"
33 #include "cyhal_wdt_impl.h"
34 #include "cy_wdt.h"
35 #include "cy_utils.h"
36 
37 #if (CYHAL_DRIVER_AVAILABLE_WDT)
38 
39 #if defined(__cplusplus)
40 extern "C" {
41 #endif
42 
43 #if defined(SRSS_NUM_WDT_A_BITS)
44 #define _CYHAL_WDT_MATCH_BITS     (SRSS_NUM_WDT_A_BITS)
45 #elif defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B)
46 #define _CYHAL_WDT_MATCH_BITS     (16)
47 #elif defined(COMPONENT_CAT1C)
48 #define _CYHAL_WDT_MATCH_BITS     (32)
49 #elif defined(COMPONENT_CAT2)
50 #define _CYHAL_WDT_MATCH_BITS     (16)
51 #else
52 #error Unhandled device type
53 #endif
54 
55 #if defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
56 #define _cyhal_wdt_lock()   Cy_WDT_Lock()
57 #define _cyhal_wdt_unlock() Cy_WDT_Unlock()
58 #else
59 #define _cyhal_wdt_lock()
60 #define _cyhal_wdt_unlock()
61 #endif
62 
63 #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
64 // 2^32 * .030518 ms
65 /** Maximum WDT timeout in milliseconds */
66 #define _CYHAL_WDT_MAX_TIMEOUT_MS 131073812
67 #elif defined(CY_IP_MXS22SRSS) && (_CYHAL_WDT_MATCH_BITS == 22)
68 // ILO, PILO, BAK all run at 32768 Hz - Period is ~0.030518 ms
69 // Max WDT Reset Period = 3 * (2^_CYHAL_WDT_MATCH_BITS) * 0.030518 ms
70 #define _CYHAL_WDT_MAX_TIMEOUT_MS 384000
71 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits) + match)
72 // ignore_bits range: 0 -> (_CYHAL_WDT_MATCH_BITS - 4) (Bottom four bits cannot be ignored)
73 #define _CYHAL_WDT_MAX_IGNORE_BITS (_CYHAL_WDT_MATCH_BITS - 4)
74 // match range: 0 -> 2^(_CYHAL_WDT_MATCH_BITS - ignore_bits)
75 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
76     {256000, 192001}, //  0 bit(s): min period: 256000ms, max period: 384000ms, round up from 192001+ms
77     {128000,  96001}, //  1 bit(s): min period: 128000ms, max period: 192000ms, round up from 96001+ms
78     { 64000,  48001}, //  2 bit(s): min period:  64000ms, max period:  96000ms, round up from 48001+ms
79     { 32000,  24001}, //  3 bit(s): min period:  32000ms, max period:  48000ms, round up from 24001+ms
80     { 16000,  12001}, //  4 bit(s): min period:  16000ms, max period:  24000ms, round up from 12001+ms
81     {  8000,   6001}, //  5 bit(s): min period:   8000ms, max period:  12000ms, round up from 6001+ms
82     {  4000,   3001}, //  6 bit(s): min period:   4000ms, max period:   6000ms, round up from 3001+ms
83     {  2000,   1501}, //  7 bit(s): min period:   2000ms, max period:   3000ms, round up from 1501+ms
84     {  1000,    751}, //  8 bit(s): min period:   1000ms, max period:   1500ms, round up from 751+ms
85     {   500,    376}, //  9 bit(s): min period:    500ms, max period:    750ms, round up from 376+ms
86     {   250,    188}, // 10 bit(s): min period:    250ms, max period:    375ms, round up from 188+ms
87     {   125,     94}, // 11 bit(s): min period:    125ms, max period:    187ms, round up from 94+ms
88     {    63,     47}, // 12 bit(s): min period:     63ms, max period:     93ms, round up from 47+ms
89     {    32,     24}, // 13 bit(s): min period:     32ms, max period:     46ms, round up from 24+ms
90     {    16,     12}, // 14 bit(s): min period:     16ms, max period:     23ms, round up from 12+ms
91     {     8,      6}, // 15 bit(s): min period:      8ms, max period:     11ms, round up from 6+ms
92     {     4,      3}, // 16 bit(s): min period:      4ms, max period:      5ms, round up from 3+ms
93     {     2,      2}, // 17 bit(s): min period:      2ms, max period:      2ms, round up from 2+ms
94     {     1,      1}, // 18 bit(s): min period:      1ms, max period:      1ms, round up from 1+ms
95 };
96 #elif defined(CY_IP_MXS40SRSS) || defined(CY_IP_MXS40SSRSS)
97 // ILO Frequency = 32768 Hz
98 // ILO Period = 1 / 32768 Hz = .030518 ms
99 // WDT Reset Period (timeout_ms) = .030518 ms * (2 * 2^(16 - ignore_bits) + match)
100 // ignore_bits range: 0 - 12
101 // match range: 0 - 2^(16 - ignore_bits)
102 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
103     {4000, 3001}, //  0 bit(s): min period: 4000ms, max period: 6000ms, round up from 3001+ms
104     {2000, 1501}, //  1 bit(s): min period: 2000ms, max period: 3000ms, round up from 1501+ms
105     {1000,  751}, //  2 bit(s): min period: 1000ms, max period: 1500ms, round up from 751+ms
106     { 500,  376}, //  3 bit(s): min period:  500ms, max period:  750ms, round up from 376+ms
107     { 250,  188}, //  4 bit(s): min period:  250ms, max period:  375ms, round up from 188+ms
108     { 125,   94}, //  5 bit(s): min period:  125ms, max period:  187ms, round up from 94+ms
109     {  63,   47}, //  6 bit(s): min period:   63ms, max period:   93ms, round up from 47+ms
110     {  32,   24}, //  7 bit(s): min period:   32ms, max period:   46ms, round up from 24+ms
111     {  16,   12}, //  8 bit(s): min period:   16ms, max period:   23ms, round up from 12+ms
112     {   8,    6}, //  9 bit(s): min period:    8ms, max period:   11ms, round up from 6+ms
113     {   4,    3}, // 10 bit(s): min period:    4ms, max period:    5ms, round up from 3+ms
114     {   2,    2}, // 11 bit(s): min period:    2ms, max period:    2ms, round up from 2+ms
115     {   1,    1}, // 12 bit(s): min period:    1ms, max period:    1ms, round up from 1+ms
116 };
117 #elif defined(COMPONENT_CAT2)
118 // ILO Frequency = 40000 Hz
119 // ILO Period = 1 / 40000 Hz = .025 ms
120 // WDT Reset Period (timeout_ms) = .025 ms * (2 * 2^(16 - ignore_bits) + match)
121 // ignore_bits range: 0 - 16 (only need up to 12)
122 // match range: 0 - 2^(16 - ignore_bits)
123 static const _cyhal_wdt_ignore_bits_data_t _cyhal_wdt_ignore_data[] = {
124     {3277, 2458}, //  0 bit(s): min period: 3277ms, max period: 4915ms, round up from 2458+ms
125     {1639, 1229}, //  1 bit(s): min period: 1639ms, max period: 2457ms, round up from 1229+ms
126     { 820,  615}, //  2 bit(s): min period:  820ms, max period: 1228ms, round up from 615+ms
127     { 410,  308}, //  3 bit(s): min period:  410ms, max period:  614ms, round up from 308+ms
128     { 205,  154}, //  4 bit(s): min period:  205ms, max period:  307ms, round up from 154+ms
129     { 103,   77}, //  5 bit(s): min period:  103ms, max period:  153ms, round up from 77+ms
130     {  52,   39}, //  6 bit(s): min period:   52ms, max period:   76ms, round up from 39+ms
131     {  26,   20}, //  7 bit(s): min period:   26ms, max period:   38ms, round up from 20+ms
132     {  13,   10}, //  8 bit(s): min period:   13ms, max period:   19ms, round up from 10+ms
133     {   7,    5}, //  9 bit(s): min period:    7ms, max period:    9ms, round up from 5+ms
134     {   4,    3}, // 10 bit(s): min period:    4ms, max period:    4ms, round up from 3+ms
135     {   2,    2}, // 11 bit(s): min period:    2ms, max period:    2ms, round up from 2+ms
136     {   1,    1}, // 12 bit(s): min period:    1ms, max period:    1ms, round up from 1+ms
137 };
138 #endif
139 
140 static bool _cyhal_wdt_initialized = false;
141 static uint16_t _cyhal_wdt_initial_timeout_ms = 0;
142 
143 #if defined (CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms)144 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms)
145 {
146     uint32_t timeout = ((uint64_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
147     return (uint32_t)(timeout + Cy_WDT_GetCount());
148 }
149 #else
150 
151 static uint16_t _cyhal_wdt_rounded_timeout_ms = 0;
152 static uint32_t _cyhal_wdt_ignore_bits = 0;
153 
_cyhal_wdt_timeout_to_match(uint16_t timeout_ms,uint16_t ignore_bits)154 __STATIC_INLINE uint16_t _cyhal_wdt_timeout_to_match(uint16_t timeout_ms, uint16_t ignore_bits)
155 {
156     uint32_t timeout = ((uint32_t)timeout_ms * CY_SYSCLK_ILO_FREQ) / 1000;
157     return (uint16_t)(timeout - (1UL << ((_CYHAL_WDT_MATCH_BITS + 1) - ignore_bits)) + Cy_WDT_GetCount());
158 }
159 
160 // 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)161 __STATIC_INLINE uint32_t _cyhal_wdt_timeout_to_ignore_bits(uint32_t *timeout_ms)
162 {
163     for (uint32_t i = 0; i <= _CYHAL_WDT_MAX_IGNORE_BITS; i++)
164     {
165         if (*timeout_ms >= _cyhal_wdt_ignore_data[i].round_threshold_ms)
166         {
167             if (*timeout_ms < _cyhal_wdt_ignore_data[i].min_period_ms)
168             {
169                 *timeout_ms = _cyhal_wdt_ignore_data[i].min_period_ms;
170             }
171             return i;
172         }
173     }
174     return _CYHAL_WDT_MAX_IGNORE_BITS; // Ideally should never reach this
175 }
176 #endif
177 
cyhal_wdt_init(cyhal_wdt_t * obj,uint32_t timeout_ms)178 cy_rslt_t cyhal_wdt_init(cyhal_wdt_t *obj, uint32_t timeout_ms)
179 {
180     if ((timeout_ms == 0) || (timeout_ms > _CYHAL_WDT_MAX_TIMEOUT_MS))
181         return CY_RSLT_WDT_INVALID_TIMEOUT;
182     if (_cyhal_wdt_initialized)
183         return CY_RSLT_WDT_ALREADY_INITIALIZED;
184 
185     cyhal_wdt_stop(obj); // Stop and unlock before doing other work
186     Cy_WDT_ClearInterrupt();
187     Cy_WDT_MaskInterrupt();
188 
189     _cyhal_wdt_initial_timeout_ms = timeout_ms;
190     #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
191     Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
192     Cy_WDT_SetUpperAction(CY_WDT_LOW_UPPER_LIMIT_ACTION_RESET);
193     #else
194     _cyhal_wdt_ignore_bits = _cyhal_wdt_timeout_to_ignore_bits(&timeout_ms);
195     _cyhal_wdt_rounded_timeout_ms = timeout_ms;
196     Cy_WDT_SetIgnoreBits(_cyhal_wdt_ignore_bits);
197     Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
198     #endif
199     cyhal_wdt_start(obj);
200     _cyhal_wdt_initialized = true;
201 
202     return CY_RSLT_SUCCESS;
203 }
204 
cyhal_wdt_free(cyhal_wdt_t * obj)205 void cyhal_wdt_free(cyhal_wdt_t *obj)
206 {
207     CY_UNUSED_PARAMETER(obj);
208     cyhal_wdt_stop(obj);
209     _cyhal_wdt_initialized = false;
210 }
211 
cyhal_wdt_kick(cyhal_wdt_t * obj)212 void cyhal_wdt_kick(cyhal_wdt_t *obj)
213 {
214     CY_UNUSED_PARAMETER(obj);
215     _cyhal_wdt_unlock();
216     Cy_WDT_ClearWatchdog(); /* Clear to prevent reset from WDT */
217     #if defined(CY_IP_MXS40SRSS) && (CY_IP_MXS40SRSS_VERSION >= 3)
218     Cy_WDT_SetUpperLimit(_cyhal_wdt_timeout_to_match(_cyhal_wdt_initial_timeout_ms));
219     #else
220     Cy_WDT_SetMatch(_cyhal_wdt_timeout_to_match(_cyhal_wdt_rounded_timeout_ms, _cyhal_wdt_ignore_bits));
221     #endif
222     _cyhal_wdt_lock();
223 }
224 
cyhal_wdt_start(cyhal_wdt_t * obj)225 void cyhal_wdt_start(cyhal_wdt_t *obj)
226 {
227     CY_UNUSED_PARAMETER(obj);
228     _cyhal_wdt_unlock();
229     Cy_WDT_Enable();
230     _cyhal_wdt_lock();
231 }
232 
cyhal_wdt_stop(cyhal_wdt_t * obj)233 void cyhal_wdt_stop(cyhal_wdt_t *obj)
234 {
235     CY_UNUSED_PARAMETER(obj);
236     _cyhal_wdt_unlock();
237     Cy_WDT_Disable();
238 }
239 
cyhal_wdt_get_timeout_ms(cyhal_wdt_t * obj)240 uint32_t cyhal_wdt_get_timeout_ms(cyhal_wdt_t *obj)
241 {
242     CY_UNUSED_PARAMETER(obj);
243     return _cyhal_wdt_initial_timeout_ms;
244 }
245 
cyhal_wdt_get_max_timeout_ms(void)246 uint32_t cyhal_wdt_get_max_timeout_ms(void)
247 {
248     return _CYHAL_WDT_MAX_TIMEOUT_MS;
249 }
250 
cyhal_wdt_is_enabled(cyhal_wdt_t * obj)251 bool cyhal_wdt_is_enabled(cyhal_wdt_t *obj)
252 {
253     CY_UNUSED_PARAMETER(obj);
254     return Cy_WDT_IsEnabled();
255 }
256 
257 #if defined(__cplusplus)
258 }
259 #endif
260 
261 #endif // CYHAL_DRIVER_AVAILABLE_WDT
262