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