1 /*
2  * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_xt_wdt.h"
8 #include "sdkconfig.h"
9 #include "soc/soc_caps.h"
10 
11 #include "esp_log.h"
12 #include "esp_check.h"
13 #include "esp_attr.h"
14 #include "esp_intr_alloc.h"
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/semphr.h"
17 
18 #if SOC_XT_WDT_SUPPORTED
19 
20 #include "esp_private/rtc_ctrl.h"
21 #include "hal/xt_wdt_hal.h"
22 #include "hal/xt_wdt_ll.h"
23 #include "soc/rtc.h"
24 
25 #define RTC_CLK_CAL_CYCLES 500
26 
27 const static char *TAG = "esp_xt_wdt";
28 
29 static xt_wdt_hal_context_t s_hal_ctx;
30 
31 static esp_xt_callback_t s_callback_func;
32 static void *s_callback_arg;
33 
34 static portMUX_TYPE s_xt_wdt_lock = portMUX_INITIALIZER_UNLOCKED;
35 
rtc_xt_wdt_default_isr_handler(void * arg)36 static IRAM_ATTR void rtc_xt_wdt_default_isr_handler(void *arg)
37 {
38     ESP_EARLY_LOGE(TAG, "XTAL32K watchdog timer got triggered");
39 
40     portENTER_CRITICAL_ISR(&s_xt_wdt_lock);
41     if (s_callback_func) {
42         (*s_callback_func)(s_callback_arg);
43     }
44     portEXIT_CRITICAL_ISR(&s_xt_wdt_lock);
45 }
46 
esp_xt_wdt_init(const esp_xt_wdt_config_t * cfg)47 esp_err_t esp_xt_wdt_init(const esp_xt_wdt_config_t *cfg)
48 {
49     esp_err_t ret = ESP_OK;
50 
51     xt_wdt_hal_config_t hal_config = {
52         .timeout = cfg->timeout,
53     };
54 
55     xt_wdt_hal_init(&s_hal_ctx, &hal_config);
56 
57     if (cfg->auto_backup_clk_enable) {
58         /* Estimate frequency of internal RTC oscillator */
59         uint32_t rtc_clk_frequency_khz = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_INTERNAL_OSC, RTC_CLK_CAL_CYCLES)) / 1000;
60         ESP_LOGD(TAG, "Calibrating backup clock from rtc clock with frequency %"PRIu32, rtc_clk_frequency_khz);
61 
62         xt_wdt_hal_enable_backup_clk(&s_hal_ctx, rtc_clk_frequency_khz);
63     }
64 
65     ESP_GOTO_ON_ERROR(rtc_isr_register(rtc_xt_wdt_default_isr_handler, NULL, XT_WDT_LL_XTAL32_DEAD_INTR_MASK, 0), err, TAG, "Failed to register isr");
66 
67     xt_wdt_hal_enable(&s_hal_ctx, 1);
68 
69     return ESP_OK;
70 err:
71     return ret;
72 }
73 
esp_xt_wdt_restore_clk(void)74 void esp_xt_wdt_restore_clk(void)
75 {
76     xt_wdt_hal_enable(&s_hal_ctx, false);
77 
78     REG_CLR_BIT(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
79     REG_SET_BIT(RTC_CNTL_EXT_XTL_CONF_REG, RTC_CNTL_XPD_XTAL_32K);
80 
81     /* Needs some time after switching to 32khz XTAL before turning on WDT again */
82     esp_rom_delay_us(300);
83 
84     xt_wdt_hal_enable(&s_hal_ctx, true);
85 }
86 
esp_xt_wdt_register_callback(esp_xt_callback_t func,void * arg)87 void esp_xt_wdt_register_callback(esp_xt_callback_t func, void *arg)
88 {
89     portENTER_CRITICAL(&s_xt_wdt_lock);
90     s_callback_func = func;
91     s_callback_arg = arg;
92     portEXIT_CRITICAL(&s_xt_wdt_lock);
93 }
94 
95 #endif //SOC_XT_WDT_SUPPORTED
96