diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 4119a1ede6..7b8994d950 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -5,8 +5,12 @@ if(${target} STREQUAL "esp32") list(APPEND requires efuse) endif() -idf_component_register(SRCS "compare_set.c" - "cpu_util.c" +set(srcs "compare_set.c" "cpu_util.c") +if(NOT BOOTLOADER_BUILD) + list(APPEND srcs "clk_ctrl_os.c") +endif() + +idf_component_register(SRCS ${srcs} INCLUDE_DIRS include REQUIRES ${requires} PRIV_REQUIRES efuse diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c new file mode 100644 index 0000000000..ae1d42c0ed --- /dev/null +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -0,0 +1,56 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "soc/clk_ctrl_os.h" + +#define DELAY_RTC_CLK_SWITCH 5 + +static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED; + +static uint8_t s_periph_ref_counts = 0; +static uint32_t s_rtc_clk_freq = 0; // Frequency of the 8M/256 clock in Hz + +bool periph_rtc_dig_clk8m_enable(void) +{ + portENTER_CRITICAL(&periph_spinlock); + if (s_periph_ref_counts == 0) { + rtc_dig_clk8m_enable(); + s_rtc_clk_freq = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, 100)); + if (s_rtc_clk_freq == 0) { + portEXIT_CRITICAL(&periph_spinlock); + return false; + } + } + s_periph_ref_counts++; + portEXIT_CRITICAL(&periph_spinlock); + return true; +} + +uint32_t periph_rtc_dig_clk8m_get_freq(void) +{ + return s_rtc_clk_freq * 256; +} + +void periph_rtc_dig_clk8m_disable(void) +{ + portENTER_CRITICAL(&periph_spinlock); + assert(s_periph_ref_counts > 0); + s_periph_ref_counts--; + if (s_periph_ref_counts == 0) { + s_rtc_clk_freq = 0; + rtc_dig_clk8m_disable(); + } + portEXIT_CRITICAL(&periph_spinlock); +} diff --git a/components/esp_hw_support/component.mk b/components/esp_hw_support/component.mk index b1674229b3..da4d6c1e71 100644 --- a/components/esp_hw_support/component.mk +++ b/components/esp_hw_support/component.mk @@ -2,3 +2,7 @@ COMPONENT_SRCDIRS := . port/$(IDF_TARGET) COMPONENT_ADD_INCLUDEDIRS := . include port/$(IDF_TARGET)/private_include port/$(IDF_TARGET)/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion + +ifdef IS_BOOTLOADER_BUILD +COMPONENT_OBJEXCLUDE += clk_ctrl_os.o +endif diff --git a/components/esp_hw_support/include/soc/clk_ctrl_os.h b/components/esp_hw_support/include/soc/clk_ctrl_os.h new file mode 100644 index 0000000000..f4d769b801 --- /dev/null +++ b/components/esp_hw_support/include/soc/clk_ctrl_os.h @@ -0,0 +1,50 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/rtc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief This function is used to enable the digital 8m rtc clock, + * to support the peripherals. + * + * @note If this function is called a number of times, the `periph_rtc_dig_clk8m_disable` + * function needs to be called same times to disable. + * + * @return true: success for enable the rtc 8M clock, false: rtc 8M clock enable failed + */ +bool periph_rtc_dig_clk8m_enable(void); + +/** + * @brief This function is used to disable the rtc digital clock, which should be called + * with the `periph_rtc_dig_clk8m_enable` pairedly + * + * @note If this function is called a number of times, the `periph_rtc_dig_clk8m_disable` + * function needs to be called same times to disable. + */ +void periph_rtc_dig_clk8m_disable(void); + +/** + * @brief This function is used to get the real clock frequency value of the rtc clock + * + * @return The real clock value + */ +uint32_t periph_rtc_dig_clk8m_get_freq(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 2dac3a9c93..75c94f7fe7 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -101,6 +101,7 @@ #define RTC_PLL_FREQ_320M 320 #define RTC_PLL_FREQ_480M 480 +#define DELAY_RTC_CLK_SWITCH 5 static void rtc_clk_cpu_freq_to_8m(void); static void rtc_clk_bbpll_disable(void); @@ -773,6 +774,18 @@ uint32_t rtc_clk_apb_freq_get(void) return freq_hz - remainder; } +void rtc_dig_clk8m_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32/rtc_time.c b/components/esp_hw_support/port/esp32/rtc_time.c index 0d2433d52c..99539e0d55 100644 --- a/components/esp_hw_support/port/esp32/rtc_time.c +++ b/components/esp_hw_support/port/esp32/rtc_time.c @@ -167,3 +167,11 @@ void rtc_clk_wait_for_slow_cycle(void) esp_rom_delay_us(1); } } + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} diff --git a/components/esp_hw_support/port/esp32c3/rtc_clk.c b/components/esp_hw_support/port/esp32c3/rtc_clk.c index d85901963c..6c82c2103b 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c3/rtc_clk.c @@ -37,6 +37,7 @@ static const char *TAG = "rtc_clk"; #define RTC_PLL_FREQ_320M 320 #define RTC_PLL_FREQ_480M 480 +#define DELAY_RTC_CLK_SWITCH 5 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. static int s_cur_pll_freq; @@ -559,6 +560,18 @@ void rtc_clk_8m_divider_set(uint32_t div) SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); } +void rtc_dig_clk8m_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32c3/rtc_time.c b/components/esp_hw_support/port/esp32c3/rtc_time.c index e9996ba03d..12c0961a43 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_time.c +++ b/components/esp_hw_support/port/esp32c3/rtc_time.c @@ -179,3 +179,11 @@ void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any mor esp_rom_delay_us(1); } } + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index 49ab1ebfd6..8497cd3834 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s2/rtc_clk.c @@ -37,6 +37,7 @@ static const char *TAG = "rtc_clk"; #define RTC_PLL_FREQ_320M 320 #define RTC_PLL_FREQ_480M 480 +#define DELAY_RTC_CLK_SWITCH 5 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. // On the ESP32-S2, 480MHz PLL is enabled at reset. @@ -539,6 +540,18 @@ void rtc_clk_8m_divider_set(uint32_t div) SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); } +void rtc_dig_clk8m_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32s2/rtc_time.c b/components/esp_hw_support/port/esp32s2/rtc_time.c index 789352e140..a8987b698c 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_time.c +++ b/components/esp_hw_support/port/esp32s2/rtc_time.c @@ -184,3 +184,11 @@ void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any mor esp_rom_delay_us(1); } } + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index 3a9d069270..a1d2433aa8 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s3/rtc_clk.c @@ -38,6 +38,7 @@ static const char *TAG = "rtc_clk"; #define RTC_PLL_FREQ_320M 320 #define RTC_PLL_FREQ_480M 480 +#define DELAY_RTC_CLK_SWITCH 5 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled. static int s_cur_pll_freq = RTC_PLL_FREQ_480M; @@ -556,6 +557,18 @@ void rtc_clk_8m_divider_set(uint32_t div) SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL_VLD); } +void rtc_dig_clk8m_enable(void) +{ + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + +void rtc_dig_clk8m_disable(void) +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + esp_rom_delay_us(DELAY_RTC_CLK_SWITCH); +} + /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32s3/rtc_time.c b/components/esp_hw_support/port/esp32s3/rtc_time.c index b529c19076..d2b78984af 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_time.c +++ b/components/esp_hw_support/port/esp32s3/rtc_time.c @@ -178,3 +178,11 @@ void rtc_clk_wait_for_slow_cycle(void) //This function may not by useful any mor esp_rom_delay_us(1); } } + +uint32_t rtc_clk_freq_cal(uint32_t cal_val) +{ + if (cal_val == 0) { + return 0; // cal_val will be denominator, return 0 as the symbol of failure. + } + return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / cal_val; +} diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index b283dadad3..7b09fde1eb 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -459,6 +459,29 @@ uint64_t rtc_time_get(void); */ void rtc_clk_wait_for_slow_cycle(void); +/** + * @brief Enable the rtc digital 8M clock + * + * This function is used to enable the digital rtc 8M clock to support peripherals. + * For enabling the analog 8M clock, using `rtc_clk_8M_enable` function above. + */ +void rtc_dig_clk8m_enable(void); + +/** + * @brief Disable the rtc digital 8M clock + * + * This function is used to disable the digital rtc 8M clock, which is only used to support peripherals. + */ +void rtc_dig_clk8m_disable(void); + +/** + * @brief Caculate the real clock value after the clock calibration + * + * @param cal_val average slow clock period in microseconds, can be return from `rtc_clk_cal` + * @return The real value of the clock has been measured + */ +uint32_t rtc_clk_freq_cal(uint32_t cal_val); + /** * @brief sleep configuration for rtc_sleep_init function */ diff --git a/components/soc/esp32c3/include/soc/rtc.h b/components/soc/esp32c3/include/soc/rtc.h index ed650f4950..3eafc77c1f 100644 --- a/components/soc/esp32c3/include/soc/rtc.h +++ b/components/soc/esp32c3/include/soc/rtc.h @@ -562,6 +562,29 @@ uint64_t rtc_deep_slp_time_get(void); */ void rtc_clk_wait_for_slow_cycle(void); +/** + * @brief Enable the rtc digital 8M clock + * + * This function is used to enable the digital rtc 8M clock to support peripherals. + * For enabling the analog 8M clock, using `rtc_clk_8M_enable` function above. + */ +void rtc_dig_clk8m_enable(void); + +/** + * @brief Disable the rtc digital 8M clock + * + * This function is used to disable the digital rtc 8M clock, which is only used to support peripherals. + */ +void rtc_dig_clk8m_disable(void); + +/** + * @brief Caculate the real clock value after the clock calibration + * + * @param cal_val average slow clock period in microseconds, can be return from `rtc_clk_cal` + * @return The real value of the clock has been measured + */ +uint32_t rtc_clk_freq_cal(uint32_t cal_val); + /** * @brief Power down flags for rtc_sleep_pd function */ diff --git a/components/soc/esp32s2/include/soc/rtc.h b/components/soc/esp32s2/include/soc/rtc.h index 11b1a7c8f9..2474c67bae 100644 --- a/components/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/esp32s2/include/soc/rtc.h @@ -588,6 +588,29 @@ uint64_t rtc_deep_slp_time_get(void); */ void rtc_clk_wait_for_slow_cycle(void); +/** + * @brief Enable the rtc digital 8M clock + * + * This function is used to enable the digital rtc 8M clock to support peripherals. + * For enabling the analog 8M clock, using `rtc_clk_8M_enable` function above. + */ +void rtc_dig_clk8m_enable(void); + +/** + * @brief Disable the rtc digital 8M clock + * + * This function is used to disable the digital rtc 8M clock, which is only used to support peripherals. + */ +void rtc_dig_clk8m_disable(void); + +/** + * @brief Caculate the real clock value after the clock calibration + * + * @param cal_val average slow clock period in microseconds, can be return from `rtc_clk_cal` + * @return The real value of the clock has been measured + */ +uint32_t rtc_clk_freq_cal(uint32_t cal_val); + /** * @brief Power down flags for rtc_sleep_pd function */ diff --git a/components/soc/esp32s3/include/soc/rtc.h b/components/soc/esp32s3/include/soc/rtc.h index 035f7f9d9f..0287081d69 100644 --- a/components/soc/esp32s3/include/soc/rtc.h +++ b/components/soc/esp32s3/include/soc/rtc.h @@ -562,6 +562,29 @@ uint64_t rtc_deep_slp_time_get(void); */ void rtc_clk_wait_for_slow_cycle(void); +/** + * @brief Enable the rtc digital 8M clock + * + * This function is used to enable the digital rtc 8M clock to support peripherals. + * For enabling the analog 8M clock, using `rtc_clk_8M_enable` function above. + */ +void rtc_dig_clk8m_enable(void); + +/** + * @brief Disable the rtc digital 8M clock + * + * This function is used to disable the digital rtc 8M clock, which is only used to support peripherals. + */ +void rtc_dig_clk8m_disable(void); + +/** + * @brief Caculate the real clock value after the clock calibration + * + * @param cal_val average slow clock period in microseconds, can be return from `rtc_clk_cal` + * @return The real value of the clock has been measured + */ +uint32_t rtc_clk_freq_cal(uint32_t cal_val); + /** * @brief Power up flags for rtc_sleep_pd function */