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