1 /*
2 * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stddef.h>
10 #include <assert.h>
11 #include <stdlib.h>
12 #include "sdkconfig.h"
13 #include "esp32h2/rom/rtc.h"
14 #include "soc/rtc.h"
15 #include "esp_private/rtc_clk.h"
16 #include "esp_hw_log.h"
17 #include "esp_rom_sys.h"
18 #include "hal/clk_tree_ll.h"
19 #include "hal/regi2c_ctrl_ll.h"
20 #include "soc/io_mux_reg.h"
21 #include "soc/lp_aon_reg.h"
22 #include "soc/lp_clkrst_reg.h"
23 #include "esp_private/sleep_event.h"
24
25 #ifdef BOOTLOADER_BUILD
26 #include "hal/modem_lpcon_ll.h"
27 #else
28 #include "esp_private/esp_modem_clock.h"
29 #endif
30
31 static const char *TAG = "rtc_clk";
32
33 // Current PLL frequency, in 96MHz. Zero if PLL is not enabled.
34 static int s_cur_pll_freq;
35
36 static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it only tracks whether the 48MHz PHY clock is in-use by USB Serial/JTAG
37
rtc_clk_bbpll_add_consumer(void)38 void rtc_clk_bbpll_add_consumer(void)
39 {
40 s_bbpll_digi_consumers_ref_count += 1;
41 }
42
rtc_clk_bbpll_remove_consumer(void)43 void rtc_clk_bbpll_remove_consumer(void)
44 {
45 s_bbpll_digi_consumers_ref_count -= 1;
46 }
47
rtc_clk_32k_enable(bool enable)48 void rtc_clk_32k_enable(bool enable)
49 {
50 if (enable) {
51 clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
52 } else {
53 clk_ll_xtal32k_disable();
54 }
55 }
56
rtc_clk_32k_enable_external(void)57 void rtc_clk_32k_enable_external(void)
58 {
59 // EXT_OSC_SLOW_GPIO_NUM == GPIO_NUM_13
60 PIN_INPUT_ENABLE(IO_MUX_GPIO13_REG);
61 REG_SET_BIT(LP_AON_GPIO_HOLD0_REG, BIT(EXT_OSC_SLOW_GPIO_NUM));
62 clk_ll_xtal32k_enable(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
63 }
64
rtc_clk_32k_bootstrap(uint32_t cycle)65 void rtc_clk_32k_bootstrap(uint32_t cycle)
66 {
67 /* No special bootstrapping needed for ESP32-H2, 'cycle' argument is to keep the signature
68 * same as for the ESP32. Just enable the XTAL here.
69 */
70 (void)cycle;
71 rtc_clk_32k_enable(true);
72 }
73
rtc_clk_32k_enabled(void)74 bool rtc_clk_32k_enabled(void)
75 {
76 return clk_ll_xtal32k_is_enabled();
77 }
78
rtc_clk_rc32k_enable(bool enable)79 void rtc_clk_rc32k_enable(bool enable)
80 {
81 if (enable) {
82 clk_ll_rc32k_enable();
83 esp_rom_delay_us(SOC_DELAY_RC32K_ENABLE);
84 } else {
85 clk_ll_rc32k_disable();
86 }
87 }
88
rtc_clk_8m_enable(bool clk_8m_en)89 void rtc_clk_8m_enable(bool clk_8m_en)
90 {
91 if (clk_8m_en) {
92 clk_ll_rc_fast_enable();
93 esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
94 } else {
95 clk_ll_rc_fast_disable();
96 }
97 }
98
rtc_clk_8m_enabled(void)99 bool rtc_clk_8m_enabled(void)
100 {
101 return clk_ll_rc_fast_is_enabled();
102 }
103
rtc_clk_lp_pll_enable(bool enable)104 void rtc_clk_lp_pll_enable(bool enable)
105 {
106 if (enable) {
107 clk_ll_lp_pll_enable();
108 esp_rom_delay_us(SOC_DELAY_LP_PLL_ENABLE);
109 } else {
110 clk_ll_lp_pll_disable();
111 }
112 }
113
rtc_clk_lp_pll_src_set(soc_lp_pll_clk_src_t clk_src)114 void rtc_clk_lp_pll_src_set(soc_lp_pll_clk_src_t clk_src)
115 {
116 clk_ll_lp_pll_set_src(clk_src);
117 esp_rom_delay_us(SOC_DELAY_LP_PLL_SWITCH);
118 }
119
rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)120 void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
121 {
122 clk_ll_rtc_slow_set_src(clk_src);
123 esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
124 }
125
rtc_clk_slow_src_get(void)126 soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
127 {
128 return clk_ll_rtc_slow_get_src();
129 }
130
rtc_clk_slow_freq_get_hz(void)131 uint32_t rtc_clk_slow_freq_get_hz(void)
132 {
133 switch (rtc_clk_slow_src_get()) {
134 case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
135 case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
136 case SOC_RTC_SLOW_CLK_SRC_RC32K: return SOC_CLK_RC32K_FREQ_APPROX;
137 case SOC_RTC_SLOW_CLK_SRC_OSC_SLOW: return SOC_CLK_OSC_SLOW_FREQ_APPROX;
138 default: return 0;
139 }
140 }
141
rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)142 void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
143 {
144 clk_ll_rtc_fast_set_src(clk_src);
145 esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
146 }
147
rtc_clk_fast_src_get(void)148 soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
149 {
150 return clk_ll_rtc_fast_get_src();
151 }
152
rtc_clk_bbpll_disable(void)153 static void rtc_clk_bbpll_disable(void)
154 {
155 clk_ll_bbpll_disable();
156 s_cur_pll_freq = 0;
157 }
158
rtc_clk_bbpll_enable(void)159 static void rtc_clk_bbpll_enable(void)
160 {
161 clk_ll_bbpll_enable();
162 }
163
rtc_clk_enable_i2c_ana_master_clock(bool enable)164 static void rtc_clk_enable_i2c_ana_master_clock(bool enable)
165 {
166 #ifdef BOOTLOADER_BUILD
167 modem_lpcon_ll_enable_i2c_master_clock(&MODEM_LPCON, enable);
168 #else
169 if (enable) {
170 modem_clock_module_enable(PERIPH_ANA_I2C_MASTER_MODULE);
171 } else {
172 modem_clock_module_disable(PERIPH_ANA_I2C_MASTER_MODULE);
173 }
174 #endif
175 }
176
rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq,int pll_freq)177 static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
178 {
179 /* Digital part */
180 clk_ll_bbpll_set_freq_mhz(pll_freq);
181 /* Analog part */
182 rtc_clk_enable_i2c_ana_master_clock(true);
183 /* BBPLL CALIBRATION START */
184 regi2c_ctrl_ll_bbpll_calibration_start();
185 clk_ll_bbpll_set_config(pll_freq, xtal_freq);
186 /* WAIT CALIBRATION DONE */
187 while(!regi2c_ctrl_ll_bbpll_calibration_is_done());
188 esp_rom_delay_us(10);
189 /* BBPLL CALIBRATION STOP */
190 regi2c_ctrl_ll_bbpll_calibration_stop();
191 rtc_clk_enable_i2c_ana_master_clock(false);
192 s_cur_pll_freq = pll_freq;
193 }
194
195 /**
196 * Switch to use XTAL as the CPU clock source.
197 * Must satisfy: cpu_freq = XTAL_FREQ / div.
198 * Does not disable the PLL.
199 */
rtc_clk_cpu_freq_to_xtal(int cpu_freq,int div)200 static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div)
201 {
202 // let f_cpu = f_ahb
203 clk_ll_cpu_set_divider(div);
204 clk_ll_ahb_set_divider(div);
205 clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
206 clk_ll_bus_update();
207 esp_rom_set_cpu_ticks_per_us(cpu_freq);
208 }
209
rtc_clk_cpu_freq_to_8m(void)210 static void rtc_clk_cpu_freq_to_8m(void)
211 {
212 // let f_cpu = f_ahb
213 clk_ll_cpu_set_divider(1);
214 clk_ll_ahb_set_divider(1);
215 clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
216 clk_ll_bus_update();
217 esp_rom_set_cpu_ticks_per_us(8);
218 }
219
220 /**
221 * Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
222 * PLL must already be enabled.
223 * @param cpu_freq new CPU frequency
224 */
rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)225 static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
226 {
227 // f_hp_root = 96MHz
228 uint32_t cpu_divider = CLK_LL_PLL_96M_FREQ_MHZ / cpu_freq_mhz;
229 clk_ll_cpu_set_divider(cpu_divider);
230 // Constraint: f_ahb <= 32MHz; f_cpu = N * f_ahb (N = 1, 2, 3...)
231 uint32_t ahb_divider = (cpu_divider == 1) ? 3 :
232 (cpu_divider == 2) ? 4 : cpu_divider;
233 clk_ll_ahb_set_divider(ahb_divider);
234 clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
235 clk_ll_bus_update();
236 esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
237 }
238
239 /**
240 * Switch to FLASH_PLL as cpu clock source.
241 * On ESP32H2, FLASH_PLL frequency is 64MHz.
242 * PLL must already be enabled.
243 */
rtc_clk_cpu_freq_to_flash_pll(uint32_t cpu_freq_mhz,uint32_t cpu_divider)244 static void rtc_clk_cpu_freq_to_flash_pll(uint32_t cpu_freq_mhz, uint32_t cpu_divider)
245 {
246 // f_hp_root = 64MHz
247 clk_ll_cpu_set_divider(cpu_divider);
248 // Constraint: f_ahb <= 32MHz; f_cpu = N * f_ahb (N = 1, 2, 3...)
249 uint32_t ahb_divider = (cpu_divider == 1) ? 2 : cpu_divider;
250 clk_ll_ahb_set_divider(ahb_divider);
251 clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_FLASH_PLL);
252 clk_ll_bus_update();
253 esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
254 }
255
rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz,rtc_cpu_freq_config_t * out_config)256 bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t *out_config)
257 {
258 uint32_t source_freq_mhz;
259 soc_cpu_clk_src_t source;
260 uint32_t divider; // divider = freq of SOC_ROOT_CLK / freq of CPU_CLK
261 uint32_t real_freq_mhz;
262
263 uint32_t xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
264 if (freq_mhz <= xtal_freq && freq_mhz != 0) {
265 divider = xtal_freq / freq_mhz;
266 real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
267 if (real_freq_mhz != freq_mhz) {
268 // no suitable divider
269 return false;
270 }
271
272 source_freq_mhz = xtal_freq;
273 source = SOC_CPU_CLK_SRC_XTAL;
274 } else if (freq_mhz == 96) {
275 real_freq_mhz = freq_mhz;
276 source = SOC_CPU_CLK_SRC_PLL;
277 source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
278 divider = 1;
279 } else if (freq_mhz == 64) {
280 real_freq_mhz = freq_mhz;
281 source = SOC_CPU_CLK_SRC_FLASH_PLL;
282 source_freq_mhz = CLK_LL_PLL_64M_FREQ_MHZ;
283 divider = 1;
284 } else if (freq_mhz == 48) {
285 real_freq_mhz = freq_mhz;
286 source = SOC_CPU_CLK_SRC_PLL;
287 source_freq_mhz = CLK_LL_PLL_96M_FREQ_MHZ;
288 divider = 2;
289 } else {
290 // unsupported frequency
291 return false;
292 }
293 *out_config = (rtc_cpu_freq_config_t) {
294 .source = source,
295 .div = divider,
296 .source_freq_mhz = source_freq_mhz,
297 .freq_mhz = real_freq_mhz
298 };
299 return true;
300 }
301
rtc_clk_set_cpu_switch_to_bbpll(int event_id)302 __attribute__((weak)) void rtc_clk_set_cpu_switch_to_bbpll(int event_id)
303 {
304 }
305
rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t * config)306 void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config)
307 {
308 soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
309 if (config->source == SOC_CPU_CLK_SRC_XTAL) {
310 rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
311 if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL || old_cpu_clk_src == SOC_CPU_CLK_SRC_FLASH_PLL) &&
312 !s_bbpll_digi_consumers_ref_count) {
313 rtc_clk_bbpll_disable();
314 }
315 } else if (config->source == SOC_CPU_CLK_SRC_PLL) {
316 if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL && old_cpu_clk_src != SOC_CPU_CLK_SRC_FLASH_PLL) {
317 rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_EN_START);
318 rtc_clk_bbpll_enable();
319 rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
320 }
321 rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
322 rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_BBPLL_EN_STOP);
323 } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
324 rtc_clk_cpu_freq_to_8m();
325 if ((old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL || old_cpu_clk_src == SOC_CPU_CLK_SRC_FLASH_PLL) &&
326 !s_bbpll_digi_consumers_ref_count) {
327 rtc_clk_bbpll_disable();
328 }
329 } else if (config->source == SOC_CPU_CLK_SRC_FLASH_PLL) {
330 if (old_cpu_clk_src != SOC_CPU_CLK_SRC_PLL && old_cpu_clk_src != SOC_CPU_CLK_SRC_FLASH_PLL) {
331 // On ESP32H2, FLASH_PLL (64MHz) is directly derived from the BBPLL (96MHz)
332 // Therefore, enabling and configuration are applied to BBPLL.
333 rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_FLASH_BBPLL_EN_START);
334 rtc_clk_bbpll_enable();
335 rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_96M_FREQ_MHZ);
336 }
337 rtc_clk_cpu_freq_to_flash_pll(config->freq_mhz, config->div);
338 rtc_clk_set_cpu_switch_to_bbpll(SLEEP_EVENT_HW_FLASH_BBPLL_EN_STOP);
339 }
340 }
341
rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t * out_config)342 void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config)
343 {
344 soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
345 uint32_t source_freq_mhz;
346 uint32_t div = clk_ll_cpu_get_divider(); // div = freq of SOC_ROOT_CLK / freq of CPU_CLK
347 uint32_t freq_mhz;
348 switch (source) {
349 case SOC_CPU_CLK_SRC_XTAL: {
350 source_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
351 freq_mhz = source_freq_mhz / div;
352 break;
353 }
354 case SOC_CPU_CLK_SRC_PLL: {
355 source_freq_mhz = clk_ll_bbpll_get_freq_mhz();
356 freq_mhz = source_freq_mhz / div;
357 break;
358 }
359 case SOC_CPU_CLK_SRC_RC_FAST:
360 source_freq_mhz = 8;
361 freq_mhz = source_freq_mhz / div;
362 break;
363 case SOC_CPU_CLK_SRC_FLASH_PLL:
364 source_freq_mhz = clk_ll_flash_pll_get_freq_mhz();
365 freq_mhz = source_freq_mhz / div;
366 break;
367 default:
368 ESP_HW_LOGE(TAG, "unsupported frequency configuration");
369 abort();
370 }
371 *out_config = (rtc_cpu_freq_config_t) {
372 .source = source,
373 .source_freq_mhz = source_freq_mhz,
374 .div = div,
375 .freq_mhz = freq_mhz
376 };
377 }
378
rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t * config)379 void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
380 {
381 if (config->source == SOC_CPU_CLK_SRC_XTAL) {
382 rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
383 } else if (config->source == SOC_CPU_CLK_SRC_PLL &&
384 s_cur_pll_freq == config->source_freq_mhz) {
385 rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
386 } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
387 rtc_clk_cpu_freq_to_8m();
388 } else if (config->source == SOC_CPU_CLK_SRC_FLASH_PLL &&
389 s_cur_pll_freq == clk_ll_bbpll_get_freq_mhz()) {
390 // On ESP32H2, FLASH_PLL (64MHz) is directly derived from the BBPLL (96MHz)
391 // Therefore, as long as bbpll was not disabled, no need to re-enable and re-configure parameters for the source clock
392 rtc_clk_cpu_freq_to_flash_pll(config->freq_mhz, config->div);
393 } else {
394 /* fallback */
395 rtc_clk_cpu_freq_set_config(config);
396 }
397 }
398
rtc_clk_cpu_freq_set_xtal(void)399 void rtc_clk_cpu_freq_set_xtal(void)
400 {
401 rtc_clk_cpu_set_to_default_config();
402 rtc_clk_bbpll_disable();
403 }
404
rtc_clk_cpu_set_to_default_config(void)405 void rtc_clk_cpu_set_to_default_config(void)
406 {
407 int freq_mhz = (int)rtc_clk_xtal_freq_get();
408
409 rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
410 s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
411 }
412
rtc_clk_xtal_freq_get(void)413 rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
414 {
415 uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
416 if (xtal_freq_mhz == 0) {
417 ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 32MHz");
418 return RTC_XTAL_FREQ_32M;
419 }
420 return (rtc_xtal_freq_t)xtal_freq_mhz;
421 }
422
rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)423 void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
424 {
425 clk_ll_xtal_store_freq_mhz(xtal_freq);
426 }
427
rtc_clk_ahb_freq_get(void)428 static uint32_t rtc_clk_ahb_freq_get(void)
429 {
430 soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
431 uint32_t soc_root_freq_mhz;
432 uint32_t divider = clk_ll_ahb_get_divider();
433 switch (source) {
434 case SOC_CPU_CLK_SRC_XTAL:
435 soc_root_freq_mhz = rtc_clk_xtal_freq_get();
436 break;
437 case SOC_CPU_CLK_SRC_PLL:
438 soc_root_freq_mhz = clk_ll_bbpll_get_freq_mhz();
439 break;
440 case SOC_CPU_CLK_SRC_RC_FAST:
441 soc_root_freq_mhz = 8;
442 break;
443 case SOC_CPU_CLK_SRC_FLASH_PLL:
444 soc_root_freq_mhz = clk_ll_flash_pll_get_freq_mhz();
445 break;
446 default:
447 // Unknown SOC_ROOT clock source
448 soc_root_freq_mhz = 0;
449 ESP_HW_LOGE(TAG, "Invalid SOC_ROOT_CLK");
450 break;
451 }
452 return soc_root_freq_mhz / divider;
453 }
454
rtc_clk_apb_freq_get(void)455 uint32_t rtc_clk_apb_freq_get(void)
456 {
457 return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ;
458 }
459
rtc_dig_clk8m_enable(void)460 void rtc_dig_clk8m_enable(void)
461 {
462 clk_ll_rc_fast_digi_enable();
463 esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
464 }
465
rtc_dig_clk8m_disable(void)466 void rtc_dig_clk8m_disable(void)
467 {
468 clk_ll_rc_fast_digi_disable();
469 esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
470 }
471
rtc_dig_8m_enabled(void)472 bool rtc_dig_8m_enabled(void)
473 {
474 return clk_ll_rc_fast_digi_is_enabled();
475 }
476