1 /*
2  * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_private/esp_clk_tree_common.h"
8 #include "hal/clk_tree_hal.h"
9 #include "hal/clk_tree_ll.h"
10 #include "soc/rtc.h"
11 #include "esp_private/esp_clk.h"
12 #include "soc/clk_tree_defs.h"
13 #include "soc/soc_caps.h"
14 #include "sdkconfig.h"
15 #include "esp_hw_log.h"
16 
17 static const char *TAG = "esp_clk_tree_common";
18 
19 typedef struct esp_clk_tree_calibrated_freq_t esp_clk_tree_calibrated_freq_t;
20 
21 struct esp_clk_tree_calibrated_freq_t {
22 #if SOC_CLK_RC_FAST_D256_SUPPORTED
23     uint32_t rc_fast_d256;
24 #elif SOC_CLK_RC_FAST_SUPPORT_CALIBRATION // && !SOC_CLK_RC_FAST_D256_SUPPORTED
25     uint32_t rc_fast;
26 #endif
27 #if SOC_CLK_XTAL32K_SUPPORTED
28     uint32_t xtal32k;
29 #endif
30 #if SOC_CLK_OSC_SLOW_SUPPORTED
31     uint32_t osc_slow;
32 #endif
33 };
34 
35 // TODO: Better to implement a spinlock for the static variables
36 static esp_clk_tree_calibrated_freq_t s_calibrated_freq = {};
37 
38 /* Number of cycles for RTC_SLOW_CLK calibration */
39 #define RTC_SLOW_CLK_CAL_CYCLES     CONFIG_RTC_CLK_CAL_CYCLES
40 /* Number of cycles for ~32kHz clocks calibration (rc_fast_d256, xtal32k, osc_slow, rc32k) */
41 #define DEFAULT_32K_CLK_CAL_CYCLES  100
42 /* Number of cycles for RC_FAST calibration */
43 #define DEFAULT_RC_FAST_CAL_CYCLES  10000  // RC_FAST has a higher frequency, therefore, requires more cycles to get an accurate value
44 
45 
46 /**
47  * Performs a frequency calibration to RTC slow clock
48  *
49  * slowclk_cycles Number of slow clock cycles to count.
50  *                If slowclk_cycles = 0, calibration will not be performed. Clock's theoretical value will be used.
51  *
52  * Returns the number of XTAL clock cycles within the given number of slow clock cycles
53  * It returns 0 if calibration failed, i.e. clock is not running
54  */
clk_tree_rtc_slow_calibration(uint32_t slowclk_cycles)55 static uint32_t clk_tree_rtc_slow_calibration(uint32_t slowclk_cycles)
56 {
57     uint32_t cal_val = 0;
58     if (slowclk_cycles > 0) {
59         cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, slowclk_cycles);
60     } else {
61         const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
62         uint32_t source_approx_freq = clk_hal_lp_slow_get_freq_hz();
63         assert(source_approx_freq);
64         cal_val = (uint32_t)(cal_dividend / source_approx_freq);
65     }
66     if (cal_val) {
67         ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val);
68         // Update the calibration value of RTC_SLOW_CLK
69         esp_clk_slowclk_cal_set(cal_val);
70     }
71     return cal_val;
72 }
73 
74 #if SOC_CLK_RC_FAST_D256_SUPPORTED
esp_clk_tree_rc_fast_d256_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)75 uint32_t esp_clk_tree_rc_fast_d256_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
76 {
77     switch (precision) {
78     case ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX:
79         return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
80     case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
81         if (!s_calibrated_freq.rc_fast_d256) {
82             s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, DEFAULT_32K_CLK_CAL_CYCLES));
83         }
84         return s_calibrated_freq.rc_fast_d256;
85     case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
86         s_calibrated_freq.rc_fast_d256 = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, DEFAULT_32K_CLK_CAL_CYCLES));
87         return s_calibrated_freq.rc_fast_d256;
88     default:
89         return 0;
90     }
91 }
92 #endif
93 
94 #if SOC_CLK_XTAL32K_SUPPORTED
esp_clk_tree_xtal32k_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)95 uint32_t esp_clk_tree_xtal32k_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
96 {
97     switch (precision) {
98     case ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX:
99         return SOC_CLK_XTAL32K_FREQ_APPROX;
100     case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
101         if (!s_calibrated_freq.xtal32k) {
102             s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
103         }
104         return s_calibrated_freq.xtal32k;
105     case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
106         s_calibrated_freq.xtal32k = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_XTAL, DEFAULT_32K_CLK_CAL_CYCLES));
107         return s_calibrated_freq.xtal32k;
108     default:
109         return 0;
110     }
111 }
112 #endif
113 
114 #if SOC_CLK_OSC_SLOW_SUPPORTED
esp_clk_tree_osc_slow_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)115 uint32_t esp_clk_tree_osc_slow_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
116 {
117     switch (precision) {
118     case ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX:
119         return SOC_CLK_OSC_SLOW_FREQ_APPROX;
120     case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
121         if (!s_calibrated_freq.osc_slow) {
122             s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
123         }
124         return s_calibrated_freq.osc_slow;
125     case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
126         s_calibrated_freq.osc_slow = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_32K_OSC_SLOW, DEFAULT_32K_CLK_CAL_CYCLES));
127         return s_calibrated_freq.osc_slow;
128     default:
129         return 0;
130     }
131 }
132 #endif
133 
esp_clk_tree_lp_slow_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)134 uint32_t esp_clk_tree_lp_slow_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
135 {
136     switch (precision) {
137     case ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED:
138         // This returns calibrated (if CONFIG_xxx_RTC_CLK_CAL_CYCLES) value stored in RTC storage register
139         return rtc_clk_freq_cal(clk_ll_rtc_slow_load_cal());
140     case ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX:
141         return clk_hal_lp_slow_get_freq_hz();
142     case ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT:
143         return rtc_clk_freq_cal(clk_tree_rtc_slow_calibration(RTC_SLOW_CLK_CAL_CYCLES));
144     default:
145         return 0;
146     }
147 }
148 
esp_clk_tree_rc_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)149 uint32_t esp_clk_tree_rc_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
150 {
151 #if SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
152     if (precision == ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX) {
153         return SOC_CLK_RC_FAST_FREQ_APPROX;
154     }
155 #if SOC_CLK_RC_FAST_D256_SUPPORTED
156     // If RC_FAST_D256 clock exists, calibration on a slow freq clock is much faster (less slow clock cycles need to wait)
157     return esp_clk_tree_rc_fast_d256_get_freq_hz(precision) << 8;
158 #else
159     // Calibrate directly on the RC_FAST clock requires much more slow clock cycles to get an accurate freq value
160     if (precision != ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED || !s_calibrated_freq.rc_fast) {
161         s_calibrated_freq.rc_fast = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_RC_FAST, DEFAULT_RC_FAST_CAL_CYCLES));
162     }
163     return s_calibrated_freq.rc_fast;
164 #endif //SOC_CLK_RC_FAST_D256_SUPPORTED
165 #else //!SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
166     if (precision != ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX) {
167         // No way of getting exact rc_fast freq
168         ESP_HW_LOGW(TAG, "unable to get the exact freq of rc_fast_clk, returning its approx. freq value");
169     }
170     return SOC_CLK_RC_FAST_FREQ_APPROX;
171 #endif //SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
172 }
173 
esp_clk_tree_lp_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)174 uint32_t esp_clk_tree_lp_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t precision)
175 {
176     switch (clk_ll_rtc_fast_get_src()) {
177     case SOC_RTC_FAST_CLK_SRC_XTAL_DIV:
178 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 //SOC_RTC_FAST_CLK_SRC_XTAL_D4
179         return clk_hal_xtal_get_freq_mhz() * MHZ >> 2;
180 #else //SOC_RTC_FAST_CLK_SRC_XTAL_D2
181         return clk_hal_xtal_get_freq_mhz() * MHZ >> 1;
182 #endif
183     case SOC_RTC_FAST_CLK_SRC_RC_FAST:
184         return esp_clk_tree_rc_fast_get_freq_hz(precision) / clk_ll_rc_fast_get_divider();
185 #if SOC_CLK_LP_FAST_SUPPORT_LP_PLL
186     case SOC_RTC_FAST_CLK_SRC_LP_PLL:
187         return clk_ll_lp_pll_get_freq_mhz() * MHZ;
188 #endif
189     default:
190         // Invalid clock source
191         assert(false);
192         return 0;
193     }
194 }
195