1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 // The LL layer for Timer Group register operations.
8 // Note that most of the register operations in this layer are non-atomic operations.
9
10 #pragma once
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 #include <stdlib.h>
17 #include <stdbool.h>
18 #include "hal/wdt_types.h"
19 #include "soc/rtc_cntl_periph.h"
20 #include "soc/rtc_cntl_struct.h"
21 #include "esp_attr.h"
22 #include "esp_assert.h"
23
24 //Type check wdt_stage_action_t
25 ESP_STATIC_ASSERT(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
26 ESP_STATIC_ASSERT(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
27 ESP_STATIC_ASSERT(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
28 ESP_STATIC_ASSERT(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
29 ESP_STATIC_ASSERT(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
30 //Type check wdt_reset_sig_length_t
31 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
32 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
33 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
34 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
35 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
36 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
37 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
38 ESP_STATIC_ASSERT(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
39
40 typedef rtc_cntl_dev_t rwdt_dev_t;
41
42 #define RWDT_DEV_GET() &RTCCNTL
43
44 /**
45 * @brief Enable the RWDT
46 *
47 * @param hw Start address of the peripheral registers.
48 */
rwdt_ll_enable(rtc_cntl_dev_t * hw)49 FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw)
50 {
51 hw->wdt_config0.en = 1;
52 }
53
54 /**
55 * @brief Disable the RWDT
56 *
57 * @param hw Start address of the peripheral registers.
58 * @note This function does not disable the flashboot mode. Therefore, given that
59 * the MWDT is disabled using this function, a timeout can still occur
60 * if the flashboot mode is simultaneously enabled.
61 */
rwdt_ll_disable(rtc_cntl_dev_t * hw)62 FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw)
63 {
64 hw->wdt_config0.en = 0;
65 }
66
67 /**
68 * @brief Check if the RWDT is enabled
69 *
70 * @param hw Start address of the peripheral registers.
71 * @return True if RTC WDT is enabled
72 */
rwdt_ll_check_if_enabled(rtc_cntl_dev_t * hw)73 FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw)
74 {
75 return (hw->wdt_config0.en) ? true : false;
76 }
77
78 /**
79 * @brief Configure a particular stage of the RWDT
80 *
81 * @param hw Start address of the peripheral registers.
82 * @param stage Which stage to configure
83 * @param timeout Number of timer ticks for the stage to timeout
84 * @param behavior What action to take when the stage times out
85 */
rwdt_ll_config_stage(rtc_cntl_dev_t * hw,wdt_stage_t stage,uint32_t timeout_ticks,wdt_stage_action_t behavior)86 FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior)
87 {
88 switch (stage) {
89 case WDT_STAGE0:
90 hw->wdt_config0.stg0 = behavior;
91 hw->wdt_config1 = timeout_ticks;
92 break;
93 case WDT_STAGE1:
94 hw->wdt_config0.stg1 = behavior;
95 hw->wdt_config2 = timeout_ticks;
96 break;
97 case WDT_STAGE2:
98 hw->wdt_config0.stg2 = behavior;
99 hw->wdt_config3 = timeout_ticks;
100 break;
101 case WDT_STAGE3:
102 hw->wdt_config0.stg3 = behavior;
103 hw->wdt_config4 = timeout_ticks;
104 break;
105 default:
106 abort();
107 }
108 }
109
110 /**
111 * @brief Disable a particular stage of the RWDT
112 *
113 * @param hw Start address of the peripheral registers.
114 * @param stage Which stage to disable
115 */
rwdt_ll_disable_stage(rtc_cntl_dev_t * hw,wdt_stage_t stage)116 FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage)
117 {
118 switch (stage) {
119 case WDT_STAGE0:
120 hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
121 break;
122 case WDT_STAGE1:
123 hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
124 break;
125 case WDT_STAGE2:
126 hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
127 break;
128 case WDT_STAGE3:
129 hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
130 break;
131 default:
132 abort();
133 }
134 }
135
136 /**
137 * @brief Enable or disable RWDT edge interrupt
138 *
139 * @param hw Start address of the peripheral registers.
140 * @param enable Whether to enable edge interrupt
141 */
rwdt_ll_set_edge_intr(rtc_cntl_dev_t * hw,bool enable)142 FORCE_INLINE_ATTR void rwdt_ll_set_edge_intr(rtc_cntl_dev_t *hw, bool enable)
143 {
144 hw->wdt_config0.edge_int_en = (enable) ? 1 : 0;
145 }
146
147 /**
148 * @brief Enable or disable RWDT level interrupt
149 *
150 * @param hw Start address of the peripheral registers.
151 * @param enable Whether to enable level interrupt
152 */
rwdt_ll_set_level_intr(rtc_cntl_dev_t * hw,bool enable)153 FORCE_INLINE_ATTR void rwdt_ll_set_level_intr(rtc_cntl_dev_t *hw, bool enable)
154 {
155 hw->wdt_config0.level_int_en = (enable) ? 1 : 0;
156 }
157
158 /**
159 * @brief Set the length of the CPU reset action
160 *
161 * @param hw Start address of the peripheral registers.
162 * @param length Length of CPU reset signal
163 */
rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t * hw,wdt_reset_sig_length_t length)164 FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
165 {
166 hw->wdt_config0.cpu_reset_length = length;
167 }
168
169 /**
170 * @brief Set the length of the system reset action
171 *
172 * @param hw Start address of the peripheral registers.
173 * @param length Length of system reset signal
174 */
rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t * hw,wdt_reset_sig_length_t length)175 FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
176 {
177 hw->wdt_config0.sys_reset_length = length;
178 }
179
180 /**
181 * @brief Enable/Disable the RWDT flashboot mode.
182 *
183 * @param hw Start address of the peripheral registers.
184 * @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode.
185 *
186 * @note Flashboot mode is independent and can trigger a WDT timeout event if the
187 * WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled
188 * on flashboot, and should be disabled by software when flashbooting completes.
189 */
rwdt_ll_set_flashboot_en(rtc_cntl_dev_t * hw,bool enable)190 FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable)
191 {
192 hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
193 }
194
195 /**
196 * @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU
197 *
198 * @param hw Start address of the peripheral registers.
199 * @param enable True to enable CPU0 to be reset, false to disable.
200 */
rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t * hw,bool enable)201 FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
202 {
203 hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0;
204 }
205
206 /**
207 * @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU
208 *
209 * @param hw Start address of the peripheral registers.
210 * @param enable True to enable CPU1 to be reset, false to disable.
211 */
rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t * hw,bool enable)212 FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
213 {
214 hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0;
215 }
216
217 /**
218 * @brief Enable/Disable the RWDT pause during sleep functionality
219 *
220 * @param hw Start address of the peripheral registers.
221 * @param enable True to enable, false to disable.
222 */
rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t * hw,bool enable)223 FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable)
224 {
225 hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0;
226 }
227
228 /**
229 * @brief Feed the RWDT
230 *
231 * Resets the current timer count and current stage.
232 *
233 * @param hw Start address of the peripheral registers.
234 */
rwdt_ll_feed(rtc_cntl_dev_t * hw)235 FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw)
236 {
237 hw->wdt_feed.feed = 1;
238 }
239
240 /**
241 * @brief Enable write protection of the RWDT registers
242 *
243 * @param hw Start address of the peripheral registers.
244 */
rwdt_ll_write_protect_enable(rtc_cntl_dev_t * hw)245 FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw)
246 {
247 hw->wdt_wprotect = 0;
248 }
249
250 /**
251 * @brief Disable write protection of the RWDT registers
252 *
253 * @param hw Start address of the peripheral registers.
254 */
rwdt_ll_write_protect_disable(rtc_cntl_dev_t * hw)255 FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw)
256 {
257 hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE;
258 }
259
260 /**
261 * @brief Enable the RWDT interrupt.
262 *
263 * @param hw Start address of the peripheral registers.
264 * @param enable True to enable RWDT interrupt, false to disable.
265 */
rwdt_ll_set_intr_enable(rtc_cntl_dev_t * hw,bool enable)266 FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable)
267 {
268 hw->int_ena.rtc_wdt = (enable) ? 1 : 0;
269 }
270
271 /**
272 * @brief Check if the RWDT interrupt has been triggered
273 *
274 * @param hw Start address of the peripheral registers.
275 * @return True if the RWDT interrupt was triggered
276 */
rwdt_ll_check_intr_status(rtc_cntl_dev_t * hw)277 FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw)
278 {
279 return (hw->int_st.rtc_wdt) ? true : false;
280 }
281
282 /**
283 * @brief Clear the RWDT interrupt status.
284 *
285 * @param hw Start address of the peripheral registers.
286 */
rwdt_ll_clear_intr_status(rtc_cntl_dev_t * hw)287 FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw)
288 {
289 hw->int_clr.rtc_wdt = 1;
290 }
291
292 #ifdef __cplusplus
293 }
294 #endif
295