refactor(clk_tree): use general api to enable the clk

This commit is contained in:
Chen Jichang
2026-03-27 11:18:44 +08:00
parent 54ecf4c09f
commit 6e206dd173
57 changed files with 1180 additions and 694 deletions
+2 -30
View File
@@ -36,9 +36,7 @@
#if SOC_I2C_SUPPORT_APB || SOC_I2C_SUPPORT_XTAL
#include "esp_private/esp_clk.h"
#endif
#if SOC_I2C_SUPPORT_RTC
#include "clk_ctrl_os.h"
#endif
#include "esp_private/esp_clk_tree_common.h"
static const char *I2C_TAG = "i2c";
@@ -740,34 +738,8 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
static uint32_t s_get_src_clk_freq(i2c_clock_source_t clk_src)
{
// TODO: replace the following switch table by clk_tree API
uint32_t periph_src_clk_hz = 0;
switch (clk_src) {
#if SOC_I2C_SUPPORT_APB
case I2C_CLK_SRC_APB:
periph_src_clk_hz = esp_clk_apb_freq();
break;
#endif
#if SOC_I2C_SUPPORT_XTAL
case I2C_CLK_SRC_XTAL:
periph_src_clk_hz = esp_clk_xtal_freq();
break;
#endif
#if SOC_I2C_SUPPORT_RTC
case I2C_CLK_SRC_RC_FAST:
periph_rtc_dig_clk8m_enable();
periph_src_clk_hz = periph_rtc_dig_clk8m_get_freq();
break;
#endif
#if SOC_I2C_SUPPORT_REF_TICK
case I2C_CLK_SRC_REF_TICK:
periph_src_clk_hz = REF_CLK_FREQ;
break;
#endif
default:
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, I2C_TAG, "clock source %d is not supported", clk_src);
break;
}
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz);
return periph_src_clk_hz;
}
-1
View File
@@ -18,7 +18,6 @@
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_clk_tree.h"
#include "clk_ctrl_os.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"
#include "esp_private/gpio.h"
+13 -11
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,7 +9,7 @@
#include "driver/dac_cosine.h"
#include "hal/clk_tree_ll.h"
#include "dac_priv_common.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#if CONFIG_DAC_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
@@ -57,13 +57,10 @@ esp_err_t dac_cosine_new_channel(const dac_cosine_config_t *cos_cfg, dac_cosine_
/* Register the handle */
ESP_GOTO_ON_ERROR(dac_priv_register_channel(cos_cfg->chan_id, "dac cosine"), err1, TAG, "register dac channel %d failed", cos_cfg->chan_id);
/* Only enabled for getting the correct rtc clock frequency */
periph_rtc_dig_clk8m_enable();
/* Cosine wave generator uses RTC_FAST clock which is divided from RC_FAST */
// [clk_tree] TODO: replace the following calculation with the RTC_FAST frequency getter
uint32_t rtc_clk_freq = periph_rtc_dig_clk8m_get_freq() / clk_ll_rc_fast_get_divider();
/* Disabled after getting the frequency, will re-enabled again when start outputting cosine wave */
periph_rtc_dig_clk8m_disable();
uint32_t rtc_clk_freq = 0;
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_RC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rtc_clk_freq);
if (rtc_clk_freq == 0) {
ESP_LOGW(TAG, "RTC clock calibration failed, using the approximate value as default");
rtc_clk_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
@@ -106,13 +103,14 @@ esp_err_t dac_cosine_del_channel(dac_cosine_handle_t handle)
esp_err_t dac_cosine_start(dac_cosine_handle_t handle)
{
esp_err_t ret = ESP_OK;
DAC_NULL_POINTER_CHECK(handle);
ESP_RETURN_ON_FALSE(!handle->is_started, ESP_ERR_INVALID_STATE, TAG,
"the dac channel has already started");
/* Acquire the RTC clock */
periph_rtc_dig_clk8m_enable();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_RC_FAST, true), TAG, "RC_FAST clock enable failed");
/* Enabled DAC channel */
ESP_RETURN_ON_ERROR(dac_priv_enable_channel(handle->cfg.chan_id), TAG,
ESP_GOTO_ON_ERROR(dac_priv_enable_channel(handle->cfg.chan_id), err, TAG,
"enable dac channel %d failed", handle->cfg.chan_id);
/* Enabled the cosine wave generator if no channel using it before */
DAC_RTC_ENTER_CRITICAL();
@@ -126,6 +124,10 @@ esp_err_t dac_cosine_start(dac_cosine_handle_t handle)
DAC_RTC_EXIT_CRITICAL();
return ESP_OK;
err:
esp_clk_tree_enable_src(SOC_MOD_CLK_RC_FAST, false);
return ret;
}
esp_err_t dac_cosine_stop(dac_cosine_handle_t handle)
@@ -148,7 +150,7 @@ esp_err_t dac_cosine_stop(dac_cosine_handle_t handle)
handle->is_started = false;
DAC_RTC_EXIT_CRITICAL();
/* Release the RTC clock */
periph_rtc_dig_clk8m_disable();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_RC_FAST, false), TAG, "RC_FAST clock disable failed");
return ESP_OK;
}
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -22,7 +22,7 @@
#include "../dac_priv_dma.h"
#include "esp_private/i2s_platform.h"
#include "esp_private/esp_clk.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#if CONFIG_DAC_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
@@ -56,7 +56,7 @@ static uint32_t s_dac_set_apll_freq(uint32_t mclk)
uint32_t expt_freq = mclk * div;
/* Set APLL coefficients to the given frequency */
uint32_t real_freq = 0;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
esp_err_t ret = esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, expt_freq, &real_freq);
if (ret == ESP_ERR_INVALID_ARG) {
return 0;
}
@@ -120,7 +120,7 @@ esp_err_t dac_dma_periph_init(uint32_t freq_hz, bool is_alternate, bool is_apll)
s_ddp->periph_dev = (void *)I2S_LL_GET_HW(DAC_DMA_PERIPH_I2S_NUM);
if (is_apll) {
periph_rtc_apll_acquire();
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true), err, TAG, "APLL enable failed");
s_ddp->use_apll = true;
}
ESP_GOTO_ON_ERROR(s_dac_dma_periph_set_clock(freq_hz, is_apll), err, TAG, "Failed to set clock of DMA peripheral");
@@ -157,7 +157,7 @@ esp_err_t dac_dma_periph_deinit(void)
ESP_RETURN_ON_ERROR(i2s_platform_release_occupation(I2S_CTLR_HP, DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to release DAC DMA peripheral");
i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF | I2S_LL_EVENT_TX_TEOF, false);
if (s_ddp->use_apll) {
periph_rtc_apll_release();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false), TAG, "APLL disable failed");
s_ddp->use_apll = false;
}
free(s_ddp);
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -25,7 +25,7 @@
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "../dac_priv_dma.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#if CONFIG_DAC_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
@@ -52,7 +52,7 @@ static uint32_t s_dac_set_apll_freq(uint32_t expt_freq)
{
/* Set APLL coefficients to the given frequency */
uint32_t real_freq = 0;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
esp_err_t ret = esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, expt_freq, &real_freq);
if (ret == ESP_ERR_INVALID_ARG) {
return 0;
}
@@ -138,7 +138,7 @@ esp_err_t dac_dma_periph_init(uint32_t freq_hz, bool is_alternate, bool is_apll)
s_ddp->periph_dev = (void *)SPI_LL_GET_HW(DAC_DMA_PERIPH_SPI_HOST);
if (is_apll) {
periph_rtc_apll_acquire();
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true), err, TAG, "APLL enable failed");
s_ddp->use_apll = true;
}
/* When transmit alternately, twice frequency is needed to guarantee the convert frequency in one channel */
@@ -167,7 +167,7 @@ esp_err_t dac_dma_periph_deinit(void)
adc_apb_periph_free();
if (s_ddp) {
if (s_ddp->use_apll) {
periph_rtc_apll_release();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false), TAG, "APLL disable failed");
s_ddp->use_apll = false;
}
free(s_ddp);
+1 -12
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -160,7 +160,6 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
// initialize HAL layer
timer_hal_init(&timer->hal, group_id, timer_id);
// select clock source, set clock resolution
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)config->clk_src, true), err, TAG, "clock source enable failed");
ESP_GOTO_ON_ERROR(gptimer_select_periph_clock(timer, config->clk_src, config->resolution_hz), err, TAG, "set periph clock failed");
// initialize counter value to zero
timer_hal_set_counter_value(&timer->hal, 0);
@@ -195,7 +194,6 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer)
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(atomic_load(&timer->fsm) == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
gptimer_group_t *group = timer->group;
gptimer_clock_source_t clk_src = timer->clk_src;
int group_id = group->group_id;
int timer_id = timer->timer_id;
timer_hal_context_t *hal = &timer->hal;
@@ -208,15 +206,6 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer)
// recycle memory resource
ESP_RETURN_ON_ERROR(gptimer_destroy(timer), TAG, "destroy gptimer failed");
switch (clk_src) {
#if TIMER_LL_FUNC_CLOCK_SUPPORT_RC_FAST
case GPTIMER_CLK_SRC_RC_FAST:
periph_rtc_dig_clk8m_disable();
break;
#endif // TIMER_LL_FUNC_CLOCK_SUPPORT_RC_FAST
default:
break;
}
return ESP_OK;
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -91,14 +91,7 @@ esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t s
uint32_t counter_src_hz = 0;
int timer_id = timer->timer_id;
int group_id = timer->group->group_id;
// TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
#if TIMER_LL_FUNC_CLOCK_SUPPORT_RC_FAST
if (src_clk == GPTIMER_CLK_SRC_RC_FAST) {
// RC_FAST clock is not enabled automatically on start up, we enable it here manually.
// Note there's a ref count in the enable/disable function, we must call them in pair in the driver.
periph_rtc_dig_clk8m_enable();
}
#endif // TIMER_LL_FUNC_CLOCK_SUPPORT_RC_FAST
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(src_clk, true), TAG, "clock source enable failed");
timer->clk_src = src_clk;
// get clock source frequency
@@ -27,7 +27,7 @@
#include "hal/timer_types.h"
#include "hal/timer_hal.h"
#include "hal/timer_ll.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/sleep_retention.h"
#include "esp_private/periph_ctrl.h"
+4 -19
View File
@@ -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
*/
@@ -25,7 +25,7 @@
#include "soc/clk_tree_defs.h"
#include "hal/i2c_periph.h"
#include "esp_clk_tree.h"
#include "clk_ctrl_os.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/gpio.h"
#include "esp_private/esp_gpio_reserve.h"
#if SOC_LP_I2C_SUPPORTED
@@ -233,15 +233,7 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus)
}
_lock_release(&s_i2c_platform.mutex);
switch (clk_src) {
#if SOC_I2C_SUPPORT_RTC
case I2C_CLK_SRC_RC_FAST:
periph_rtc_dig_clk8m_disable();
break;
#endif // SOC_I2C_SUPPORT_RTC
default:
break;
}
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(clk_src, false), TAG, "clock source clock disable failed");
if (do_deinitialize) {
ESP_LOGD(TAG, "delete bus %d", port_num);
@@ -268,14 +260,7 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, soc_module_clk_t clk_
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_STATE, TAG,
"group clock conflict, already is %d but attempt to %d", handle->clk_src, clk_src);
// TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
#if SOC_I2C_SUPPORT_RTC
if (clk_src == (soc_module_clk_t)I2C_CLK_SRC_RC_FAST) {
// RC_FAST clock is not enabled automatically on start up, we enable it here manually.
// Note there's a ref count in the enable/disable function, we must call them in pair in the driver.
periph_rtc_dig_clk8m_enable();
}
#endif // SOC_I2C_SUPPORT_RTC
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(clk_src, true), TAG, "clock source clock enable failed");
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &periph_src_clk_hz), TAG, "i2c get clock frequency error");
+1
View File
@@ -305,6 +305,7 @@ esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave
i2c_ll_set_slave_addr(hal->dev, slave_config->slave_addr, false);
i2c_ll_set_tout(hal->dev, I2C_LL_MAX_TIMEOUT);
ESP_GOTO_ON_ERROR(i2c_select_periph_clock(i2c_slave->base, slave_config->clk_source), err, TAG, "select periph clock failed");
PERIPH_RCC_ATOMIC() {
i2c_ll_set_source_clk(hal->dev, slave_config->clk_source);
}
+31 -30
View File
@@ -36,7 +36,6 @@
#endif
#if SOC_I2S_SUPPORTS_APLL
#include "hal/clk_tree_ll.h"
#include "clk_ctrl_os.h"
#endif
#include "esp_private/i2s_platform.h"
@@ -55,7 +54,6 @@
#include "esp_clock_output.h"
#endif
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_intr_alloc.h"
@@ -319,9 +317,6 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
new_chan->role = I2S_ROLE_MASTER; // Set default role to master
new_chan->dir = dir;
new_chan->state = I2S_CHAN_STATE_REGISTER;
#if SOC_I2S_SUPPORTS_APLL
new_chan->apll_en = false;
#endif
new_chan->mode_info = NULL;
new_chan->controller = i2s_obj;
#if CONFIG_PM_ENABLE
@@ -580,7 +575,7 @@ static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
return 0;
}
uint32_t real_freq = 0;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
esp_err_t ret = esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, expt_freq, &real_freq);
if (ret == ESP_ERR_INVALID_ARG) {
ESP_LOGE(TAG, "set APLL freq failed due to invalid argument");
return 0;
@@ -1029,7 +1024,6 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
i2s_obj->tx_chan->start = i2s_tx_channel_start;
i2s_obj->tx_chan->stop = i2s_tx_channel_stop;
*tx_handle = i2s_obj->tx_chan;
esp_clk_tree_enable_src((soc_module_clk_t)i2s_ll_tx_clk_get_src(i2s_obj->hal.dev), true);
ESP_LOGD(TAG, "tx channel is registered on I2S%d successfully", i2s_obj->id);
}
/* Register and specify the rx handle */
@@ -1044,7 +1038,6 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
i2s_obj->rx_chan->start = i2s_rx_channel_start;
i2s_obj->rx_chan->stop = i2s_rx_channel_stop;
*rx_handle = i2s_obj->rx_chan;
esp_clk_tree_enable_src((soc_module_clk_t)i2s_ll_rx_clk_get_src(i2s_obj->hal.dev), true);
ESP_LOGD(TAG, "rx channel is registered on I2S%d successfully", i2s_obj->id);
}
@@ -1081,6 +1074,20 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
i2s_dir_t __attribute__((unused)) dir = handle->dir;
bool is_bound = true;
#if SOC_I2S_SUPPORTS_APLL
/* Must switch back to D2CLK on ESP32-S2,
* because the clock of some registers are bound to APLL,
* otherwise, once APLL is disabled, the registers can't be updated anymore
* NOTE: even this limitation is only applicable to ESP32-S2, switch back to Default clock does not harm for other chips */
PERIPH_RCC_ATOMIC() {
if (handle->dir == I2S_DIR_TX) {
i2s_ll_tx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT);
} else {
i2s_ll_rx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT);
}
}
#endif
#if SOC_I2S_HW_VERSION_2
PERIPH_RCC_ATOMIC() {
if (dir == I2S_DIR_TX) {
@@ -1089,33 +1096,20 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
i2s_ll_rx_disable_clock(handle->controller->hal.dev);
}
}
if (handle->clk_src != I2S_CLK_SRC_EXTERNAL)
#endif
{
// disable clock source
i2s_clock_src_t clk_src = handle->clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (clk_src == I2S_CLK_SRC_DEFAULT) {
clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
// since the enum value of default clock on some chips may be 0, we use mode to check if the clock is enabled
if (handle->mode != I2S_COMM_MODE_NONE) {
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
}
#if SOC_I2S_SUPPORTS_APLL
if (handle->apll_en) {
/* Must switch back to D2CLK on ESP32-S2,
* because the clock of some registers are bound to APLL,
* otherwise, once APLL is disabled, the registers can't be updated anymore */
PERIPH_RCC_ATOMIC() {
if (handle->dir == I2S_DIR_TX) {
i2s_ll_tx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT);
} else {
i2s_ll_rx_clk_set_src(handle->controller->hal.dev, I2S_CLK_SRC_DEFAULT);
}
}
periph_rtc_apll_release();
}
#endif
#if CONFIG_PM_ENABLE
if (handle->pm_lock) {
esp_pm_lock_delete(handle->pm_lock);
@@ -1442,6 +1436,8 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
esp_err_t i2s_channel_tune_rate(i2s_chan_handle_t handle, const i2s_tuning_config_t *tune_cfg, i2s_tuning_info_t *tune_info)
{
esp_err_t ret = ESP_OK;
/** We tune the sample rate via the MCLK clock.
* Because the sample rate is decided by MCLK eventually,
* and MCLK has a higher resolution which can be tuned more precisely.
@@ -1480,11 +1476,11 @@ esp_err_t i2s_channel_tune_rate(i2s_chan_handle_t handle, const i2s_tuning_confi
new_mclk = handle->origin_mclk_hz + tune_cfg->min_delta_mclk;
}
xSemaphoreTake(handle->mutex, portMAX_DELAY);
#if SOC_CLK_APLL_SUPPORTED
#if SOC_I2S_SUPPORTS_APLL
if (handle->clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false), err, TAG, "APLL disable failed");
handle->sclk_hz = i2s_set_get_apll_freq(new_mclk);
periph_rtc_apll_acquire();
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true), err, TAG, "APLL enable failed");
}
#endif
/* Calculate the new divider */
@@ -1492,7 +1488,8 @@ esp_err_t i2s_channel_tune_rate(i2s_chan_handle_t handle, const i2s_tuning_confi
i2s_hal_calc_mclk_precise_division(handle->sclk_hz, new_mclk, &mclk_div);
/* mclk_div = sclk / mclk >= 2 */
if (mclk_div.integer < 2) {
return ESP_ERR_INVALID_ARG;
ret = ESP_ERR_INVALID_ARG;
goto err;
}
/* Set the new divider for MCLK */
PERIPH_RCC_ATOMIC() {
@@ -1526,7 +1523,11 @@ result:
tune_info->water_mark = used_size * 100 / tot_size;
}
xSemaphoreGive(handle->mutex);
return ESP_OK;
return ret;
err:
xSemaphoreGive(handle->mutex);
return ret;
}
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
+56 -73
View File
@@ -20,7 +20,6 @@
#include "driver/i2s_pdm.h"
#include "i2s_private.h"
#include "esp_private/esp_clk_tree_common.h"
#include "clk_ctrl_os.h"
#include "esp_intr_alloc.h"
#include "esp_check.h"
@@ -79,23 +78,18 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
#endif
ESP_RETURN_ON_FALSE(clk_cfg->up_sample_fs <= 480, ESP_ERR_INVALID_ARG, TAG, "up_sample_fs should be within 480");
i2s_hal_clock_info_t clk_info;
/* Calculate clock parameters */
ESP_RETURN_ON_ERROR(i2s_pdm_tx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
#if SOC_I2S_HW_VERSION_2
i2s_clock_src_t old_clk_src = handle->clk_src;
if (clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL)
#endif
{
i2s_clock_src_t clk_src = clk_cfg->clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (clk_src == I2S_CLK_SRC_DEFAULT) {
clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
}
i2s_hal_clock_info_t clk_info;
// Calculate clock parameters before enabling clock source
ESP_RETURN_ON_ERROR(i2s_pdm_tx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
hal_utils_clk_div_t ret_mclk_div = {};
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
@@ -110,7 +104,7 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
portEXIT_CRITICAL(&g_i2s.spinlock);
uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator;
ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result");
ESP_GOTO_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid mclk division result");
/* Update the mode info: clock configuration */
memcpy(&(pdm_tx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_tx_clk_config_t));
@@ -120,16 +114,14 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
handle->curr_mclk_hz = handle->origin_mclk_hz;
handle->bclk_hz = clk_info.bclk;
#if SOC_I2S_HW_VERSION_2
if (old_clk_src != I2S_CLK_SRC_EXTERNAL) {
esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false);
}
#endif
ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
clk_info.sclk, ret_mclk_div.integer, ret_mclk_div.numerator, ret_mclk_div.denominator, handle->origin_mclk_hz, clk_info.bclk_div, clk_info.bclk);
return ret;
err:
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
return ret;
}
static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg)
@@ -238,13 +230,6 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t
* while initializing, because clock and gpio is relay on the slot */
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_slot(handle, &pdm_tx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, &pdm_tx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is APLL */
if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
@@ -287,23 +272,20 @@ esp_err_t i2s_channel_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && pdm_tx_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
handle->apll_en = false;
i2s_clock_src_t old_clk_src = pdm_tx_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
#ifdef CONFIG_PM_ENABLE
// Create/Re-create power management lock
if (pdm_tx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
if (old_clk_src != clk_cfg->clk_src) {
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
@@ -345,7 +327,15 @@ esp_err_t i2s_channel_reconfig_pdm_tx_slot(i2s_chan_handle_t handle, const i2s_p
/* If the slot bit width changed, then need to update the clock */
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
if (pdm_tx_cfg->slot_cfg.slot_bit_width != slot_bits) {
i2s_clock_src_t old_clk_src = pdm_tx_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
}
xSemaphoreGive(handle->mutex);
@@ -435,23 +425,20 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
ESP_RETURN_ON_FALSE(clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL, ESP_ERR_INVALID_ARG, TAG, "not support external clock source in pdm mode");
#endif
i2s_hal_clock_info_t clk_info;
/* Calculate clock parameters */
ESP_RETURN_ON_ERROR(i2s_pdm_rx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
#if SOC_I2S_HW_VERSION_2
i2s_clock_src_t old_clk_src = handle->clk_src;
if (clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL)
#endif
{
i2s_clock_src_t clk_src = clk_cfg->clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (clk_src == I2S_CLK_SRC_DEFAULT) {
clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
}
i2s_hal_clock_info_t clk_info;
/* Calculate clock parameters before enabling clock source, so that APLL frequency
* can be set while ref_cnt is still < 2 (which is the threshold for freq change) */
ESP_RETURN_ON_ERROR(i2s_pdm_rx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
hal_utils_clk_div_t ret_mclk_div = {};
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
@@ -461,7 +448,7 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
portEXIT_CRITICAL(&g_i2s.spinlock);
uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator;
ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result");
ESP_GOTO_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid mclk division result");
/* Update the mode info: clock configuration */
memcpy(&(pdm_rx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_rx_clk_config_t));
@@ -471,16 +458,14 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
handle->curr_mclk_hz = handle->origin_mclk_hz;
handle->bclk_hz = clk_info.bclk;
#if SOC_I2S_HW_VERSION_2
if (old_clk_src != I2S_CLK_SRC_EXTERNAL) {
esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false);
}
#endif
ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
clk_info.sclk, ret_mclk_div.integer, ret_mclk_div.numerator, ret_mclk_div.denominator, handle->origin_mclk_hz, clk_info.bclk_div, clk_info.bclk);
return ret;
err:
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
return ret;
}
static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg)
@@ -590,13 +575,6 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
/* i2s_set_pdm_rx_slot should be called before i2s_set_pdm_rx_clock and i2s_pdm_rx_set_gpio while initializing, because clock is relay on the slot */
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, &pdm_rx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, &pdm_rx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is APLL */
if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
@@ -639,23 +617,20 @@ esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && pdm_rx_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
handle->apll_en = false;
i2s_clock_src_t old_clk_src = pdm_rx_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
#ifdef CONFIG_PM_ENABLE
// Create/Re-create power management lock
if (pdm_rx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
if (old_clk_src != clk_cfg->clk_src) {
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
@@ -697,7 +672,15 @@ esp_err_t i2s_channel_reconfig_pdm_rx_slot(i2s_chan_handle_t handle, const i2s_p
/* If the slot bit width changed, then need to update the clock */
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
if (pdm_rx_cfg->slot_cfg.slot_bit_width != slot_bits) {
i2s_clock_src_t old_clk_src = pdm_rx_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
}
xSemaphoreGive(handle->mutex);
-3
View File
@@ -155,9 +155,6 @@ struct i2s_channel_obj_t {
bool is_raw_pdm: 1; /*!< Flag of whether send/receive PDM in raw data, i.e., no PCM2PDM/PDM2PCM filter enabled */
bool is_external: 1; /*!< Whether use external clock */
bool full_duplex_slave: 1; /*!< whether the channel is forced to switch to slave role for full duplex */
#if SOC_I2S_SUPPORTS_APLL
bool apll_en: 1; /*!< Flag of whether APLL enabled */
#endif
};
uint32_t active_slot; /*!< Active slot number */
uint32_t total_slot; /*!< Total slot number */
+28 -37
View File
@@ -21,7 +21,6 @@
#include "driver/i2s_std.h"
#include "i2s_private.h"
#include "esp_private/esp_clk_tree_common.h"
#include "clk_ctrl_os.h"
#include "esp_intr_alloc.h"
#include "esp_check.h"
@@ -82,23 +81,18 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
(clk_cfg->mclk_multiple % 3 == 0), ESP_ERR_INVALID_ARG, TAG,
"The 'mclk_multiple' should be the multiple of 3 while using 24-bit data width");
i2s_hal_clock_info_t clk_info;
/* Calculate clock parameters */
ESP_RETURN_ON_ERROR(i2s_std_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
#if SOC_I2S_HW_VERSION_2
i2s_clock_src_t old_clk_src = handle->clk_src;
if (clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL)
#endif
{
i2s_clock_src_t clk_src = clk_cfg->clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (clk_src == I2S_CLK_SRC_DEFAULT) {
clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
}
i2s_hal_clock_info_t clk_info;
// Calculate clock parameters before enabling clock source
ESP_RETURN_ON_ERROR(i2s_std_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
hal_utils_clk_div_t ret_mclk_div = {};
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
@@ -111,7 +105,7 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
}
portEXIT_CRITICAL(&g_i2s.spinlock);
uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator;
ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result");
ESP_GOTO_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid mclk division result");
/* Update the mode info: clock configuration */
memcpy(&(std_cfg->clk_cfg), clk_cfg, sizeof(i2s_std_clk_config_t));
@@ -121,16 +115,14 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
handle->curr_mclk_hz = handle->origin_mclk_hz;
handle->bclk_hz = clk_info.bclk;
#if SOC_I2S_HW_VERSION_2
if (old_clk_src != I2S_CLK_SRC_EXTERNAL) {
esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false);
}
#endif
ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
clk_info.sclk, ret_mclk_div.integer, ret_mclk_div.numerator, ret_mclk_div.denominator, handle->origin_mclk_hz, clk_info.bclk_div, clk_info.bclk);
return ret;
err:
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
return ret;
}
static i2s_std_slot_config_t s_i2s_std_normalize_slot_config(const i2s_std_slot_config_t *slot_cfg)
@@ -345,13 +337,6 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
#endif
/* i2s_set_std_slot should be called before i2s_set_std_clock while initializing, because clock is relay on the slot */
ESP_GOTO_ON_ERROR(i2s_std_set_slot(handle, &std_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is APLL */
if (std_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
#endif
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, &std_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
/* i2s_std_set_gpio should be called after i2s_std_set_clock as mclk relies on the clock source */
ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, &std_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
@@ -403,23 +388,21 @@ esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std
i2s_std_config_t *std_cfg = (i2s_std_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(std_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && std_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && std_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
handle->apll_en = false;
i2s_clock_src_t old_clk_src = std_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
#ifdef CONFIG_PM_ENABLE
// Create/Re-create power management lock
if (std_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
if (old_clk_src != clk_cfg->clk_src) {
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
@@ -460,7 +443,15 @@ esp_err_t i2s_channel_reconfig_std_slot(i2s_chan_handle_t handle, const i2s_std_
/* If the slot bit width changed, then need to update the clock */
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
if (std_cfg->slot_cfg.slot_bit_width != slot_bits) {
i2s_clock_src_t old_clk_src = std_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, &std_cfg->clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
}
xSemaphoreGive(handle->mutex);
+27 -37
View File
@@ -21,7 +21,6 @@
#include "driver/i2s_tdm.h"
#include "i2s_private.h"
#include "esp_private/esp_clk_tree_common.h"
#include "clk_ctrl_os.h"
#include "esp_intr_alloc.h"
#include "esp_check.h"
@@ -79,23 +78,18 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
esp_err_t ret = ESP_OK;
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t *)(handle->mode_info);
i2s_hal_clock_info_t clk_info;
/* Calculate clock parameters */
ESP_RETURN_ON_ERROR(i2s_tdm_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
#if SOC_I2S_HW_VERSION_2
i2s_clock_src_t old_clk_src = handle->clk_src;
if (clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL)
#endif
{
i2s_clock_src_t clk_src = clk_cfg->clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (clk_src == I2S_CLK_SRC_DEFAULT) {
clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
}
i2s_hal_clock_info_t clk_info;
// Calculate clock parameters before enabling clock source
ESP_RETURN_ON_ERROR(i2s_tdm_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
hal_utils_clk_div_t ret_mclk_div = {};
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
@@ -108,7 +102,7 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
}
portEXIT_CRITICAL(&g_i2s.spinlock);
uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator;
ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result");
ESP_GOTO_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid mclk division result");
/* Update the mode info: clock configuration */
memcpy(&(tdm_cfg->clk_cfg), clk_cfg, sizeof(i2s_tdm_clk_config_t));
@@ -118,16 +112,14 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
handle->curr_mclk_hz = handle->origin_mclk_hz;
handle->bclk_hz = clk_info.bclk;
#if SOC_I2S_HW_VERSION_2
if (old_clk_src != I2S_CLK_SRC_EXTERNAL) {
esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false);
}
#endif
ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
clk_info.sclk, ret_mclk_div.integer, ret_mclk_div.numerator, ret_mclk_div.denominator, handle->origin_mclk_hz, clk_info.bclk_div, clk_info.bclk);
return ret;
err:
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
return ret;
}
static i2s_tdm_slot_config_t s_i2s_tdm_normalize_slot_config(const i2s_tdm_slot_config_t *slot_cfg)
@@ -327,13 +319,6 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
s_i2s_channel_try_to_constitude_tdm_duplex(handle, tdm_cfg);
/* i2s_set_tdm_slot should be called before i2s_set_tdm_clock while initializing, because clock is relay on the slot */
ESP_GOTO_ON_ERROR(i2s_tdm_set_slot(handle, &tdm_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is APLL */
if (tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
#endif
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, &tdm_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
/* i2s_tdm_set_gpio should be called after i2s_tdm_set_clock as mclk relies on the clock source */
ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, &tdm_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
@@ -384,24 +369,21 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t *)handle->mode_info;
ESP_GOTO_ON_FALSE(tdm_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
periph_rtc_apll_acquire();
handle->apll_en = true;
}
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
handle->apll_en = false;
i2s_clock_src_t old_clk_src = tdm_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
#ifdef CONFIG_PM_ENABLE
// Create/Re-create power management lock
if (tdm_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
if (old_clk_src != clk_cfg->clk_src) {
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
@@ -442,7 +424,15 @@ esp_err_t i2s_channel_reconfig_tdm_slot(i2s_chan_handle_t handle, const i2s_tdm_
/* If the slot bit width changed, then need to update the clock */
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
if (tdm_cfg->slot_cfg.slot_bit_width != slot_bits) {
i2s_clock_src_t old_clk_src = tdm_cfg->clk_cfg.clk_src;
#ifdef I2S_LL_DEFAULT_CLK_SRC
if (old_clk_src == I2S_CLK_SRC_DEFAULT) {
old_clk_src = I2S_LL_DEFAULT_CLK_SRC;
}
#endif
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, &tdm_cfg->clk_cfg), err, TAG, "update clock failed");
// disable old clock source after new clock is successfully configured
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)old_clk_src, false), err, TAG, "clock source disable failed");
}
/* Reset queue */
+4 -6
View File
@@ -17,7 +17,6 @@
#include "soc/soc_caps.h"
#include "hal/ledc_hal.h"
#include "driver/ledc.h"
#include "clk_ctrl_os.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/periph_ctrl.h"
#include "driver/gpio.h"
@@ -162,8 +161,10 @@ static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channe
//We know that RC_FAST is about 8M/20M, but don't know the actual value. So we need to do a calibration.
static bool ledc_slow_clk_calibrate(void)
{
if (periph_rtc_dig_clk8m_enable()) {
s_ledc_slow_clk_rc_fast_freq = periph_rtc_dig_clk8m_get_freq();
if (esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_RC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &s_ledc_slow_clk_rc_fast_freq) != ESP_OK) {
ESP_LOGE(LEDC_TAG, "Calibrate RC_FAST_CLK failed");
return false;
}
#if !SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
/* Workaround: RC_FAST calibration cannot be performed, we can only use its theoretic freq */
ESP_LOGD(LEDC_TAG, "Calibration cannot be performed, approximate RC_FAST_CLK : %"PRIu32" Hz", s_ledc_slow_clk_rc_fast_freq);
@@ -172,9 +173,6 @@ static bool ledc_slow_clk_calibrate(void)
#endif
return true;
}
ESP_LOGE(LEDC_TAG, "Calibrate RC_FAST_CLK failed");
return false;
}
static void _ledc_fade_hw_acquire(ledc_mode_t mode, ledc_channel_t channel)
{
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h"
#include "parlio_priv.h"
+10 -26
View File
@@ -1,11 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "rmt_private.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "soc/rtc.h"
#include "driver/gpio.h"
@@ -81,7 +81,6 @@ rmt_group_t *rmt_acquire_group_handle(int group_id)
void rmt_release_group_handle(rmt_group_t *group)
{
int group_id = group->group_id;
rmt_clock_source_t clk_src = group->clk_src;
bool do_deinitialize = false;
rmt_hal_context_t *hal = &group->hal;
@@ -103,16 +102,6 @@ void rmt_release_group_handle(rmt_group_t *group)
}
_lock_release(&s_platform.mutex);
switch (clk_src) {
#if RMT_LL_SUPPORT(RC_FAST)
case RMT_CLK_SRC_RC_FAST:
periph_rtc_dig_clk8m_disable();
break;
#endif // RMT_LL_SUPPORT(RC_FAST)
default:
break;
}
if (do_deinitialize) {
#if RMT_USE_RETENTION_LINK
sleep_retention_module_t module = rmt_reg_retention_info[group_id].module;
@@ -195,18 +184,9 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
clock_selection_conflict = (group->clk_src != clk_src);
}
portEXIT_CRITICAL(&group->spinlock);
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_ARG, TAG,
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_STATE, TAG,
"group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
// TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
#if RMT_LL_SUPPORT(RC_FAST)
if (clk_src == RMT_CLK_SRC_RC_FAST) {
// RC_FAST clock is not enabled automatically on start up, we enable it here manually.
// Note there's a ref count in the enable/disable function, we must call them in pair in the driver.
periph_rtc_dig_clk8m_enable();
}
#endif // RMT_LL_SUPPORT(RC_FAST)
#if CONFIG_PM_ENABLE
// if DMA is not used, we're using CPU to push the data to the RMT FIFO
// if the CPU frequency goes down, the transfer+encoding scheme could be unstable because CPU can't fill the data in time
@@ -224,8 +204,8 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
#if RMT_LL_GET(CHANNEL_CLK_INDEPENDENT)
uint32_t periph_src_clk_hz = 0;
// get clock source frequency
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz),
TAG, "get clock source frequency failed");
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz),
err, TAG, "get clock source frequency failed");
PERIPH_RCC_ATOMIC() {
rmt_ll_set_group_clock_src(group->hal.regs, chan->channel_id, clk_src, 1, 1, 0);
rmt_ll_enable_group_clock(group->hal.regs, true);
@@ -235,7 +215,7 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
real_div = (group->resolution_hz + expect_channel_resolution / 2) / expect_channel_resolution;
#else
// set division for group clock source, to achieve highest resolution while guaranteeing the channel resolution.
ESP_RETURN_ON_ERROR(rmt_set_group_prescale(chan, expect_channel_resolution, &real_div), TAG, "set rmt group prescale failed");
ESP_GOTO_ON_ERROR(rmt_set_group_prescale(chan, expect_channel_resolution, &real_div), err, TAG, "set rmt group prescale failed");
#endif // RMT_LL_GET(CHANNEL_CLK_INDEPENDENT)
if (chan->direction == RMT_CHANNEL_DIRECTION_TX) {
@@ -249,6 +229,10 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
ESP_LOGW(TAG, "channel resolution loss, real=%"PRIu32, chan->resolution_hz);
}
return ret;
err:
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
return ret;
}
esp_err_t rmt_get_channel_id(rmt_channel_handle_t channel, int *ret_id)
+3
View File
@@ -318,9 +318,12 @@ static esp_err_t rmt_del_rx_channel(rmt_channel_handle_t channel)
rmt_group_t *group = channel->group;
int group_id = group->group_id;
int channel_id = channel->channel_id;
soc_module_clk_t clk_src = (soc_module_clk_t)group->clk_src;
ESP_LOGD(TAG, "del rx channel(%d,%d)", group_id, channel_id);
// recycle memory resource
ESP_RETURN_ON_ERROR(rmt_rx_destroy(rx_chan), TAG, "destroy rx channel failed");
// disable the clock source at last
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(clk_src, false), TAG, "clock source disable failed");
return ESP_OK;
}
+3
View File
@@ -377,9 +377,12 @@ static esp_err_t rmt_del_tx_channel(rmt_channel_handle_t channel)
rmt_group_t *group = channel->group;
int group_id = group->group_id;
int channel_id = channel->channel_id;
soc_module_clk_t clk_src = (soc_module_clk_t)group->clk_src;
ESP_LOGD(TAG, "del tx channel(%d,%d)", group_id, channel_id);
// recycle memory resource
ESP_RETURN_ON_ERROR(rmt_tx_destroy(tx_chan), TAG, "destroy tx channel failed");
// disable the clock source at last
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(clk_src, false), TAG, "clock source disable failed");
return ESP_OK;
}
@@ -118,7 +118,7 @@ We have two bits to control the interrupt:
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/cache_utils.h"
#include "driver/spi_master.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_ipc.h"
@@ -450,9 +450,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
uint32_t clock_source_hz = 0;
uint32_t clock_source_div = 1;
spi_clock_source_t clk_src = dev_config->clock_source ? dev_config->clock_source : SPI_CLK_SRC_DEFAULT;
if ((soc_module_clk_t)clk_src == SOC_MOD_CLK_RC_FAST) {
SPI_CHECK(periph_rtc_dig_clk8m_enable(), "the selected clock not available", ESP_ERR_INVALID_STATE);
}
SPI_CHECK(esp_clk_tree_enable_src(clk_src, true) == ESP_OK, "clock source enable failed", ESP_ERR_INVALID_STATE);
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_source_hz);
#if SPI_LL_SRC_PRE_DIV_MAX
@@ -613,7 +610,6 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
}
spi_device_release_bus(handle);
}
periph_rtc_dig_clk8m_disable();
}
SPI_CHECK(esp_clk_tree_enable_src(handle->hal_dev.timing_conf.clock_source, false) == ESP_OK, "clock source disable failed", ESP_ERR_INVALID_STATE);
@@ -19,7 +19,7 @@
#include "esp_check.h"
#include "esp_types.h"
#include "esp_heap_caps.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "freertos/FreeRTOS.h"
#include "driver/temperature_sensor.h"
#include "esp_private/periph_ctrl.h"
@@ -242,11 +242,7 @@ esp_err_t temperature_sensor_enable(temperature_sensor_handle_t tsens)
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "tsens not in init state");
#if SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
if (tsens->clk_src == TEMPERATURE_SENSOR_CLK_SRC_RC_FAST) {
periph_rtc_dig_clk8m_enable();
}
#endif
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(tsens->clk_src, true), TAG, "clock source enable failed");
#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
temperature_sensor_ll_wakeup_enable(true);
@@ -271,13 +267,10 @@ esp_err_t temperature_sensor_disable(temperature_sensor_handle_t tsens)
temperature_sensor_ll_sample_enable(false);
#endif
#if SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
if (tsens->clk_src == TEMPERATURE_SENSOR_CLK_SRC_RC_FAST) {
periph_rtc_dig_clk8m_disable();
}
#endif
tsens->fsm = TEMP_SENSOR_FSM_INIT;
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(tsens->clk_src, false), TAG, "clock source disable failed");
return ESP_OK;
}
-21
View File
@@ -39,7 +39,6 @@
#include "soc/lp_gpio_pins.h"
#endif
#endif
#include "clk_ctrl_os.h"
#include "esp_pm.h"
#ifdef CONFIG_UART_ISR_IN_IRAM
@@ -1087,11 +1086,6 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
// Enable the newly selected clock source
esp_clk_tree_enable_src(uart_sclk_sel, true);
#if SOC_UART_SUPPORT_RTC_CLK
if (uart_sclk_sel == (soc_module_clk_t)UART_SCLK_RTC) {
periph_rtc_dig_clk8m_enable();
}
#endif
bool success = false;
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
@@ -2139,11 +2133,6 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) {
esp_clk_tree_enable_src(uart_context[uart_num].sclk_sel, false);
#if SOC_UART_SUPPORT_RTC_CLK
if (uart_context[uart_num].sclk_sel == (soc_module_clk_t)UART_SCLK_RTC) {
periph_rtc_dig_clk8m_disable();
}
#endif
uart_context[uart_num].sclk_sel = -1;
}
@@ -2348,11 +2337,6 @@ esp_err_t uart_detect_bitrate_start(uart_port_t uart_num, const uart_bitrate_det
uint32_t sclk_freq = 0;
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(uart_sclk_sel, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sclk_freq), err, UART_TAG, "invalid source_clk");
esp_clk_tree_enable_src(uart_sclk_sel, true);
#if SOC_UART_SUPPORT_RTC_CLK
if (uart_sclk_sel == (soc_module_clk_t)UART_SCLK_RTC) {
periph_rtc_dig_clk8m_enable();
}
#endif
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
PERIPH_RCC_ATOMIC() {
uart_hal_set_sclk(&(uart_context[uart_num].hal), uart_sclk_sel);
@@ -2436,11 +2420,6 @@ esp_err_t uart_detect_bitrate_stop(uart_port_t uart_num, bool deinit, uart_bitra
uart_release_pin(uart_num, true, true, true, true, true, true);
if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) {
esp_clk_tree_enable_src(uart_context[uart_num].sclk_sel, false);
#if SOC_UART_SUPPORT_RTC_CLK
if (src_clk == (soc_module_clk_t)UART_SCLK_RTC) {
periph_rtc_dig_clk8m_disable();
}
#endif
uart_context[uart_num].sclk_sel = -1;
}
uart_module_disable(uart_num);
+7 -7
View File
@@ -31,7 +31,7 @@
#include "hal/emac_hal.h"
#include "soc/soc.h"
#include "hal/emac_periph.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "sdkconfig.h"
#include "esp_rom_sys.h"
#include "esp_private/eth_mac_esp_dma.h"
@@ -486,18 +486,18 @@ static esp_err_t emac_config_pll_clock(emac_esp32_t *emac)
#if SOC_EMAC_REF_CLK_FROM_APLL
// the RMII reference comes from the APLL
periph_rtc_apll_acquire();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true), TAG, "APLL enable failed");
emac->use_pll = true;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
esp_err_t ret = esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, expt_freq, &real_freq);
ESP_RETURN_ON_FALSE(ret != ESP_ERR_INVALID_ARG, ESP_FAIL, TAG, "Set APLL clock coefficients failed");
if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "APLL is occupied already, it is working at %" PRIu32 " Hz", real_freq);
}
#elif SOC_EMAC_REF_CLK_FROM_MPLL
// the RMII reference comes from the MPLL
periph_rtc_mpll_acquire();
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, true), TAG, "MPLL enable failed");
emac->use_pll = true;
esp_err_t ret = periph_rtc_mpll_freq_set(expt_freq * 2, &real_freq); // cannot set 50MHz at MPLL, the nearest possible freq is 100 MHz
esp_err_t ret = esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_MPLL, expt_freq * 2, &real_freq); // cannot set 50MHz at MPLL, the nearest possible freq is 100 MHz
if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "MPLL is occupied already, it is working at %" PRIu32 " Hz", real_freq);
ESP_LOGW(TAG, "Trying to derive RMII clock to be %" PRIu32 " Hz...", RMII_CLK_HZ);
@@ -671,9 +671,9 @@ static void emac_esp_free_driver_obj(emac_esp32_t *emac)
if (emac->use_pll) {
#if CONFIG_IDF_TARGET_ESP32
periph_rtc_apll_release();
esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false);
#elif CONFIG_IDF_TARGET_ESP32P4
periph_rtc_mpll_release();
esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, false);
#endif
}
#ifdef CONFIG_IDF_TARGET_ESP32
@@ -16,7 +16,7 @@
#include "esp_log.h"
#include "esp_eth_test_utils.h"
#include "hal/emac_hal.h" // for MAC_HAL_TDES0_* control bits
#include "clk_ctrl_os.h"
#include "esp_private/esp_clk_tree_common.h"
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via _transmit_frame
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via _transmit_multiple_buf_frame (2 buffers)
@@ -615,37 +615,37 @@ TEST_CASE("internal emac MPLL shared with PSRAM", "[esp_emac_clk_out][skip_setup
// PSRAM default speed: MPLL at 400 MHz — EMAC divider 8 gives exactly 50 MHz
ESP_LOGI(TAG, "Verify MPLL at 400 MHz (simulating PSRAM default)");
TEST_ESP_OK(periph_rtc_mpll_acquire());
TEST_ESP_OK(periph_rtc_mpll_freq_set(400 * 1000000, &real_freq));
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, true));
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_MPLL, 400 * 1000000, &real_freq));
ESP_LOGI(TAG, "MPLL set to %" PRIu32 " Hz", real_freq);
mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
TEST_ASSERT_NOT_NULL(mac);
TEST_ESP_OK(mac->del(mac));
periph_rtc_mpll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, false));
// PSRAM 250M speed: MPLL at 500 MHz — EMAC divider 10 gives exactly 50 MHz
ESP_LOGI(TAG, "Verify MPLL at 500 MHz (simulating PSRAM @ 250M speed)");
TEST_ESP_OK(periph_rtc_mpll_acquire());
TEST_ESP_OK(periph_rtc_mpll_freq_set(500 * 1000000, &real_freq));
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, true));
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_MPLL, 500 * 1000000, &real_freq));
ESP_LOGI(TAG, "MPLL set to %" PRIu32 " Hz", real_freq);
mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
TEST_ASSERT_NOT_NULL(mac);
TEST_ESP_OK(mac->del(mac));
periph_rtc_mpll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, false));
// PSRAM 80M speed: MPLL at 320 MHz — no integer divider can produce 50 MHz within tolerance,
// see AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ for reference
// Best candidate: 320/6 = 53.33 MHz (error ~3.33 MHz >> 2500 Hz tolerance)
ESP_LOGI(TAG, "Verify MPLL at 320 MHz (simulating PSRAM @ 80M speed) — expected to fail");
TEST_ESP_OK(periph_rtc_mpll_acquire());
TEST_ESP_OK(periph_rtc_mpll_freq_set(320 * 1000000, &real_freq));
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, true));
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_MPLL, 320 * 1000000, &real_freq));
ESP_LOGI(TAG, "MPLL set to %" PRIu32 " Hz", real_freq);
mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
TEST_ASSERT_NULL(mac);
periph_rtc_mpll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_MPLL, false));
}
#endif // SOC_EMAC_REF_CLK_FROM_MPLL
@@ -669,24 +669,24 @@ TEST_CASE("internal emac APLL shared with I2S", "[esp_emac_clk_out][skip_setup_t
// Another peripheral has APLL at 50 MHz — exact RMII clock match, EMAC should succeed
ESP_LOGI(TAG, "Verify APLL at 50 MHz (exact RMII clock match)");
periph_rtc_apll_acquire();
TEST_ESP_OK(periph_rtc_apll_freq_set(50 * 1000000, &real_freq));
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true));
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, 50 * 1000000, &real_freq));
ESP_LOGI(TAG, "APLL set to %" PRIu32 " Hz", real_freq);
mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
TEST_ASSERT_NOT_NULL(mac);
TEST_ESP_OK(mac->del(mac));
periph_rtc_apll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false));
// I2S typical frequency: APLL at ~12.288 MHz (48 kHz * 256) — far from 50 MHz, EMAC should fail
ESP_LOGI(TAG, "Verify APLL at ~12.288 MHz (simulating I2S @ 48 kHz) — expected to fail");
periph_rtc_apll_acquire();
TEST_ESP_OK(periph_rtc_apll_freq_set(12288000, &real_freq));
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true));
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, 12288000, &real_freq));
ESP_LOGI(TAG, "APLL set to %" PRIu32 " Hz", real_freq);
mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
TEST_ASSERT_NULL(mac);
periph_rtc_apll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false));
}
#endif // SOC_EMAC_REF_CLK_FROM_APLL
@@ -81,8 +81,8 @@
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#ifdef __cplusplus
extern "C" {
@@ -60,8 +60,8 @@
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
@@ -55,8 +55,8 @@
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
@@ -52,8 +52,8 @@
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'esp_clk_tree_apll_freq_set' for the calculation
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 7, \
@@ -9,6 +9,7 @@
#include "unity.h"
#include "test_regi2c.h"
#include "esp_private/regi2c_ctrl.h"
#include "esp_private/esp_clk_tree_common.h"
#include "sdkconfig.h"
TEST_CASE("regi2c basic read/write test", "[regi2c]")
@@ -19,7 +20,7 @@ TEST_CASE("regi2c basic read/write test", "[regi2c]")
#if CONFIG_IDF_TARGET_ESP32
// For ESP32, we need to enable the APLL clock before accessing the APLL regi2c registers
periph_rtc_apll_acquire();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, true));
#endif
/* ---- Part 1: full-register read / write ---- */
@@ -91,6 +92,6 @@ TEST_CASE("regi2c basic read/write test", "[regi2c]")
#if CONFIG_IDF_TARGET_ESP32
// Disable APLL clock
periph_rtc_apll_release();
TEST_ESP_OK(esp_clk_tree_enable_src(SOC_MOD_CLK_APLL, false));
#endif
}
@@ -25,7 +25,6 @@ extern "C" {
#if CONFIG_IDF_TARGET_ESP32
#include "clk_ctrl_os.h"
#include "soc/regi2c_apll.h"
#define TEST_BLOCK I2C_APLL
#define TEST_HOST_ID I2C_APLL_HOSTID
+17 -162
View File
@@ -1,211 +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;
#endif
#if CONFIG_ESP_LDO_RESERVE_PSRAM
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_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(&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
+10 -10
View File
@@ -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
*/
@@ -119,6 +119,72 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable);
*/
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
return false; // TODO: PM-653
}
#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() {
int16_t prev_ref_cnt = 0;
if (enable) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]++;
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 (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] == 1) {
}
if ((prev_ref_cnt == 0 && enable) || (prev_ref_cnt == 1 && !enable)) {
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;
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;
}
}
if (!enable) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]--;
}
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] < 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;
}
}
return ESP_OK;
}
#undef ENUM2ARRAY
@@ -448,7 +448,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
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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,16 +5,21 @@
*/
#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)
{
@@ -60,6 +65,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;
}
static int16_t s_xtal_x2_ref_cnt = 0;
static int16_t s_bbpll_ref_cnt = 0;
@@ -139,8 +150,26 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
{
PERIPH_RCC_ATOMIC() {
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;
case SOC_MOD_CLK_XTAL_X2_F64M:
// later, here should handle ref count for XTAL_X2_F64M clock gating, then also handle XTAL_X2 circuit enable/disable
esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable);
@@ -154,5 +183,5 @@ esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
break;
}
}
return ESP_OK; // TODO: PM-653
return ESP_OK;
}
@@ -1,20 +1,25 @@
/*
* 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");
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)
{
@@ -63,9 +68,14 @@ 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;
}
static int16_t s_xtal_x2_ref_cnt = 0;
static int16_t s_bbpll_ref_cnt = 0;
void esp_clk_tree_initialize(void)
{
// Power
@@ -142,8 +152,26 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
esp_err_t esp_clk_tree_enable_src(soc_module_clk_t clk_src, bool enable)
{
PERIPH_RCC_ATOMIC() {
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;
case SOC_MOD_CLK_XTAL_X2_F32M:
// later, here should handle ref count for XTAL_X2_F32M clock gating, then also handle XTAL_X2 circuit enable/disable
esp_clk_tree_enable_power(SOC_ROOT_CIRCUIT_CLK_XTAL_X2, enable);
@@ -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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
return false; // TODO: PM-653
}
#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 (!esp_clk_tree_initialized) {
return ESP_OK;
}
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] == 1) {
// these clock sources have their own reference counting
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;
case SOC_MOD_CLK_APLL:
if (enable) {
esp_clk_tree_apll_acquire();
} else {
esp_clk_tree_apll_release();
}
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);
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;
}
}
if (!enable) {
s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)]--;
}
if (s_pll_src_cg_ref_cnt[ENUM2ARRAY(clk_src)] < 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;
}
}
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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 @@ bool esp_clk_tree_enable_power(soc_root_clk_circuit_t clk_circuit, bool enable)
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;
}
@@ -80,6 +80,13 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr
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)
{
/* TODO: [ESP32S31] IDF-14733 */
(void)clk_src; (void)expt_freq_value; (void)ret_freq_value;
return ESP_ERR_NOT_SUPPORTED;
}
static int16_t s_cpll_ref_cnt = 0;
void esp_clk_tree_initialize(void)
@@ -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 */
+6 -1
View File
@@ -133,6 +133,7 @@ struct esp_rgb_panel_t {
gpio_num_t data_gpio_nums[LCD_LL_GET(RGB_BUS_WIDTH)]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
uint64_t gpio_reserve_mask; // GPIOs reserved by this panel, used to revoke the GPIO reservation when the panel is deleted
uint32_t src_clk_hz; // Peripheral source clock resolution
lcd_clock_source_t clk_src; // Peripheral clock source
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels
size_t bb_eof_count; // record the number we received the DMA EOF event, compare with `expect_eof_count` in the VSYNC_END ISR
@@ -241,6 +242,9 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
PERIPH_RCC_ATOMIC() {
lcd_ll_enable_clock(rgb_panel->hal.dev, false);
}
if (rgb_panel->clk_src) {
esp_clk_tree_enable_src(rgb_panel->clk_src, false);
}
if (rgb_panel->panel_id >= 0) {
PERIPH_RCC_RELEASE_ATOMIC(soc_lcd_rgb_signals[rgb_panel->panel_id].module, ref_count) {
if (ref_count == 0) {
@@ -891,10 +895,11 @@ static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_
{
// get clock source frequency
uint32_t src_clk_hz = 0;
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
rgb_panel->clk_src = clk_src;
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz),
TAG, "get clock source frequency failed");
rgb_panel->src_clk_hz = src_clk_hz;
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
PERIPH_RCC_ATOMIC() {
lcd_ll_select_clk_src(rgb_panel->hal.dev, clk_src);
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,6 +16,7 @@
#include "esp_attr.h"
#include "test_rgb_board.h"
#include "esp_private/spi_flash_os.h"
#include "esp_clk_tree.h"
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
#define TEST_LCD_CALLBACK_ATTR IRAM_ATTR
@@ -25,7 +26,7 @@
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
static esp_lcd_panel_handle_t test_rgb_panel_initialization(size_t data_width, lcd_color_format_t in_color_format, size_t bb_pixels, bool refresh_on_demand, bool user_fb,
static esp_lcd_panel_handle_t test_rgb_panel_initialization(size_t data_width, lcd_color_format_t in_color_format, size_t bb_pixels, lcd_clock_source_t clk_src, bool refresh_on_demand, bool user_fb,
esp_lcd_rgb_panel_vsync_cb_t vsync_cb, void *user_data)
{
esp_lcd_panel_handle_t panel_handle = NULL;
@@ -34,7 +35,7 @@ static esp_lcd_panel_handle_t test_rgb_panel_initialization(size_t data_width, l
.in_color_format = in_color_format,
.dma_burst_size = 64,
.bounce_buffer_size_px = bb_pixels,
.clk_src = LCD_CLK_SRC_DEFAULT,
.clk_src = clk_src,
.disp_gpio_num = TEST_LCD_DISP_EN_GPIO,
.pclk_gpio_num = TEST_LCD_PCLK_GPIO,
.vsync_gpio_num = TEST_LCD_VSYNC_GPIO,
@@ -97,7 +98,7 @@ TEST_CASE("lcd_rgb_panel_stream_mode", "[lcd]")
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, false, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
@@ -119,7 +120,7 @@ TEST_CASE("lcd_rgb_panel_8bit_interface", "[lcd]")
printf("initialize RGB panel with stream mode\r\n");
// bpp for RGB888 is 24
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(8, LCD_COLOR_FMT_RGB888, 0, false, false, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(8, LCD_COLOR_FMT_RGB888, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
uint8_t color_byte = esp_random() & 0xFF;
printf("flush random color block 0x%x\r\n", color_byte);
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
@@ -147,7 +148,7 @@ TEST_CASE("lcd_rgb_panel_refresh_on_demand", "[lcd]")
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
printf("initialize RGB panel with non-stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, true, false, test_rgb_panel_trans_done, cur_task);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, true, false, test_rgb_panel_trans_done, cur_task);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
@@ -172,7 +173,7 @@ TEST_CASE("lcd_rgb_panel_bounce_buffer", "[lcd]")
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
printf("initialize RGB panel with non-stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 20 * TEST_LCD_H_RES, false, false, test_rgb_panel_trans_done, cur_task);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 20 * TEST_LCD_H_RES, LCD_CLK_SRC_DEFAULT, false, false, test_rgb_panel_trans_done, cur_task);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
@@ -195,7 +196,7 @@ TEST_CASE("lcd_rgb_panel_update_pclk", "[lcd]")
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, false, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
printf("flush one clock block to the LCD\r\n");
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
@@ -223,7 +224,7 @@ TEST_CASE("lcd_rgb_panel_restart", "[lcd]")
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, false, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
printf("flush one clock block to the LCD\r\n");
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
@@ -253,7 +254,7 @@ TEST_CASE("lcd_rgb_panel_rotate", "[lcd]")
memset(img, color_byte, w * h * sizeof(uint16_t));
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, false, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
printf("Update the rotation of panel\r\n");
for (size_t i = 0; i < 8; i++) {
@@ -278,7 +279,7 @@ TEST_CASE("lcd_rgb_panel_user_frame_buffer", "[lcd]")
TEST_ASSERT_NOT_NULL(img);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, true, NULL, NULL);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, true, NULL, NULL);
printf("flush one clock block to the LCD\r\n");
uint8_t color_byte = esp_random() & 0xFF;
@@ -300,6 +301,34 @@ TEST_CASE("lcd_rgb_panel_user_frame_buffer", "[lcd]")
free(user_frame_buffer);
}
#if SOC_CLK_APLL_SUPPORTED
TEST_CASE("lcd_rgb_panel_use_apll", "[lcd]")
{
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
printf("set APLL frequency\r\n");
uint32_t real_freq = 0;
TEST_ESP_OK(esp_clk_tree_src_set_freq_hz(SOC_MOD_CLK_APLL, 160 * 1000 * 1000, &real_freq));
printf("APLL frequency: %"PRIu32" Hz\r\n", real_freq);
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_APLL, false, false, NULL, NULL);
printf("flush random color block\r\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
vTaskDelay(pdMS_TO_TICKS(10));
}
printf("delete RGB panel\r\n");
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
free(img);
}
#endif // SOC_CLK_APLL_SUPPORTED
#if CONFIG_LCD_RGB_ISR_IRAM_SAFE
TEST_LCD_CALLBACK_ATTR static bool test_rgb_panel_count_in_callback(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)
{
@@ -325,7 +354,7 @@ TEST_CASE("lcd_rgb_panel_iram_safe", "[lcd]")
uint32_t callback_calls = 0;
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, false, false, test_rgb_panel_count_in_callback, &callback_calls);
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, test_rgb_panel_count_in_callback, &callback_calls);
printf("flush one clock block to the LCD\r\n");
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
@@ -14,8 +14,9 @@
#include "esp_private/esp_psram_ldo.h"
#include "hal/psram_ctrlr_ll.h"
#include "hal/mspi_ll.h"
#include "clk_ctrl_os.h"
#include "soc/rtc.h"
#include "esp_check.h"
#include "esp_private/esp_clk_tree_common.h"
#define AP_HEX_PSRAM_SYNC_READ 0x0000
#define AP_HEX_PSRAM_SYNC_WRITE 0x8080
@@ -418,9 +419,10 @@ static void s_configure_psram_ecc(void)
esp_err_t esp_psram_impl_enable(void)
{
#if SOC_CLK_MPLL_SUPPORTED
periph_rtc_mpll_acquire();
// We need to use the acquire and freq_set functions directly instead of general clk_tree API for IRAM safe function
esp_clk_tree_mpll_acquire();
uint32_t real_mpll_freq = 0;
periph_rtc_mpll_freq_set(AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ * 1000000, &real_mpll_freq);
esp_clk_tree_mpll_freq_set(AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ * 1000000, &real_mpll_freq);
ESP_EARLY_LOGD(TAG, "real_mpll_freq: %d", real_mpll_freq);
#endif
@@ -6,15 +6,16 @@
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_clk_tree.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/mspi_timing_tuning.h"
#include "esp_private/esp_psram_impl.h"
#include "esp_private/esp_psram_ldo.h"
#include "hal/psram_ctrlr_ll.h"
#include "hal/mspi_ll.h"
#include "clk_ctrl_os.h"
#include "soc/rtc.h"
#define AP_OCT_PSRAM_SYNC_READ 0x0000
@@ -419,9 +420,10 @@ esp_err_t esp_psram_impl_enable(void)
esp_psram_power_init(&config);
#endif
#if SOC_CLK_MPLL_SUPPORTED
periph_rtc_mpll_acquire();
// We need to use the acquire and freq_set functions directly instead of general clk_tree API for IRAM safe function
esp_clk_tree_mpll_acquire();
uint32_t real_mpll_freq = 0;
periph_rtc_mpll_freq_set(AP_OCT_PSRAM_MPLL_DEFAULT_FREQ_MHZ * 1000000, &real_mpll_freq);
esp_clk_tree_mpll_freq_set(AP_OCT_PSRAM_MPLL_DEFAULT_FREQ_MHZ * 1000000, &real_mpll_freq);
ESP_EARLY_LOGD(TAG, "real_mpll_freq: %d", real_mpll_freq);
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -225,14 +225,14 @@ typedef enum {
/**
* @brief Array initializer for all supported clock sources of Temperature Sensor
*/
#define SOC_TEMP_SENSOR_CLKS {SOC_MOD_CLK_TEMP_SENSOR}
#define SOC_TEMP_SENSOR_CLKS {SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of Temp Sensor clock source
*/
typedef enum {
TEMPERATURE_SENSOR_CLK_SRC_RC_FAST = SOC_MOD_CLK_TEMP_SENSOR, /*!< Select RC_FAST as the source clock */
TEMPERATURE_SENSOR_CLK_SRC_DEFAULT = SOC_MOD_CLK_TEMP_SENSOR, /*!< Select RC_FAST as the default choice */
TEMPERATURE_SENSOR_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
TEMPERATURE_SENSOR_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default choice */
} soc_periph_temperature_sensor_clk_src_t;
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -244,14 +244,14 @@ typedef enum {
/**
* @brief Array initializer for all supported clock sources of Temperature Sensor
*/
#define SOC_TEMP_SENSOR_CLKS {SOC_MOD_CLK_TEMP_SENSOR}
#define SOC_TEMP_SENSOR_CLKS {SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of Temp Sensor clock source
*/
typedef enum {
TEMPERATURE_SENSOR_CLK_SRC_RC_FAST = SOC_MOD_CLK_TEMP_SENSOR, /*!< Select RC_FAST as the source clock */
TEMPERATURE_SENSOR_CLK_SRC_DEFAULT = SOC_MOD_CLK_TEMP_SENSOR, /*!< Select RC_FAST as the default choice */
TEMPERATURE_SENSOR_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
TEMPERATURE_SENSOR_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default choice */
} soc_periph_temperature_sensor_clk_src_t;
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
+1 -9
View File
@@ -24,7 +24,7 @@
#include "bootloader_flash.h"
#include "esp_check.h"
#include "esp_private/esp_clk_tree_common.h"
#include "clk_ctrl_os.h"
#include "esp_clk_tree.h"
#include "soc/soc_caps.h"
#include "hal/spi_flash_hal.h"
#include "hal/mspi_ll.h"
@@ -287,9 +287,6 @@ static uint32_t init_gpspi_clock(esp_flash_t *chip, const esp_flash_spi_device_c
uint32_t clk_src_freq = 0;
spi_clock_source_t clk_src = config->clock_source ? config->clock_source : SPI_CLK_SRC_DEFAULT;
if ((soc_module_clk_t)clk_src == SOC_MOD_CLK_RC_FAST) {
periph_rtc_dig_clk8m_enable();
}
esp_clk_tree_enable_src(clk_src, true);
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq);
@@ -356,11 +353,6 @@ static void deinit_gpspi_clock(esp_flash_t *chip)
// Disable the clock source
esp_clk_tree_enable_src(chip->clock_source, false);
// Disable RC_FAST clock if it was used
if ((soc_module_clk_t)chip->clock_source == SOC_MOD_CLK_RC_FAST) {
periph_rtc_dig_clk8m_disable();
}
#endif // !CONFIG_IDF_TARGET_ESP32
}