mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
refactor(clk_tree): use general api to enable the clk
This commit is contained in:
@@ -1,209 +1,66 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_ldo_regulator.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/critical_section.h"
|
||||
#include "esp_check.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
#include "rtc_clk.h"
|
||||
#endif
|
||||
|
||||
#if SOC_CLK_APLL_SUPPORTED || SOC_CLK_MPLL_SUPPORTED
|
||||
ESP_LOG_ATTR_TAG(TAG, "clk_ctrl_os");
|
||||
#endif
|
||||
|
||||
static portMUX_TYPE __attribute__((unused)) periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static uint8_t s_periph_ref_counts = 0;
|
||||
static uint32_t s_rc_fast_freq_hz = 0; // Frequency of the RC_FAST clock in Hz
|
||||
#if SOC_CLK_APLL_SUPPORTED
|
||||
// Current APLL frequency, in HZ. Zero if APLL is not enabled.
|
||||
static uint32_t s_cur_apll_freq_hz = 0;
|
||||
static int s_apll_ref_cnt = 0;
|
||||
#endif
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
static uint32_t s_cur_mpll_freq_hz = 0;
|
||||
static int s_mpll_ref_cnt = 0;
|
||||
static esp_ldo_channel_handle_t s_ldo_chan = NULL;
|
||||
#endif
|
||||
#include "soc/clk_tree_defs.h"
|
||||
|
||||
bool periph_rtc_dig_clk8m_enable(void)
|
||||
{
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
if (s_periph_ref_counts == 0) {
|
||||
rtc_dig_clk8m_enable();
|
||||
#if SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
|
||||
s_rc_fast_freq_hz = esp_clk_tree_rc_fast_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT);
|
||||
if (s_rc_fast_freq_hz == 0) {
|
||||
rtc_dig_clk8m_disable();
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
return false;
|
||||
}
|
||||
#endif //SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
|
||||
}
|
||||
s_periph_ref_counts++;
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
return true;
|
||||
return esp_clk_tree_enable_src(SOC_MOD_CLK_RC_FAST, true) == ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t periph_rtc_dig_clk8m_get_freq(void)
|
||||
{
|
||||
#if !SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
|
||||
/* Workaround: CLK8M calibration cannot be performed, we can only return its theoretic value */
|
||||
return SOC_CLK_RC_FAST_FREQ_APPROX;
|
||||
#if SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
|
||||
return esp_clk_tree_rc_fast_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT);
|
||||
#else
|
||||
return s_rc_fast_freq_hz;
|
||||
return SOC_CLK_RC_FAST_FREQ_APPROX;
|
||||
#endif
|
||||
}
|
||||
|
||||
void periph_rtc_dig_clk8m_disable(void)
|
||||
{
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
assert(s_periph_ref_counts > 0);
|
||||
s_periph_ref_counts--;
|
||||
if (s_periph_ref_counts == 0) {
|
||||
s_rc_fast_freq_hz = 0;
|
||||
rtc_dig_clk8m_disable();
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
(void)esp_clk_tree_enable_src(SOC_MOD_CLK_RC_FAST, false);
|
||||
}
|
||||
|
||||
#if SOC_CLK_APLL_SUPPORTED
|
||||
void periph_rtc_apll_acquire(void)
|
||||
{
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
s_apll_ref_cnt++;
|
||||
if (s_apll_ref_cnt == 1) {
|
||||
// For the first time enable APLL, need to set power up
|
||||
rtc_clk_apll_enable(true);
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
(void)esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true);
|
||||
}
|
||||
|
||||
void periph_rtc_apll_release(void)
|
||||
{
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
assert(s_apll_ref_cnt > 0);
|
||||
s_apll_ref_cnt--;
|
||||
if (s_apll_ref_cnt == 0) {
|
||||
// If there is no peripheral using APLL, shut down the power
|
||||
s_cur_apll_freq_hz = 0;
|
||||
rtc_clk_apll_enable(false);
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
(void)esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false);
|
||||
}
|
||||
|
||||
esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz)
|
||||
{
|
||||
uint32_t o_div = 0;
|
||||
uint32_t sdm0 = 0;
|
||||
uint32_t sdm1 = 0;
|
||||
uint32_t sdm2 = 0;
|
||||
// Guarantee 'periph_rtc_apll_acquire' has been called before set apll freq
|
||||
assert(s_apll_ref_cnt > 0);
|
||||
uint32_t apll_freq = rtc_clk_apll_coeff_calc(expt_freq_hz, &o_div, &sdm0, &sdm1, &sdm2);
|
||||
|
||||
ESP_RETURN_ON_FALSE(apll_freq, ESP_ERR_INVALID_ARG, TAG, "APLL coefficients calculate failed");
|
||||
bool need_config = true;
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
/* If APLL is not in use or only one peripheral in use, its frequency can be changed as will
|
||||
* But when more than one peripheral refers APLL, its frequency is not allowed to change once it is set */
|
||||
if (s_cur_apll_freq_hz == 0 || s_apll_ref_cnt < 2) {
|
||||
s_cur_apll_freq_hz = apll_freq;
|
||||
} else {
|
||||
apll_freq = s_cur_apll_freq_hz;
|
||||
need_config = false;
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
*real_freq_hz = apll_freq;
|
||||
|
||||
if (need_config) {
|
||||
ESP_LOGD(TAG, "APLL will working at %"PRIu32" Hz with coefficients [sdm0] %"PRIu32" [sdm1] %"PRIu32" [sdm2] %"PRIu32" [o_div] %"PRIu32"",
|
||||
apll_freq, sdm0, sdm1, sdm2, o_div);
|
||||
/* Set coefficients for APLL, notice that it doesn't mean APLL will start */
|
||||
rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2);
|
||||
} else {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
return esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, expt_freq_hz, real_freq_hz);
|
||||
}
|
||||
#endif // SOC_CLK_APLL_SUPPORTED
|
||||
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
esp_err_t IRAM_ATTR periph_rtc_mpll_acquire(void)
|
||||
{
|
||||
// power up LDO for the MPLL
|
||||
#if CONFIG_ESP_LDO_RESERVE_PSRAM
|
||||
esp_ldo_channel_config_t ldo_mpll_config = {
|
||||
.chan_id = CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN,
|
||||
.voltage_mv = CONFIG_ESP_LDO_VOLTAGE_PSRAM_DOMAIN,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_acquire_channel(&ldo_mpll_config, &s_ldo_chan), TAG, "acquire internal LDO for MPLL failed");
|
||||
#endif
|
||||
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
s_mpll_ref_cnt++;
|
||||
if (s_mpll_ref_cnt == 1) {
|
||||
// For the first time enable MPLL, need to set power up
|
||||
rtc_clk_mpll_enable();
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
return ESP_OK;
|
||||
// For IRAM compatibility, we do not use esp_clk_tree_enable_src here
|
||||
return esp_clk_tree_mpll_acquire();
|
||||
}
|
||||
|
||||
void periph_rtc_mpll_release(void)
|
||||
{
|
||||
#if defined(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN) && CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN != -1
|
||||
if (s_ldo_chan) {
|
||||
esp_ldo_release_channel(s_ldo_chan);
|
||||
}
|
||||
#endif
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
assert(s_mpll_ref_cnt > 0);
|
||||
s_mpll_ref_cnt--;
|
||||
if (s_mpll_ref_cnt == 0) {
|
||||
// If there is no peripheral using MPLL, shut down the power
|
||||
s_cur_mpll_freq_hz = 0;
|
||||
rtc_clk_mpll_disable();
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
// For IRAM compatibility, we do not use esp_clk_tree_enable_src here
|
||||
(void)esp_clk_tree_mpll_release();
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR periph_rtc_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
// Guarantee 'periph_rtc_apll_acquire' has been called before set apll freq
|
||||
assert(s_mpll_ref_cnt > 0);
|
||||
|
||||
esp_os_enter_critical(&periph_spinlock);
|
||||
if (s_cur_mpll_freq_hz == expt_freq_hz) {
|
||||
goto end;
|
||||
}
|
||||
/* If MPLL is not in use or only one peripheral in use, its frequency can be changed as will
|
||||
* But when more than one peripheral refers MPLL, its frequency is not allowed to change once it is set */
|
||||
if (s_cur_mpll_freq_hz == 0 || s_mpll_ref_cnt < 2) {
|
||||
uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz();
|
||||
rtc_clk_mpll_configure(xtal_freq_mhz, expt_freq_hz / MHZ, false);
|
||||
s_cur_mpll_freq_hz = clk_ll_mpll_get_freq_mhz(xtal_freq_mhz) * MHZ;
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
end:
|
||||
if (real_freq_hz != NULL) {
|
||||
*real_freq_hz = s_cur_mpll_freq_hz;
|
||||
}
|
||||
esp_os_exit_critical(&periph_spinlock);
|
||||
return ret;
|
||||
// For IRAM compatibility, we do not use esp_clk_tree_src_set_freq_hz here
|
||||
return esp_clk_tree_mpll_freq_set(expt_freq_hz, real_freq_hz);
|
||||
}
|
||||
#endif // SOC_CLK_MPLL_SUPPORTED
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -21,7 +21,7 @@ extern "C" {
|
||||
*
|
||||
* @return true: success for enable the RC_FAST clock, false: RC_FAST clock enable failed
|
||||
*/
|
||||
bool periph_rtc_dig_clk8m_enable(void);
|
||||
bool periph_rtc_dig_clk8m_enable(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief This function is used to disable the digital RC_FAST clock, which should be called
|
||||
@@ -30,25 +30,25 @@ bool periph_rtc_dig_clk8m_enable(void);
|
||||
* @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);
|
||||
void periph_rtc_dig_clk8m_disable(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the real clock frequency value of RC_FAST clock
|
||||
*
|
||||
* @return The real clock value, in Hz
|
||||
*/
|
||||
uint32_t periph_rtc_dig_clk8m_get_freq(void);
|
||||
uint32_t periph_rtc_dig_clk8m_get_freq(void) __attribute__((deprecated("Please use esp_clk_tree_src_get_freq_hz instead")));
|
||||
|
||||
#if SOC_CLK_APLL_SUPPORTED
|
||||
/**
|
||||
* @brief Enable APLL power if it has not enabled
|
||||
*/
|
||||
void periph_rtc_apll_acquire(void);
|
||||
void periph_rtc_apll_acquire(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief Shut down APLL power if no peripherals using APLL
|
||||
*/
|
||||
void periph_rtc_apll_release(void);
|
||||
void periph_rtc_apll_release(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief Calculate and set APLL coefficients by given frequency
|
||||
@@ -69,19 +69,19 @@ void periph_rtc_apll_release(void);
|
||||
* - ESP_ERR_INVALID_ARG: The input expt_freq is out of APLL support range
|
||||
* - ESP_ERR_INVALID_STATE: APLL is referred by more than one peripherals, not allowed to change its frequency now
|
||||
*/
|
||||
esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz);
|
||||
esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz) __attribute__((deprecated("Please use esp_clk_tree_src_set_freq_hz instead")));
|
||||
#endif // SOC_CLK_APLL_SUPPORTED
|
||||
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
/**
|
||||
* @brief Enable MPLL power if it has not enabled
|
||||
*/
|
||||
esp_err_t periph_rtc_mpll_acquire(void);
|
||||
esp_err_t periph_rtc_mpll_acquire(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief Shut down MPLL power if no peripherals using APLL
|
||||
*/
|
||||
void periph_rtc_mpll_release(void);
|
||||
void periph_rtc_mpll_release(void) __attribute__((deprecated("Please use esp_clk_tree_enable_src instead")));
|
||||
|
||||
/**
|
||||
* @brief Configure MPLL frequency
|
||||
@@ -96,7 +96,7 @@ void periph_rtc_mpll_release(void);
|
||||
* - ESP_OK: MPLL frequency set success
|
||||
* - ESP_ERR_INVALID_STATE: MPLL is referred by more than one peripherals, not allowed to change its frequency now
|
||||
*/
|
||||
esp_err_t periph_rtc_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz);
|
||||
esp_err_t periph_rtc_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz) __attribute__((deprecated("Please use esp_clk_tree_src_set_freq_hz instead")));
|
||||
#endif // SOC_CLK_MPLL_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -18,7 +20,7 @@ extern "C" {
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, /*< Get value from the data cached by the driver; If the data is 0, then a calibration will be performed */
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, /*< Get its approxiamte frequency value */
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, /*< Get its approximate frequency value */
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, /*< Always perform a calibration */
|
||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, /*< Invalid degree of precision */
|
||||
} esp_clk_tree_src_freq_precision_t;
|
||||
@@ -42,6 +44,20 @@ typedef enum {
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value);
|
||||
|
||||
/**
|
||||
* @brief Set frequency of module clock source
|
||||
*
|
||||
* @param[in] clk_src Clock source available to modules, in soc_module_clk_t
|
||||
* @param[in] expt_freq_value Expected frequency of the clock source, in Hz
|
||||
* @param[out] ret_freq_value Real frequency of the clock source, in Hz
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_SUPPORTED Unsupported clock source
|
||||
*/
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -118,6 +118,72 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
*/
|
||||
bool esp_clk_tree_is_power_on(soc_root_clk_circuit_t clk_circuit);
|
||||
|
||||
#if SOC_CLK_APLL_SUPPORTED
|
||||
/**
|
||||
* @brief Enable APLL power if it has not enabled
|
||||
*
|
||||
* @note Do not use this function in applications or drivers, please use `esp_clk_tree_enable_src` instead.
|
||||
*/
|
||||
void esp_clk_tree_apll_acquire(void);
|
||||
|
||||
/**
|
||||
* @brief Shut down APLL power if no peripherals using APLL
|
||||
*
|
||||
* @note Do not use this function in applications or drivers, please use `esp_clk_tree_enable_src` instead.
|
||||
*/
|
||||
void esp_clk_tree_apll_release(void);
|
||||
|
||||
/**
|
||||
* @brief Calculate and set APLL coefficients by given frequency
|
||||
* @note This calculation is based on the inequality:
|
||||
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= CLK_LL_APLL_MULTIPLIER_MIN_HZ(350 MHz)
|
||||
* It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one.
|
||||
* which means more appropriate coefficients are likely to exist.
|
||||
* But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well.
|
||||
* @note The APLL frequency is only allowed to set when there is only one peripheral refer to it.
|
||||
* If APLL is already set by another peripheral, this function will return `ESP_ERR_INVALID_STATE`
|
||||
* and output the current frequency by parameter `real_freq`.
|
||||
*
|
||||
* @param expt_freq Expected APLL frequency (unit: Hz)
|
||||
* @param real_freq APLL real working frequency [output] (unit: Hz)
|
||||
* @return
|
||||
* - ESP_OK: APLL frequency set success
|
||||
* - ESP_ERR_INVALID_ARG: The input expt_freq is out of APLL support range
|
||||
* - ESP_ERR_INVALID_STATE: APLL is referred by more than one peripherals, not allowed to change its frequency now
|
||||
*/
|
||||
esp_err_t esp_clk_tree_apll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz);
|
||||
#endif // SOC_CLK_APLL_SUPPORTED
|
||||
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
/**
|
||||
* @brief Enable MPLL power if it has not enabled
|
||||
*
|
||||
* @note Do not use this function in applications or drivers, please use `esp_clk_tree_enable_src` instead.
|
||||
*/
|
||||
esp_err_t esp_clk_tree_mpll_acquire(void);
|
||||
|
||||
/**
|
||||
* @brief Shut down MPLL power if no peripherals using MPLL
|
||||
*
|
||||
* @note Do not use this function in applications or drivers, please use `esp_clk_tree_enable_src` instead.
|
||||
*/
|
||||
void esp_clk_tree_mpll_release(void);
|
||||
|
||||
/**
|
||||
* @brief Configure MPLL frequency
|
||||
* @note The MPLL frequency is only allowed to set when there is only one peripheral refer to it.
|
||||
* If MPLL is already set by another peripheral, this function will return `ESP_ERR_INVALID_STATE`
|
||||
* and output the current frequency by parameter `real_freq`.
|
||||
*
|
||||
* @param expt_freq Expected MPLL frequency (unit: Hz)
|
||||
* @param real_freq MPLL current working frequency [output] (unit: Hz)
|
||||
* @return
|
||||
* - ESP_OK: MPLL frequency set success
|
||||
* - ESP_ERR_INVALID_STATE: MPLL is referred by more than one peripherals, not allowed to change its frequency now
|
||||
*/
|
||||
esp_err_t esp_clk_tree_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz);
|
||||
#endif // SOC_CLK_MPLL_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -70,6 +75,26 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src");
|
||||
ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency");
|
||||
|
||||
uint32_t real_freq_value = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_APLL:
|
||||
ret = esp_clk_tree_apll_freq_set(expt_freq_value, &real_freq_value);
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (ret_freq_value) {
|
||||
*ret_freq_value = real_freq_value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -88,6 +113,41 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// APLL has its own reference counting
|
||||
if (clk_src == SOC_MOD_CLK_APLL) {
|
||||
if (enable) {
|
||||
esp_clk_tree_apll_acquire();
|
||||
} else {
|
||||
esp_clk_tree_apll_release();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -64,6 +69,12 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -82,6 +93,31 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -64,6 +69,12 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -82,6 +93,31 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
@@ -70,8 +72,13 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#define ENUM2ARRAY(clk_src) (clk_src - SOC_MOD_CLK_PLL_F12M)
|
||||
static int16_t s_pll_src_cg_ref_cnt[9] = { 0 };
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
static bool esp_clk_tree_initialized = false;
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
@@ -87,10 +94,10 @@ void esp_clk_tree_initialize(void)
|
||||
soc_cpu_clk_src_t current_cpu_clk_src = clk_ll_cpu_get_src();
|
||||
|
||||
if (current_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F160M) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(SOC_MOD_CLK_PLL_F160M)] = 1;
|
||||
s_pll_src_cg_ref_cnt[SOC_MOD_CLK_PLL_F160M] = 1;
|
||||
_clk_gate_ll_ref_240m_clk_en(false);
|
||||
} else if (current_cpu_clk_src == SOC_CPU_CLK_SRC_PLL_F240M) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(SOC_MOD_CLK_PLL_F240M)] = 1;
|
||||
s_pll_src_cg_ref_cnt[SOC_MOD_CLK_PLL_F240M] = 1;
|
||||
_clk_gate_ll_ref_160m_clk_en(false);
|
||||
}
|
||||
_clk_gate_ll_ref_120m_clk_en(false);
|
||||
@@ -117,38 +124,47 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
return ESP_OK; // TODO: PM-354
|
||||
}
|
||||
|
||||
#define ENABLE_CLK_GATE(clk_src_en_func, enable) \
|
||||
PERIPH_RCC_ATOMIC() { \
|
||||
clk_src_en_func(enable); \
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
if (!esp_clk_tree_initialized || (clk_src < SOC_MOD_CLK_PLL_F12M) || (clk_src > SOC_MOD_CLK_PLL_F240M)) {
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
if (!esp_clk_tree_initialized) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
if (enable) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]++;
|
||||
}
|
||||
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] == 1) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_PLL_F12M: clk_gate_ll_ref_12m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F20M: clk_gate_ll_ref_20m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F40M: clk_gate_ll_ref_40m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F48M: clk_gate_ll_ref_48m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F60M: clk_gate_ll_ref_60m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F80M: clk_gate_ll_ref_80m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F120M: clk_gate_ll_ref_120m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F160M: clk_gate_ll_ref_160m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F240M: clk_gate_ll_ref_240m_clk_en(enable); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (!enable) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]--;
|
||||
}
|
||||
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] < 0) {
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] = 0;
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST: enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable(); break;
|
||||
case SOC_MOD_CLK_PLL_F12M: ENABLE_CLK_GATE(clk_gate_ll_ref_12m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F20M: ENABLE_CLK_GATE(clk_gate_ll_ref_20m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F40M: ENABLE_CLK_GATE(clk_gate_ll_ref_40m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F48M: ENABLE_CLK_GATE(clk_gate_ll_ref_48m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F60M: ENABLE_CLK_GATE(clk_gate_ll_ref_60m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F80M: ENABLE_CLK_GATE(clk_gate_ll_ref_80m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F120M: ENABLE_CLK_GATE(clk_gate_ll_ref_120m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F160M: ENABLE_CLK_GATE(clk_gate_ll_ref_160m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F240M: ENABLE_CLK_GATE(clk_gate_ll_ref_240m_clk_en, enable); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#undef ENUM2ARRAY
|
||||
|
||||
@@ -459,7 +459,9 @@ FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void)
|
||||
#endif
|
||||
rtc_clk_cpu_freq_to_xtal(freq_mhz, 1);
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_clk_tree_enable_src(old_cpu_clk_src, false);
|
||||
if (old_cpu_clk_src != SOC_MOD_CLK_XTAL) {
|
||||
esp_clk_tree_enable_src(old_cpu_clk_src, false);
|
||||
}
|
||||
#endif
|
||||
s_cur_pll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -64,6 +69,12 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -82,6 +93,31 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -64,6 +69,12 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -82,6 +93,29 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -61,6 +66,12 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -79,6 +90,29 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,16 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
@@ -13,12 +14,12 @@
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/reset_reasons.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
@@ -103,8 +104,30 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#define ENUM2ARRAY(clk_src) (clk_src - SOC_MOD_CLK_PLL_F20M)
|
||||
static int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_PLL_F240M - SOC_MOD_CLK_PLL_F20M + 1] = { 0 };
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src");
|
||||
ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency");
|
||||
|
||||
uint32_t real_freq_value = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_APLL:
|
||||
ret = esp_clk_tree_apll_freq_set(expt_freq_value, &real_freq_value);
|
||||
break;
|
||||
case SOC_MOD_CLK_MPLL:
|
||||
ret = esp_clk_tree_mpll_freq_set(expt_freq_value, &real_freq_value);
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (ret_freq_value) {
|
||||
*ret_freq_value = real_freq_value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
static bool esp_clk_tree_initialized = false;
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
@@ -139,36 +162,67 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
return ESP_OK; // TODO: PM-354
|
||||
}
|
||||
|
||||
#define ENABLE_CLK_GATE(clk_src_en_func, enable) \
|
||||
PERIPH_RCC_ATOMIC() { \
|
||||
clk_src_en_func(enable); \
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
if (!esp_clk_tree_initialized || (clk_src < SOC_MOD_CLK_PLL_F20M) || (clk_src > SOC_MOD_CLK_PLL_F240M)) {
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
if (enable) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]++;
|
||||
}
|
||||
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] == 1) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_PLL_F20M: clk_gate_ll_ref_20m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F25M: clk_gate_ll_ref_25m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F50M: clk_gate_ll_ref_50m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F80M: clk_gate_ll_ref_80m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F120M: clk_gate_ll_ref_120m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F160M: clk_gate_ll_ref_160m_clk_en(enable); break;
|
||||
case SOC_MOD_CLK_PLL_F240M: clk_gate_ll_ref_240m_clk_en(enable); break;
|
||||
default: break;
|
||||
if (!esp_clk_tree_initialized) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// these clock sources have their own reference counting
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_APLL:
|
||||
if (enable) {
|
||||
esp_clk_tree_apll_acquire();
|
||||
} else {
|
||||
esp_clk_tree_apll_release();
|
||||
}
|
||||
}
|
||||
if (!enable) {
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]--;
|
||||
}
|
||||
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] < 0) {
|
||||
return ESP_OK;
|
||||
case SOC_MOD_CLK_MPLL:
|
||||
if (enable) {
|
||||
return esp_clk_tree_mpll_acquire();
|
||||
} else {
|
||||
esp_clk_tree_mpll_release();
|
||||
}
|
||||
return ESP_OK;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// other clock sources use the global reference counting
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] = 0;
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST: enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable(); break;
|
||||
case SOC_MOD_CLK_PLL_F20M: ENABLE_CLK_GATE(clk_gate_ll_ref_20m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F25M: ENABLE_CLK_GATE(clk_gate_ll_ref_25m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F50M: ENABLE_CLK_GATE(clk_gate_ll_ref_50m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F80M: ENABLE_CLK_GATE(clk_gate_ll_ref_80m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F120M: ENABLE_CLK_GATE(clk_gate_ll_ref_120m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F160M: ENABLE_CLK_GATE(clk_gate_ll_ref_160m_clk_en, enable); break;
|
||||
case SOC_MOD_CLK_PLL_F240M: ENABLE_CLK_GATE(clk_gate_ll_ref_240m_clk_en, enable); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#undef ENUM2ARRAY
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -68,6 +73,26 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src");
|
||||
ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency");
|
||||
|
||||
uint32_t real_freq_value = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_APLL:
|
||||
ret = esp_clk_tree_apll_freq_set(expt_freq_value, &real_freq_value);
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (ret_freq_value) {
|
||||
*ret_freq_value = real_freq_value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -86,6 +111,40 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// APLL has its own reference counting
|
||||
if (clk_src == SOC_MOD_CLK_APLL) {
|
||||
if (enable) {
|
||||
esp_clk_tree_apll_acquire();
|
||||
} else {
|
||||
esp_clk_tree_apll_release();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "esp_clk_tree");
|
||||
|
||||
static _Atomic int16_t s_pll_src_cg_ref_cnt[SOC_MOD_CLK_INVALID] = { 0 };
|
||||
|
||||
esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision,
|
||||
uint32_t *freq_value)
|
||||
{
|
||||
@@ -68,6 +73,18 @@ uint32_t *freq_value)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_src_set_freq_hz(soc_module_clk_t clk_src, uint32_t expt_freq_value, uint32_t *ret_freq_value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src");
|
||||
ESP_RETURN_ON_FALSE(expt_freq_value > 0, ESP_ERR_INVALID_ARG, TAG, "invalid frequency");
|
||||
|
||||
switch (clk_src) {
|
||||
default:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_clk_tree_initialize(void)
|
||||
{
|
||||
}
|
||||
@@ -86,6 +103,29 @@ esp_err_t esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool ena
|
||||
|
||||
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
|
||||
{
|
||||
(void)clk_src; (void)enable;
|
||||
if (clk_src < 1 || clk_src >= SOC_MOD_CLK_INVALID) {
|
||||
// some conditions is legal, e.g. -1 means external clock source
|
||||
return ESP_OK;
|
||||
}
|
||||
int16_t prev_ref_cnt = 0;
|
||||
if (enable) {
|
||||
prev_ref_cnt = atomic_fetch_add(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
} else {
|
||||
prev_ref_cnt = atomic_fetch_sub(&s_pll_src_cg_ref_cnt[clk_src], 1);
|
||||
if (prev_ref_cnt <= 0) {
|
||||
ESP_EARLY_LOGW(TAG, "soc_module_clk_t %d disabled multiple times!!", clk_src);
|
||||
atomic_store(&s_pll_src_cg_ref_cnt[clk_src], 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
|
||||
switch (clk_src) {
|
||||
case SOC_MOD_CLK_RC_FAST:
|
||||
enable ? rtc_dig_clk8m_enable() : rtc_dig_clk8m_disable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_private/critical_section.h"
|
||||
#include "hal/clk_tree_hal.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/rtc.h"
|
||||
@@ -12,7 +16,13 @@
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_hw_log.h"
|
||||
#include "esp_log.h"
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
#include "esp_private/rtc_clk.h"
|
||||
#include "esp_ldo_regulator.h"
|
||||
#endif
|
||||
|
||||
ESP_HW_LOG_ATTR_TAG(TAG, "esp_clk_tree_common");
|
||||
|
||||
@@ -201,3 +211,182 @@ uint32_t esp_clk_tree_lp_fast_get_freq_hz(esp_clk_tree_src_freq_precision_t prec
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_CLK_APLL_SUPPORTED
|
||||
// Current APLL frequency, in HZ. Zero if APLL is not enabled.
|
||||
static portMUX_TYPE __attribute__((unused)) s_periph_apll_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static uint32_t s_cur_apll_freq_hz = 0;
|
||||
static int s_apll_ref_cnt = 0;
|
||||
|
||||
// Pending APLL coefficients: calibration requires APLL to be powered on,
|
||||
// so if freq is set before acquire, we defer rtc_clk_apll_coeff_set until enable.
|
||||
static bool s_apll_coeff_pending = false;
|
||||
static uint32_t s_apll_pending_o_div = 0;
|
||||
static uint32_t s_apll_pending_sdm0 = 0;
|
||||
static uint32_t s_apll_pending_sdm1 = 0;
|
||||
static uint32_t s_apll_pending_sdm2 = 0;
|
||||
|
||||
void esp_clk_tree_apll_acquire(void)
|
||||
{
|
||||
bool apply_pending = false;
|
||||
uint32_t o_div, sdm0, sdm1, sdm2;
|
||||
|
||||
esp_os_enter_critical(&s_periph_apll_spinlock);
|
||||
s_apll_ref_cnt++;
|
||||
if (s_apll_ref_cnt == 1) {
|
||||
rtc_clk_apll_enable(true);
|
||||
if (s_apll_coeff_pending) {
|
||||
apply_pending = true;
|
||||
o_div = s_apll_pending_o_div;
|
||||
sdm0 = s_apll_pending_sdm0;
|
||||
sdm1 = s_apll_pending_sdm1;
|
||||
sdm2 = s_apll_pending_sdm2;
|
||||
s_apll_coeff_pending = false;
|
||||
}
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_apll_spinlock);
|
||||
|
||||
if (apply_pending) {
|
||||
rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_clk_tree_apll_release(void)
|
||||
{
|
||||
esp_os_enter_critical(&s_periph_apll_spinlock);
|
||||
assert(s_apll_ref_cnt > 0);
|
||||
s_apll_ref_cnt--;
|
||||
if (s_apll_ref_cnt == 0) {
|
||||
s_cur_apll_freq_hz = 0;
|
||||
s_apll_coeff_pending = false;
|
||||
rtc_clk_apll_enable(false);
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_apll_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t esp_clk_tree_apll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz)
|
||||
{
|
||||
uint32_t o_div = 0;
|
||||
uint32_t sdm0 = 0;
|
||||
uint32_t sdm1 = 0;
|
||||
uint32_t sdm2 = 0;
|
||||
|
||||
uint32_t apll_freq = rtc_clk_apll_coeff_calc(expt_freq_hz, &o_div, &sdm0, &sdm1, &sdm2);
|
||||
ESP_RETURN_ON_FALSE(apll_freq, ESP_ERR_INVALID_ARG, TAG, "APLL coefficients calculate failed");
|
||||
bool need_config = true;
|
||||
bool apll_enabled = false;
|
||||
esp_os_enter_critical(&s_periph_apll_spinlock);
|
||||
/* If APLL is not in use or only one peripheral in use, its frequency can be changed as will
|
||||
* But when more than one peripheral refers APLL, its frequency is not allowed to change once it is set */
|
||||
if (s_cur_apll_freq_hz == 0 || s_apll_ref_cnt < 2) {
|
||||
s_cur_apll_freq_hz = apll_freq;
|
||||
apll_enabled = (s_apll_ref_cnt > 0);
|
||||
if (!apll_enabled) {
|
||||
// APLL not yet powered on, defer coeff_set (which includes calibration) until acquire
|
||||
s_apll_coeff_pending = true;
|
||||
s_apll_pending_o_div = o_div;
|
||||
s_apll_pending_sdm0 = sdm0;
|
||||
s_apll_pending_sdm1 = sdm1;
|
||||
s_apll_pending_sdm2 = sdm2;
|
||||
}
|
||||
} else {
|
||||
apll_freq = s_cur_apll_freq_hz;
|
||||
need_config = false;
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_apll_spinlock);
|
||||
if (real_freq_hz != NULL) {
|
||||
*real_freq_hz = apll_freq;
|
||||
}
|
||||
if (need_config) {
|
||||
ESP_LOGD(TAG, "APLL works at %"PRIu32" Hz with coefficients [sdm0] %"PRIu32" [sdm1] %"PRIu32" [sdm2] %"PRIu32" [o_div] %"PRIu32"",
|
||||
apll_freq, sdm0, sdm1, sdm2, o_div);
|
||||
if (apll_enabled) {
|
||||
rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2);
|
||||
}
|
||||
} else {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* SOC_CLK_APLL_SUPPORTED */
|
||||
|
||||
#if SOC_CLK_MPLL_SUPPORTED
|
||||
static portMUX_TYPE __attribute__((unused)) s_periph_mpll_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static uint32_t s_cur_mpll_freq_hz = 0;
|
||||
static int s_mpll_ref_cnt = 0;
|
||||
#if CONFIG_ESP_LDO_RESERVE_PSRAM
|
||||
static esp_ldo_channel_handle_t s_ldo_chan = NULL;
|
||||
#endif
|
||||
|
||||
esp_err_t IRAM_ATTR esp_clk_tree_mpll_acquire(void)
|
||||
{
|
||||
// power up LDO for the MPLL
|
||||
#if CONFIG_ESP_LDO_RESERVE_PSRAM
|
||||
if (s_ldo_chan == NULL) {
|
||||
esp_ldo_channel_config_t ldo_mpll_config = {
|
||||
.chan_id = CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN,
|
||||
.voltage_mv = CONFIG_ESP_LDO_VOLTAGE_PSRAM_DOMAIN,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_acquire_channel(&ldo_mpll_config, &s_ldo_chan), TAG, "acquire internal LDO for MPLL failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_os_enter_critical(&s_periph_mpll_spinlock);
|
||||
s_mpll_ref_cnt++;
|
||||
if (s_mpll_ref_cnt == 1) {
|
||||
// For the first time enable MPLL, need to set power up
|
||||
rtc_clk_mpll_enable();
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_mpll_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_clk_tree_mpll_release(void)
|
||||
{
|
||||
bool __attribute__((unused)) release_ldo = false;
|
||||
esp_os_enter_critical(&s_periph_mpll_spinlock);
|
||||
assert(s_mpll_ref_cnt > 0);
|
||||
s_mpll_ref_cnt--;
|
||||
if (s_mpll_ref_cnt == 0) {
|
||||
s_cur_mpll_freq_hz = 0;
|
||||
rtc_clk_mpll_disable();
|
||||
release_ldo = true;
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_mpll_spinlock);
|
||||
|
||||
#if defined(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN) && CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN != -1
|
||||
if (release_ldo && s_ldo_chan) {
|
||||
esp_ldo_release_channel(s_ldo_chan);
|
||||
s_ldo_chan = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR esp_clk_tree_mpll_freq_set(uint32_t expt_freq_hz, uint32_t *real_freq_hz)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
// Guarantee 'esp_clk_tree_mpll_acquire' has been called before set mpll freq
|
||||
assert(s_mpll_ref_cnt > 0);
|
||||
|
||||
esp_os_enter_critical(&s_periph_mpll_spinlock);
|
||||
if (s_cur_mpll_freq_hz == expt_freq_hz) {
|
||||
goto end;
|
||||
}
|
||||
/* If MPLL is not in use or only one peripheral in use, its frequency can be changed as will
|
||||
* But when more than one peripheral refers MPLL, its frequency is not allowed to change once it is set */
|
||||
if (s_cur_mpll_freq_hz == 0 || s_mpll_ref_cnt < 2) {
|
||||
uint32_t xtal_freq_mhz = clk_hal_xtal_get_freq_mhz();
|
||||
rtc_clk_mpll_configure(xtal_freq_mhz, expt_freq_hz / MHZ, false);
|
||||
s_cur_mpll_freq_hz = clk_ll_mpll_get_freq_mhz(xtal_freq_mhz) * MHZ;
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
end:
|
||||
if (real_freq_hz != NULL) {
|
||||
*real_freq_hz = s_cur_mpll_freq_hz;
|
||||
}
|
||||
esp_os_exit_critical(&s_periph_mpll_spinlock);
|
||||
return ret;
|
||||
}
|
||||
#endif /* SOC_CLK_MPLL_SUPPORTED */
|
||||
|
||||
Reference in New Issue
Block a user