1 /*
2  * SPDX-FileCopyrightText: 2020-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 "hal/efuse_ll.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 (see note).
84  * @param behavior What action to take when the stage times out
85  *
86  * @note The value of of RWDT stage 0 timeout register is special, in
87  *       that an implicit multiplier is applied to that value to produce
88  *       and effective timeout tick value. The multiplier is dependent
89  *       on an EFuse value. Therefore, when configuring stage 0, the valid
90  *       values for the timeout argument are:
91  *       - If Efuse value is 0, any even number between [2,2*UINT32_MAX]
92  *       - If Efuse value is 1, any multiple of 4 between [4,4*UINT32_MAX]
93  *       - If Efuse value is 2, any multiple of 8 between [8,8*UINT32_MAX]
94  *       - If Efuse value is 3, any multiple of 16 between [16,16*UINT32_MAX]
95  */
rwdt_ll_config_stage(rtc_cntl_dev_t * hw,wdt_stage_t stage,uint32_t timeout_ticks,wdt_stage_action_t behavior)96 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)
97 {
98     switch (stage) {
99     case WDT_STAGE0:
100         hw->wdt_config0.stg0 = behavior;
101         //Account of implicty multiplier applied to stage 0 timeout tick config value
102         hw->wdt_config1 = timeout_ticks >> (1 + efuse_ll_get_wdt_delay_sel());
103         break;
104     case WDT_STAGE1:
105         hw->wdt_config0.stg1 = behavior;
106         hw->wdt_config2 = timeout_ticks;
107         break;
108     case WDT_STAGE2:
109         hw->wdt_config0.stg2 = behavior;
110         hw->wdt_config3 = timeout_ticks;
111         break;
112     case WDT_STAGE3:
113         hw->wdt_config0.stg3 = behavior;
114         hw->wdt_config4 = timeout_ticks;
115         break;
116     default:
117         abort();
118     }
119 }
120 
121 /**
122  * @brief Disable a particular stage of the RWDT
123  *
124  * @param hw Start address of the peripheral registers.
125  * @param stage Which stage to disable
126  */
rwdt_ll_disable_stage(rtc_cntl_dev_t * hw,wdt_stage_t stage)127 FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage)
128 {
129     switch (stage) {
130     case WDT_STAGE0:
131         hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
132         break;
133     case WDT_STAGE1:
134         hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
135         break;
136     case WDT_STAGE2:
137         hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
138         break;
139     case WDT_STAGE3:
140         hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
141         break;
142     default:
143         abort();
144     }
145 }
146 
147 /**
148  * @brief Set the length of the CPU reset action
149  *
150  * @param hw Start address of the peripheral registers.
151  * @param length Length of CPU reset signal
152  */
rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t * hw,wdt_reset_sig_length_t length)153 FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
154 {
155     hw->wdt_config0.cpu_reset_length = length;
156 }
157 
158 /**
159  * @brief Set the length of the system reset action
160  *
161  * @param hw Start address of the peripheral registers.
162  * @param length Length of system reset signal
163  */
rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t * hw,wdt_reset_sig_length_t length)164 FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
165 {
166     hw->wdt_config0.sys_reset_length = length;
167 }
168 
169 /**
170  * @brief Enable/Disable the RWDT flashboot mode.
171  *
172  * @param hw Start address of the peripheral registers.
173  * @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode.
174  *
175  * @note Flashboot mode is independent and can trigger a WDT timeout event if the
176  *       WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled
177  *       on flashboot, and should be disabled by software when flashbooting completes.
178  */
rwdt_ll_set_flashboot_en(rtc_cntl_dev_t * hw,bool enable)179 FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t *hw, bool enable)
180 {
181     hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
182 }
183 
184 /**
185  * @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU
186  *
187  * @param hw Start address of the peripheral registers.
188  * @param enable True to enable CPU0 to be reset, false to disable.
189  */
rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t * hw,bool enable)190 FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t *hw, bool enable)
191 {
192     hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0;
193 }
194 
195 /**
196  * @brief Enable/Disable the RWDT pause during sleep functionality
197  *
198  * @param hw Start address of the peripheral registers.
199  * @param enable True to enable, false to disable.
200  */
rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t * hw,bool enable)201 FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t *hw, bool enable)
202 {
203     hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0;
204 }
205 
206 /**
207  * @brief Enable/Disable chip reset on RWDT timeout.
208  *
209  * A chip reset also resets the analog portion of the chip. It will appear as a
210  * POWERON reset rather than an RTC reset.
211  *
212  * @param hw Start address of the peripheral registers.
213  * @param enable True to enable, false to disable.
214  */
rwdt_ll_set_chip_reset_en(rtc_cntl_dev_t * hw,bool enable)215 FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_en(rtc_cntl_dev_t *hw, bool enable)
216 {
217     hw->wdt_config0.chip_reset_en = (enable) ? 1 : 0;
218 }
219 
220 /**
221  * @brief Set width of chip reset signal
222  *
223  * @param hw Start address of the peripheral registers.
224  * @param width Width of chip reset signal in terms of number of RTC_SLOW_CLK cycles
225  */
rwdt_ll_set_chip_reset_width(rtc_cntl_dev_t * hw,uint32_t width)226 FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_width(rtc_cntl_dev_t *hw, uint32_t width)
227 {
228     hw->wdt_config0.chip_reset_width = width;
229 }
230 
231 /**
232  * @brief Feed the RWDT
233  *
234  * Resets the current timer count and current stage.
235  *
236  * @param hw Start address of the peripheral registers.
237  */
rwdt_ll_feed(rtc_cntl_dev_t * hw)238 FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw)
239 {
240     hw->wdt_feed.feed = 1;
241 }
242 
243 /**
244  * @brief Enable write protection of the RWDT registers
245  *
246  * @param hw Start address of the peripheral registers.
247  */
rwdt_ll_write_protect_enable(rtc_cntl_dev_t * hw)248 FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw)
249 {
250     hw->wdt_wprotect = 0;
251 }
252 
253 /**
254  * @brief Disable write protection of the RWDT registers
255  *
256  * @param hw Start address of the peripheral registers.
257  */
rwdt_ll_write_protect_disable(rtc_cntl_dev_t * hw)258 FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw)
259 {
260     hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE;
261 }
262 
263 /**
264  * @brief Enable the RWDT interrupt.
265  *
266  * @param hw Start address of the peripheral registers.
267  * @param enable True to enable RWDT interrupt, false to disable.
268  */
rwdt_ll_set_intr_enable(rtc_cntl_dev_t * hw,bool enable)269 FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t *hw, bool enable)
270 {
271     hw->int_ena.rtc_wdt = (enable) ? 1 : 0;
272 }
273 
274 /**
275  * @brief Check if the RWDT interrupt has been triggered
276  *
277  * @param hw Start address of the peripheral registers.
278  * @return True if the RWDT interrupt was triggered
279  */
rwdt_ll_check_intr_status(rtc_cntl_dev_t * hw)280 FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw)
281 {
282     return (hw->int_st.rtc_wdt) ? true : false;
283 }
284 
285 /**
286  * @brief Clear the RWDT interrupt status.
287  *
288  * @param hw Start address of the peripheral registers.
289  */
rwdt_ll_clear_intr_status(rtc_cntl_dev_t * hw)290 FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t *hw)
291 {
292     hw->int_clr.rtc_wdt = 1;
293 }
294 
295 #ifdef __cplusplus
296 }
297 #endif
298