1 /*
2  * SPDX-FileCopyrightText: 2015-2022 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 <stdlib.h>
11 #include "soc/rtc.h"
12 #include "esp_private/rtc_clk.h"
13 #include "soc/rtc_periph.h"
14 #include "soc/sens_periph.h"
15 #include "soc/soc_caps.h"
16 #include "soc/chip_revision.h"
17 #include "hal/efuse_ll.h"
18 #include "hal/efuse_hal.h"
19 #include "soc/gpio_struct.h"
20 #include "hal/gpio_ll.h"
21 #include "esp_hw_log.h"
22 #include "sdkconfig.h"
23 #include "esp_rom_sys.h"
24 #include "esp_rom_gpio.h"
25 #include "esp32/rom/rtc.h"
26 #include "hal/clk_tree_ll.h"
27 #include "soc/rtc_cntl_reg.h"
28 #include "soc/io_mux_reg.h"
29 
30 #define XTAL_32K_BOOTSTRAP_TIME_US      7
31 
32 static void rtc_clk_cpu_freq_to_8m(void);
33 static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz);
34 
35 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
36 static uint32_t s_cur_pll_freq;
37 
38 static const char* TAG = "rtc_clk";
39 
rtc_clk_32k_enable_common(clk_ll_xtal32k_enable_mode_t mode)40 static void rtc_clk_32k_enable_common(clk_ll_xtal32k_enable_mode_t mode)
41 {
42     CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
43                         RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE |
44                         RTC_IO_X32N_RDE | RTC_IO_X32N_FUN_IE | RTC_IO_X32P_FUN_IE);
45     SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
46 
47 #ifdef CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT
48     // version0 and version1 need provide additional current to external XTAL.
49     if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 200)) {
50         /* TOUCH sensor can provide additional current to external XTAL.
51         In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */
52         SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M);
53         /* Tie PAD Touch8 to VDD
54         NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead*/
55         SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M);
56         /* Set the current used to compensate TOUCH PAD8 */
57         SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 4, RTC_IO_TOUCH_PAD8_DAC_S);
58         /* Power up TOUCH8
59         So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N)*/
60         SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
61     }
62 #elif defined CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_V2
63     if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 200)) {
64         /* TOUCH sensor can provide additional current to external XTAL.
65         In some case, X32N and X32P PAD don't have enough drive capability to start XTAL */
66         SET_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M);
67         SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_DCUR, 3, RTC_IO_TOUCH_DCUR_S);
68         CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FSM_EN_M);
69         /* Tie PAD Touch8 to VDD
70         NOTE: TOUCH8 and TOUCH9 register settings are reversed except for DAC, so we set RTC_IO_TOUCH_PAD9_REG here instead
71         */
72         SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_TIE_OPT_M);
73         /* Set the current used to compensate TOUCH PAD8 */
74         SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD8_REG, RTC_IO_TOUCH_PAD8_DAC, 1, RTC_IO_TOUCH_PAD8_DAC_S);
75         /* Power up TOUCH8
76         So the Touch DAC start to drive some current from VDD to TOUCH8(which is also XTAL-N)
77         */
78         SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
79         CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_START_M);
80     }
81 #endif
82 
83     clk_ll_xtal32k_enable(mode);
84 }
85 
rtc_clk_32k_enable(bool enable)86 void rtc_clk_32k_enable(bool enable)
87 {
88     if (enable) {
89         rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_CRYSTAL);
90     } else {
91         clk_ll_xtal32k_disable();
92         /* Disable X32N and X32P pad drive external xtal */
93         CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
94 
95 #ifdef CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT
96         if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 200)) {
97             /* Power down TOUCH */
98             CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
99         }
100 #elif defined CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT_V2
101         if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 200)) {
102             /* Power down TOUCH */
103             CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS_M);
104             SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_DCUR, 0, RTC_IO_TOUCH_DCUR_S);
105             CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD9_REG, RTC_IO_TOUCH_PAD9_XPD_M);
106             SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FSM_EN_M);
107         }
108 #endif
109     }
110 }
111 
rtc_clk_32k_enable_external(void)112 void rtc_clk_32k_enable_external(void)
113 {
114     rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_EXTERNAL);
115 }
116 
117 /* Helping external 32kHz crystal to start up.
118  * External crystal connected to outputs GPIO32 GPIO33.
119  * Forms N pulses with a frequency of about 32KHz on the outputs of the crystal.
120  */
rtc_clk_32k_bootstrap(uint32_t cycle)121 void rtc_clk_32k_bootstrap(uint32_t cycle)
122 {
123     if (cycle){
124         esp_rom_gpio_pad_select_gpio(XTAL32K_P_GPIO_NUM);
125         esp_rom_gpio_pad_select_gpio(XTAL32K_N_GPIO_NUM);
126         gpio_ll_output_enable(&GPIO, XTAL32K_P_GPIO_NUM);
127         gpio_ll_output_enable(&GPIO, XTAL32K_N_GPIO_NUM);
128         gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 1);
129         gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 0);
130 
131         const uint32_t delay_us = (1000000 / SOC_CLK_XTAL32K_FREQ_APPROX / 2);
132         while (cycle) {
133             gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 1);
134             gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 0);
135             esp_rom_delay_us(delay_us);
136             gpio_ll_set_level(&GPIO, XTAL32K_N_GPIO_NUM, 1);
137             gpio_ll_set_level(&GPIO, XTAL32K_P_GPIO_NUM, 0);
138             esp_rom_delay_us(delay_us);
139             cycle--;
140         }
141         // disable pins
142         gpio_ll_output_disable(&GPIO, XTAL32K_P_GPIO_NUM);
143         gpio_ll_output_disable(&GPIO, XTAL32K_N_GPIO_NUM);
144     }
145 
146     clk_ll_xtal32k_disable();
147     SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE);
148     esp_rom_delay_us(XTAL_32K_BOOTSTRAP_TIME_US);
149 
150     rtc_clk_32k_enable_common(CLK_LL_XTAL32K_ENABLE_MODE_BOOTSTRAP);
151 }
152 
rtc_clk_32k_enabled(void)153 bool rtc_clk_32k_enabled(void)
154 {
155     return clk_ll_xtal32k_is_enabled();
156 }
157 
rtc_clk_8m_enable(bool clk_8m_en,bool d256_en)158 void rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
159 {
160     if (clk_8m_en) {
161         clk_ll_rc_fast_enable();
162         if (d256_en) {
163             clk_ll_rc_fast_d256_enable();
164         } else {
165             clk_ll_rc_fast_d256_disable();
166         }
167         esp_rom_delay_us(SOC_DELAY_RC_FAST_ENABLE);
168     } else {
169         clk_ll_rc_fast_disable();
170     }
171 }
172 
rtc_clk_8m_enabled(void)173 bool rtc_clk_8m_enabled(void)
174 {
175     return clk_ll_rc_fast_is_enabled();
176 }
177 
rtc_clk_8md256_enabled(void)178 bool rtc_clk_8md256_enabled(void)
179 {
180     return clk_ll_rc_fast_d256_is_enabled();
181 }
182 
rtc_clk_apll_enable(bool enable)183 void rtc_clk_apll_enable(bool enable)
184 {
185     if (enable) {
186         clk_ll_apll_enable();
187     } else {
188         clk_ll_apll_disable();
189     }
190 
191     if (!enable && (clk_ll_cpu_get_src() != SOC_CPU_CLK_SRC_PLL)) {
192         // if apll and bbpll are both not in use, then can also power down the internal I2C bus
193         // this power down affects most of the analog peripherals
194         clk_ll_i2c_pd();
195     } else {
196         clk_ll_i2c_pu();
197     }
198 }
199 
rtc_clk_apll_coeff_calc(uint32_t freq,uint32_t * _o_div,uint32_t * _sdm0,uint32_t * _sdm1,uint32_t * _sdm2)200 uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
201 {
202     uint32_t xtal_freq_mhz = (uint32_t)rtc_clk_xtal_freq_get();
203     if (xtal_freq_mhz == 0) {
204         // xtal_freq has not set yet
205         ESP_HW_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet");
206         abort();
207     }
208     /* Reference formula: apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) / ((o_div + 2) * 2)
209      *                                ----------------------------------------------   -----------------
210      *                                     350 MHz <= Numerator <= 500 MHz                Denominator
211      */
212     int o_div = 0; // range: 0~31
213     int sdm0 = 0;  // range: 0~255
214     int sdm1 = 0;  // range: 0~255
215     int sdm2 = 0;  // range: 0~63
216     /* Firstly try to satisfy the condition that the operation frequency of numerator should be greater than 350 MHz,
217      * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
218      * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
219      * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
220     o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
221     if (o_div > 31) {
222         ESP_HW_LOGE(TAG, "Expected frequency is too small");
223         return 0;
224     }
225     if (o_div < 0) {
226         /* Try to satisfy the condition that the operation frequency of numerator should be smaller than 500 MHz,
227          * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
228          * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
229          * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
230         o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
231         if (o_div < 0) {
232             ESP_HW_LOGE(TAG, "Expected frequency is too big");
233             return 0;
234         }
235     }
236     // sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
237     sdm2 = (int)(((o_div + 2) * 2 * freq) / (xtal_freq_mhz * MHZ)) - 4;
238     // numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2
239     float numrator = (((o_div + 2) * 2 * freq) / ((float)xtal_freq_mhz * MHZ)) - 4 - sdm2;
240     // If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2
241     if (numrator > 1.0f - (1.0f / 65536.0f) / 2.0f) {
242         sdm2++;
243     }
244     // If numrator is smaller than (1/65536)/2, keep sdm0 = sdm1 = 0, otherwise calculate sdm0 and sdm1
245     else if (numrator > (1.0f / 65536.0f) / 2.0f) {
246         // Get the closest sdm1
247         sdm1 = (int)(numrator * 65536.0f + 0.5f) / 256;
248         // Get the closest sdm0
249         sdm0 = (int)(numrator * 65536.0f + 0.5f) % 256;
250     }
251     uint32_t real_freq = (uint32_t)(xtal_freq_mhz * MHZ * (4 + sdm2 + (float)sdm1/256.0f + (float)sdm0/65536.0f) / (((float)o_div + 2) * 2));
252     *_o_div = o_div;
253     *_sdm0 = sdm0;
254     *_sdm1 = sdm1;
255     *_sdm2 = sdm2;
256     return real_freq;
257 }
258 
rtc_clk_apll_coeff_set(uint32_t o_div,uint32_t sdm0,uint32_t sdm1,uint32_t sdm2)259 void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
260 {
261     bool is_rev0 = (efuse_ll_get_chip_ver_rev1() == 0);
262     clk_ll_apll_set_config(is_rev0, o_div, sdm0, sdm1, sdm2);
263 
264     /* calibration */
265     clk_ll_apll_set_calibration();
266 
267     /* wait for calibration end */
268     while (!clk_ll_apll_calibration_is_done()) {
269         /* use esp_rom_delay_us so the RTC bus doesn't get flooded */
270         esp_rom_delay_us(1);
271     }
272 }
273 
rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)274 void rtc_clk_slow_src_set(soc_rtc_slow_clk_src_t clk_src)
275 {
276     clk_ll_rtc_slow_set_src(clk_src);
277 
278     // The logic should be moved to BT driver
279     if (clk_src == SOC_RTC_SLOW_CLK_SRC_XTAL32K) {
280         clk_ll_xtal32k_digi_enable();
281     } else {
282         clk_ll_xtal32k_digi_disable();
283     }
284 
285     esp_rom_delay_us(SOC_DELAY_RTC_SLOW_CLK_SWITCH);
286 }
287 
rtc_clk_slow_src_get(void)288 soc_rtc_slow_clk_src_t rtc_clk_slow_src_get(void)
289 {
290     return clk_ll_rtc_slow_get_src();
291 }
292 
rtc_clk_slow_freq_get_hz(void)293 uint32_t rtc_clk_slow_freq_get_hz(void)
294 {
295     switch (rtc_clk_slow_src_get()) {
296     case SOC_RTC_SLOW_CLK_SRC_RC_SLOW: return SOC_CLK_RC_SLOW_FREQ_APPROX;
297     case SOC_RTC_SLOW_CLK_SRC_XTAL32K: return SOC_CLK_XTAL32K_FREQ_APPROX;
298     case SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256: return SOC_CLK_RC_FAST_D256_FREQ_APPROX;
299     default: return 0;
300     }
301 }
302 
rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)303 void rtc_clk_fast_src_set(soc_rtc_fast_clk_src_t clk_src)
304 {
305     clk_ll_rtc_fast_set_src(clk_src);
306     esp_rom_delay_us(SOC_DELAY_RTC_FAST_CLK_SWITCH);
307 }
308 
rtc_clk_fast_src_get(void)309 soc_rtc_fast_clk_src_t rtc_clk_fast_src_get(void)
310 {
311     return clk_ll_rtc_fast_get_src();
312 }
313 
rtc_clk_bbpll_disable(void)314 static void rtc_clk_bbpll_disable(void)
315 {
316     clk_ll_bbpll_disable();
317     s_cur_pll_freq = 0;
318 
319     // if apll is under force power down, then can also power down the internal I2C bus
320     // this power down affects most of the analog peripherals
321     if (clk_ll_apll_is_fpd()) {
322         clk_ll_i2c_pd();
323     }
324 }
325 
rtc_clk_bbpll_enable(void)326 static void rtc_clk_bbpll_enable(void)
327 {
328     clk_ll_i2c_pu();
329     clk_ll_bbpll_enable();
330 }
331 
rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq,int pll_freq)332 static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq)
333 {
334     /* Raise the voltage */
335     if (pll_freq == CLK_LL_PLL_320M_FREQ_MHZ) {
336         REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_80M_160M);
337     } else { // CLK_LL_PLL_480M_FREQ_MHZ
338         REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M);
339         esp_rom_delay_us(SOC_DELAY_PLL_DBIAS_RAISE);
340     }
341 
342     clk_ll_bbpll_set_config(pll_freq, xtal_freq);
343     uint32_t delay_pll_en = (clk_ll_rtc_slow_get_src() == SOC_RTC_SLOW_CLK_SRC_RC_SLOW) ?
344             SOC_DELAY_PLL_ENABLE_WITH_150K : SOC_DELAY_PLL_ENABLE_WITH_32K;
345     esp_rom_delay_us(delay_pll_en);
346     s_cur_pll_freq = pll_freq;
347 }
348 
349 /**
350  * Switch to use XTAL as the CPU clock source.
351  * Must satisfy: cpu_freq = XTAL_FREQ / div.
352  * Does not disable the PLL.
353  */
rtc_clk_cpu_freq_to_xtal(int cpu_freq,int div)354 void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div)
355 {
356     esp_rom_set_cpu_ticks_per_us(cpu_freq);
357     /* set divider from XTAL to APB clock */
358     clk_ll_cpu_set_divider(div);
359     /* adjust ref_tick */
360     clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_XTAL, cpu_freq);
361     /* switch clock source */
362     clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
363     rtc_clk_apb_freq_update(cpu_freq * MHZ);
364     /* lower the voltage */
365     int dbias = (cpu_freq <= 2) ? DIG_DBIAS_2M : DIG_DBIAS_XTAL;
366     REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
367 }
368 
rtc_clk_cpu_freq_to_8m(void)369 static void rtc_clk_cpu_freq_to_8m(void)
370 {
371     esp_rom_set_cpu_ticks_per_us(8);
372     REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL);
373     clk_ll_cpu_set_divider(1);
374     /* adjust ref_tick */
375     clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_RC_FAST, 8);
376     /* switch clock source */
377     clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
378     rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX);
379 }
380 
381 /**
382  * Switch to one of PLL-based frequencies. Current frequency can be XTAL or PLL.
383  * PLL must already be enabled.
384  * @param cpu_freq new CPU frequency
385  */
rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)386 static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
387 {
388     int dbias = (cpu_freq_mhz == 240) ? DIG_DBIAS_240M : DIG_DBIAS_80M_160M;
389     clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
390     REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias);
391     /* adjust ref_tick */
392     clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, cpu_freq_mhz);
393     /* switch clock source */
394     clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
395     rtc_clk_apb_freq_update(80 * MHZ);
396     esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
397     rtc_clk_wait_for_slow_cycle();
398 }
399 
rtc_clk_cpu_freq_set_xtal(void)400 void rtc_clk_cpu_freq_set_xtal(void)
401 {
402     rtc_clk_cpu_set_to_default_config();
403     rtc_clk_bbpll_disable();
404 }
405 
rtc_clk_cpu_set_to_default_config(void)406 void rtc_clk_cpu_set_to_default_config(void)
407 {
408     int freq_mhz = (int)rtc_clk_xtal_freq_get();
409 
410     rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
411     rtc_clk_wait_for_slow_cycle();
412 }
413 
rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz,rtc_cpu_freq_config_t * out_config)414 bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config)
415 {
416     uint32_t source_freq_mhz;
417     soc_cpu_clk_src_t source;
418     uint32_t divider;
419     uint32_t real_freq_mhz;
420 
421     uint32_t xtal_freq = (uint32_t) rtc_clk_xtal_freq_get();
422     if (freq_mhz <= xtal_freq && freq_mhz != 0) {
423         divider = xtal_freq / freq_mhz;
424         real_freq_mhz = (xtal_freq + divider / 2) / divider; /* round */
425         if (real_freq_mhz != freq_mhz) {
426             // no suitable divider
427             return false;
428         }
429 
430         source_freq_mhz = xtal_freq;
431         source = SOC_CPU_CLK_SRC_XTAL;
432     } else if (freq_mhz == 80) {
433         real_freq_mhz = freq_mhz;
434         source = SOC_CPU_CLK_SRC_PLL;
435         source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
436         divider = 4;
437     } else if (freq_mhz == 160) {
438         real_freq_mhz = freq_mhz;
439         source = SOC_CPU_CLK_SRC_PLL;
440         source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
441         divider = 2;
442     } else if (freq_mhz == 240) {
443         real_freq_mhz = freq_mhz;
444         source = SOC_CPU_CLK_SRC_PLL;
445         source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
446         divider = 2;
447     } else {
448         // unsupported frequency
449         return false;
450     }
451     *out_config = (rtc_cpu_freq_config_t) {
452         .source = source,
453         .div = divider,
454         .source_freq_mhz = source_freq_mhz,
455         .freq_mhz = real_freq_mhz
456     };
457     return true;
458 }
459 
rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t * config)460 void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t* config)
461 {
462     rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
463     soc_cpu_clk_src_t old_cpu_clk_src = clk_ll_cpu_get_src();
464     if (old_cpu_clk_src != SOC_CPU_CLK_SRC_XTAL) {
465         rtc_clk_cpu_freq_to_xtal(xtal_freq, 1);
466         rtc_clk_wait_for_slow_cycle();
467     }
468     if (old_cpu_clk_src == SOC_CPU_CLK_SRC_PLL) {
469         rtc_clk_bbpll_disable();
470     }
471 
472     if (config->source == SOC_CPU_CLK_SRC_XTAL) {
473         if (config->div > 1) {
474             rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
475         }
476     } else if (config->source == SOC_CPU_CLK_SRC_PLL) {
477         rtc_clk_bbpll_enable();
478         rtc_clk_wait_for_slow_cycle();
479         rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), config->source_freq_mhz);
480         rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
481     } else if (config->source == SOC_CPU_CLK_SRC_RC_FAST) {
482         rtc_clk_cpu_freq_to_8m();
483     }
484 }
485 
rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t * out_config)486 void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t* out_config)
487 {
488     soc_cpu_clk_src_t source = clk_ll_cpu_get_src();
489     uint32_t source_freq_mhz;
490     uint32_t div;
491     uint32_t freq_mhz;
492     switch (source) {
493     case SOC_CPU_CLK_SRC_XTAL: {
494         div = clk_ll_cpu_get_divider();
495         source_freq_mhz = (uint32_t) rtc_clk_xtal_freq_get();
496         freq_mhz = source_freq_mhz / div;
497     }
498     break;
499     case SOC_CPU_CLK_SRC_PLL: {
500         freq_mhz = clk_ll_cpu_get_freq_mhz_from_pll();
501         if (freq_mhz == CLK_LL_PLL_80M_FREQ_MHZ) {
502             source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
503             div = 4;
504         } else if (freq_mhz == CLK_LL_PLL_160M_FREQ_MHZ) {
505             source_freq_mhz = CLK_LL_PLL_320M_FREQ_MHZ;
506             div = 2;
507         } else if (freq_mhz == CLK_LL_PLL_240M_FREQ_MHZ) {
508             source_freq_mhz = CLK_LL_PLL_480M_FREQ_MHZ;
509             div = 2;
510         } else {
511             ESP_HW_LOGE(TAG, "unsupported frequency configuration");
512             abort();
513         }
514         break;
515     }
516     case SOC_CPU_CLK_SRC_RC_FAST:
517         source_freq_mhz = 8;
518         div = 1;
519         freq_mhz = source_freq_mhz;
520         break;
521     case SOC_CPU_CLK_SRC_APLL:
522     default:
523         ESP_HW_LOGE(TAG, "unsupported frequency configuration");
524         abort();
525     }
526     *out_config = (rtc_cpu_freq_config_t) {
527         .source = source,
528         .source_freq_mhz = source_freq_mhz,
529         .div = div,
530         .freq_mhz = freq_mhz
531     };
532 }
533 
rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t * config)534 void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config)
535 {
536     if (config->source == SOC_CPU_CLK_SRC_XTAL) {
537         rtc_clk_cpu_freq_to_xtal(config->freq_mhz, config->div);
538     } else if (config->source == SOC_CPU_CLK_SRC_PLL &&
539             s_cur_pll_freq == config->source_freq_mhz) {
540         rtc_clk_cpu_freq_to_pll_mhz(config->freq_mhz);
541     } else {
542         /* fallback */
543         rtc_clk_cpu_freq_set_config(config);
544     }
545 }
546 
rtc_clk_xtal_freq_get(void)547 rtc_xtal_freq_t rtc_clk_xtal_freq_get(void)
548 {
549     uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
550     if (xtal_freq_mhz == 0) {
551         return RTC_XTAL_FREQ_AUTO;
552     }
553     return (rtc_xtal_freq_t)xtal_freq_mhz;
554 }
555 
rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)556 void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
557 {
558     clk_ll_xtal_store_freq_mhz((uint32_t)xtal_freq);
559 }
560 
rtc_clk_apb_freq_update(uint32_t apb_freq)561 void rtc_clk_apb_freq_update(uint32_t apb_freq)
562 {
563     clk_ll_apb_store_freq_hz(apb_freq);
564 }
565 
rtc_clk_apb_freq_get(void)566 uint32_t rtc_clk_apb_freq_get(void)
567 {
568 #if CONFIG_IDF_ENV_FPGA
569     return CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * MHZ;
570 #endif // CONFIG_IDF_ENV_FPGA
571     return clk_ll_apb_load_freq_hz();
572 }
573 
rtc_dig_clk8m_enable(void)574 void rtc_dig_clk8m_enable(void)
575 {
576     clk_ll_rc_fast_digi_enable();
577     esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
578 }
579 
rtc_dig_clk8m_disable(void)580 void rtc_dig_clk8m_disable(void)
581 {
582     clk_ll_rc_fast_digi_disable();
583     esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH);
584 }
585 
rtc_dig_8m_enabled(void)586 bool rtc_dig_8m_enabled(void)
587 {
588     return clk_ll_rc_fast_digi_is_enabled();
589 }
590 
591 /* Name used in libphy.a:phy_chip_v7.o
592  * TODO: update the library to use rtc_clk_xtal_freq_get
593  */
594 rtc_xtal_freq_t rtc_get_xtal(void) __attribute__((alias("rtc_clk_xtal_freq_get")));
595