diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 740fc93693..8f9cc3daae 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -29,8 +29,7 @@ #include "esp_private/gdma.h" #endif -#include "soc/rtc.h" - +#include "soc/clk_ctrl_os.h" #include "esp_intr_alloc.h" #include "esp_err.h" #include "esp_check.h" @@ -916,124 +915,6 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) /*------------------------------------------------------------- I2S clock operation -------------------------------------------------------------*/ -#if SOC_I2S_SUPPORTS_APLL -/** - * @brief Get APLL frequency - */ -static float i2s_apll_get_freq(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) -{ - int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; - -#if CONFIG_IDF_TARGET_ESP32 - /* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */ - if (esp_efuse_get_chip_ver() == 0) { - sdm0 = 0; - sdm1 = 0; - } -#endif - float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4); - if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) { - return SOC_I2S_APLL_MAX_FREQ; - } - float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1) - return fpll / 2; -} - -/** - * @brief APLL calculate function, was described by following: - * APLL Output frequency is given by the formula: - * - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * apll_freq = fout / ((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * * sdm0 frequency adjustment parameter, 0..255 - * * sdm1 frequency adjustment parameter, 0..255 - * * sdm2 frequency adjustment parameter, 0..63 - * * o_div frequency divider, 0..31 - * - * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, - * then apply the above formula, finding the closest frequency to the desired one. - * But 256*256*64*32 = 134,217,728 loops are too slow with ESP32 - * 1. We will choose the parameters with the highest level of change, - * With 350MHzhal_cfg.chan_bits / p_i2s[i2s_num]->hal_cfg.total_chan) < SOC_I2S_APLL_MIN_RATE) { - ESP_LOGE(TAG, "mclk is too small"); + /* Calculate the expected APLL */ + int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1); + /* apll_freq = mclk * div + * when div = 1, hardware will still divide 2 + * when div = 0, the final mclk will be unpredictable + * So the div here should be at least 2 */ + div = div < 2 ? 2 : div; + 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); + if (ret == ESP_ERR_INVALID_ARG) { + ESP_LOGE(TAG, "set APLL coefficients failed"); return 0; } - i2s_apll_calculate_fi2s(mclk, p_i2s[i2s_num]->hal_cfg.sample_bits, &sdm0, &sdm1, &sdm2, &odir); - ESP_LOGI(TAG, "APLL Enabled, coefficient: sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); - rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, odir); + if (ret == ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, "APLL is occupied already, it is working at %d Hz", real_freq); + } + ESP_LOGI(TAG, "APLL expected frequency is %d Hz, real frequency is %d Hz", expt_freq, real_freq); /* Set I2S_APLL as I2S module clock source */ i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_APLL); /* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */ - return 0; + return real_freq; } /* Set I2S_D2CLK (160M) as default I2S module clock source */ i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK); @@ -1108,7 +997,7 @@ static esp_err_t i2s_calculate_adc_dac_clock(int i2s_num, i2s_hal_clock_cfg_t *c clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk; /* Check if the configuration is correct */ - ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); + ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); return ESP_OK; } @@ -1146,7 +1035,7 @@ static esp_err_t i2s_calculate_pdm_tx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk; /* Check if the configuration is correct */ - ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); + ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); return ESP_OK; } @@ -1184,7 +1073,7 @@ static esp_err_t i2s_calculate_pdm_rx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk; /* Check if the configuration is correct */ - ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); + ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); return ESP_OK; } @@ -1240,7 +1129,7 @@ static esp_err_t i2s_calculate_common_clock(int i2s_num, i2s_hal_clock_cfg_t *cl clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk; /* Check if the configuration is correct */ - ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); + ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large"); return ESP_OK; } @@ -2003,6 +1892,13 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, pre_alloc_i2s_obj->i2s_queue = NULL; } +#if SOC_I2S_SUPPORTS_APLL + /* Power up APLL clock */ + if (i2s_config->use_apll) { + periph_rtc_apll_acquire(); + } +#endif + /* Step 7: Set I2S clocks and start. No need to give parameters since configurations has been set in 'i2s_driver_init' */ ESP_GOTO_ON_ERROR(i2s_set_clk(i2s_num, 0, 0, 0), err, TAG, "I2S set clock failed"); return ESP_OK; @@ -2057,7 +1953,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) if (p_i2s[i2s_num]->use_apll) { // switch back to PLL clock source i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK); - rtc_clk_apll_enable(0, 0, 0, 0, 0); + periph_rtc_apll_release(); } #endif diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 4e7717090b..f6a277be4d 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ /** diff --git a/components/esp_eth/src/esp_eth_mac_esp.c b/components/esp_eth/src/esp_eth_mac_esp.c index 4c8d73fbbc..e75d6358c8 100644 --- a/components/esp_eth/src/esp_eth_mac_esp.c +++ b/components/esp_eth/src/esp_eth_mac_esp.c @@ -24,7 +24,7 @@ #include "hal/emac_hal.h" #include "hal/gpio_hal.h" #include "soc/soc.h" -#include "soc/rtc.h" +#include "soc/clk_ctrl_os.h" #include "sdkconfig.h" #include "esp_rom_gpio.h" #include "esp_rom_sys.h" @@ -56,6 +56,7 @@ typedef struct { bool isr_need_yield; bool flow_ctrl_enabled; // indicates whether the user want to do flow control bool do_flow_ctrl; // indicates whether we need to do software flow control + bool use_apll; // Only use APLL in EMAC_DATA_INTERFACE_RMII && EMAC_CLK_OUT #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -299,30 +300,20 @@ static void emac_esp32_init_smi_gpio(emac_esp32_t *emac) } } -static void emac_config_apll_clock(void) +static esp_err_t emac_config_apll_clock(void) { - /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */ - rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get(); - switch (rtc_xtal_freq) { - case RTC_XTAL_FREQ_40M: // Recommended - /* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */ - /* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */ - rtc_clk_apll_enable(true, 0, 0, 6, 2); - break; - case RTC_XTAL_FREQ_26M: - /* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */ - /* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */ - rtc_clk_apll_enable(true, 39, 118, 15, 3); - break; - case RTC_XTAL_FREQ_24M: - /* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */ - /* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */ - rtc_clk_apll_enable(true, 255, 255, 12, 2); - break; - default: // Assume we have a 40M xtal - rtc_clk_apll_enable(true, 0, 0, 6, 2); - break; + uint32_t expt_freq = 50000000; // 50MHz + uint32_t real_freq = 0; + esp_err_t ret = periph_rtc_apll_freq_set(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 %d Hz", real_freq); } + // If the difference of real APLL frequency is not within 50 ppm, i.e. 2500 Hz, the APLL is unavailable + ESP_RETURN_ON_FALSE(abs(real_freq - expt_freq) <= 2500, + ESP_ERR_INVALID_STATE, TAG, "The APLL is working at an unusable frequency"); + + return ESP_OK; } static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) @@ -429,6 +420,9 @@ static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors) if (emac->intr_hdl) { esp_intr_free(emac->intr_hdl); } + if (emac->use_apll) { + periph_rtc_apll_release(); + } for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { free(emac->tx_buf[i]); } @@ -546,7 +540,10 @@ static esp_err_t esp_emac_config_data_interface(const eth_mac_config_t *config, } /* Enable RMII clock */ emac_ll_clock_enable_rmii_output(emac->hal.ext_regs); - emac_config_apll_clock(); + // Power up APLL clock + periph_rtc_apll_acquire(); + ESP_GOTO_ON_ERROR(emac_config_apll_clock(), err, TAG, "Configure APLL for RMII failed"); + emac->use_apll = true; } else { ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock mode"); } @@ -589,6 +586,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; + emac->use_apll = false; emac->parent.set_mediator = emac_esp32_set_mediator; emac->parent.init = emac_esp32_init; emac->parent.deinit = emac_esp32_deinit; diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c index d3cc0d5248..991adc84e7 100644 --- a/components/esp_hw_support/clk_ctrl_os.c +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -6,6 +6,7 @@ #include #include "soc/clk_ctrl_os.h" +#include "esp_check.h" #include "sdkconfig.h" #define DELAY_RTC_CLK_SWITCH 5 @@ -14,6 +15,13 @@ static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED; static uint8_t s_periph_ref_counts = 0; static uint32_t s_rtc_clk_freq = 0; // Frequency of the 8M/256 clock in Hz +#if SOC_CLK_APLL_SUPPORTED +static const char *TAG = "clk_ctrl_os"; +// Current APLL frequency, in HZ. Zero if APLL is not enabled. +static uint32_t s_cur_apll_freq = 0; +static int s_apll_ref_cnt = 0; +#endif + bool periph_rtc_dig_clk8m_enable(void) { @@ -51,3 +59,65 @@ void periph_rtc_dig_clk8m_disable(void) } portEXIT_CRITICAL(&periph_spinlock); } + +#if SOC_CLK_APLL_SUPPORTED +void periph_rtc_apll_acquire(void) +{ + portENTER_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); + } + portEXIT_CRITICAL(&periph_spinlock); +} + +void periph_rtc_apll_release(void) +{ + portENTER_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 = 0; + rtc_clk_apll_enable(false); + } + portEXIT_CRITICAL(&periph_spinlock); +} + +esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq) +{ + 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, &o_div, &sdm0, &sdm1, &sdm2); + + ESP_RETURN_ON_FALSE(apll_freq, ESP_ERR_INVALID_ARG, TAG, "APLL coefficients calculate failed"); + bool need_config = true; + portENTER_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 == 0 || s_apll_ref_cnt < 2) { + s_cur_apll_freq = apll_freq; + } else { + apll_freq = s_cur_apll_freq; + need_config = false; + } + portEXIT_CRITICAL(&periph_spinlock); + *real_freq = apll_freq; + + if (need_config) { + ESP_LOGD(TAG, "APLL will working at %d Hz with coefficients [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d", + 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; +} +#endif // SOC_I2S_SUPPORTS_APLL diff --git a/components/esp_hw_support/include/soc/clk_ctrl_os.h b/components/esp_hw_support/include/soc/clk_ctrl_os.h index b5eff46930..95bce65793 100644 --- a/components/esp_hw_support/include/soc/clk_ctrl_os.h +++ b/components/esp_hw_support/include/soc/clk_ctrl_os.h @@ -5,6 +5,7 @@ */ #include "soc/rtc.h" +#include "esp_err.h" #ifdef __cplusplus extern "C" { @@ -37,6 +38,39 @@ void periph_rtc_dig_clk8m_disable(void); */ uint32_t periph_rtc_dig_clk8m_get_freq(void); +#if SOC_CLK_APLL_SUPPORTED +/** + * @brief Enable APLL power if it has not enabled + */ +void periph_rtc_apll_acquire(void); + +/** + * @brief Shut down APLL power if no peripherals using APLL + */ +void periph_rtc_apll_release(void); + +/** + * @brief Calculate and set APLL coefficients by given frequency + * @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency + * @note This calculation is based on the inequality: + * xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_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 refered by more than one peripherals, not allowed to change its frequency now + */ +esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq); +#endif // SOC_CLK_APLL_SUPPORTED + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/port/esp32/private_include/regi2c_apll.h b/components/esp_hw_support/port/esp32/private_include/regi2c_apll.h index f2651045ae..6787c0ca7b 100644 --- a/components/esp_hw_support/port/esp32/private_include/regi2c_apll.h +++ b/components/esp_hw_support/port/esp32/private_include/regi2c_apll.h @@ -12,7 +12,7 @@ * * This file lists register fields of APLL, located on an internal configuration * bus. These definitions are used via macros defined in regi2c_ctrl.h, by - * rtc_clk_apll_enable function in rtc_clk.c. + * rtc_clk_apll_freq_set and rtc_clk_apll_enable function in rtc_clk.c. */ #define I2C_APLL 0X6D diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 737daa88f4..4a28816ff0 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -15,6 +15,7 @@ #include "soc/rtc.h" #include "soc/rtc_periph.h" #include "soc/sens_periph.h" +#include "soc/soc_caps.h" #include "soc/dport_reg.h" #include "soc/efuse_periph.h" #include "soc/syscon_reg.h" @@ -268,7 +269,7 @@ bool rtc_clk_8md256_enabled(void) return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0; } -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div) +void rtc_clk_apll_enable(bool enable) { REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1); REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0); @@ -279,32 +280,92 @@ void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm } else { REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD); } +} - if (enable) { - uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1; - uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0); - if (is_rev0) { - sdm0 = 0; - sdm1 = 0; - sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0; +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2) +{ + uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get(); + if (rtc_xtal_freq == 0) { + // xtal_freq has not set yet + SOC_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet"); + abort(); + } + /* Reference formula: apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) / ((o_div + 2) * 2) + * ---------------------------------------------- ----------------- + * 350 MHz <= Numerator <= 500 MHz Denominator + */ + int o_div = 0; // range: 0~31 + int sdm0 = 0; // range: 0~255 + int sdm1 = 0; // range: 0~255 + int sdm2 = 0; // range: 0~63 + /* Firstly try to satisfy the condition that the operation frequency of numerator should be greater than 350 MHz, + * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. + * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is + * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ + o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + if (o_div > 31) { + SOC_LOGE(TAG, "Expected frequency is too small"); + return 0; + } + if (o_div < 0) { + /* Try to satisfy the condition that the operation frequency of numerator should be smaller than 500 MHz, + * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. + * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is + * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ + o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + if (o_div < 0) { + SOC_LOGE(TAG, "Expected frequency is too big"); + return 0; } - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div); + } + // sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 + sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4; + // numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2 + float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2; + // If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2 + if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) { + sdm2++; + } + // If numrator is smaller than (1/65536)/2, keep sdm0 = sdm1 = 0, otherwise calculate sdm0 and sdm1 + else if (numrator > (1.0 / 65536.0) / 2.0) { + // Get the closest sdm1 + sdm1 = (int)(numrator * 65536.0 + 0.5) / 256; + // Get the closest sdm0 + sdm0 = (int)(numrator * 65536.0 + 0.5) % 256; + } + uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2)); + *_o_div = o_div; + *_sdm0 = sdm0; + *_sdm1 = sdm1; + *_sdm2 = sdm2; + return real_freq; +} - /* calibration */ - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2); - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3); +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) +{ + uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1; + uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0); + if (is_rev0) { + sdm0 = 0; + sdm1 = 0; + sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0; + } + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div); - /* wait for calibration end */ - while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) { - /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ - esp_rom_delay_us(1); - } + /* calibration */ + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3); + + /* wait for calibration end */ + while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) { + /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ + esp_rom_delay_us(1); } } diff --git a/components/esp_hw_support/port/esp32s2/private_include/regi2c_apll.h b/components/esp_hw_support/port/esp32s2/private_include/regi2c_apll.h index d62caa1daf..aed1de9d88 100644 --- a/components/esp_hw_support/port/esp32s2/private_include/regi2c_apll.h +++ b/components/esp_hw_support/port/esp32s2/private_include/regi2c_apll.h @@ -12,7 +12,7 @@ * * This file lists register fields of APLL, located on an internal configuration * bus. These definitions are used via macros defined in regi2c_ctrl.h, by - * rtc_clk_apll_enable function in rtc_clk.c. + * rtc_clk_apll_freq_set and rtc_clk_apll_enable function in rtc_clk.c. */ #define I2C_APLL 0X6D diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index d03de58477..14ba0ec209 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s2/rtc_clk.c @@ -15,6 +15,7 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/rtc_io_reg.h" +#include "soc/soc_caps.h" #include "soc/sens_reg.h" #include "soc/dport_reg.h" #include "soc/efuse_reg.h" @@ -119,30 +120,90 @@ bool rtc_clk_8md256_enabled(void) return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0; } -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div) +void rtc_clk_apll_enable(bool enable) { REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1); REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0); +} - if (enable) { - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_2_REV1); - REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div); - - /* calibration */ - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1); - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2); - REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3); - - /* wait for calibration end */ - while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) { - /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ - esp_rom_delay_us(1); +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2) +{ + uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get(); + if (rtc_xtal_freq == 0) { + // xtal_freq has not set yet + SOC_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet"); + abort(); + } + /* Reference formula: apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) / ((o_div + 2) * 2) + * ---------------------------------------------- ----------------- + * 350 MHz <= Numerator <= 500 MHz Denominator + */ + int o_div = 0; // range: 0~31 + int sdm0 = 0; // range: 0~255 + int sdm1 = 0; // range: 0~255 + int sdm2 = 0; // range: 0~63 + /* Firstly try to satisfy the condition that the operation frequency of numerator should be greater than 350 MHz, + * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. + * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is + * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ + o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + if (o_div > 31) { + SOC_LOGE(TAG, "Expected frequency is too small"); + return 0; + } + if (o_div < 0) { + /* Try to satisfy the condition that the operation frequency of numerator should be smaller than 500 MHz, + * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. + * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is + * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ + o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + if (o_div < 0) { + SOC_LOGE(TAG, "Expected frequency is too big"); + return 0; } } + // sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 + sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4; + // numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2 + float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2; + // If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2 + if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) { + sdm2++; + } + // If numrator is smaller than (1/65536)/2, keep sdm0 = sdm1 = 0, otherwise calculate sdm0 and sdm1 + else if (numrator > (1.0 / 65536.0) / 2.0) { + // Get the closest sdm1 + sdm1 = (int)(numrator * 65536.0 + 0.5) / 256; + // Get the closest sdm0 + sdm0 = (int)(numrator * 65536.0 + 0.5) % 256; + } + uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2)); + *_o_div = o_div; + *_sdm0 = sdm0; + *_sdm1 = sdm1; + *_sdm2 = sdm2; + return real_freq; +} + +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) +{ + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_2_REV1); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div); + + /* calibration */ + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3); + + /* wait for calibration end */ + while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) { + /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ + esp_rom_delay_us(1); + } } void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq) diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 1b3eb18373..acbf1c139c 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -26,27 +26,32 @@ static void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mc cal->mclk_div = clk_cfg->mclk_div; cal->a = 1; cal->b = 0; - /* If sclk = 0 means APLL clock applied, mclk_div should set to 1 */ - if (!clk_cfg->sclk) { - cal->mclk_div = 1; + + uint32_t freq_diff = abs(clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div); + if (!freq_diff) { + return; + } + float decimal = freq_diff / (float)clk_cfg->mclk; + // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0 + if (decimal > 125.0 / 126.0) { + cal->mclk_div++; return; } - uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div; uint32_t min = ~0; for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) { - for (int b = 1; b < a; b++) { - ma = freq_diff * a; - mb = clk_cfg->mclk * b; - if (ma == mb) { - cal->a = a; - cal->b = b; - return; - } - if (abs((mb - ma)) < min) { - cal->a = a; - cal->b = b; - min = abs(mb - ma); - } + // Calculate the closest 'b' in this loop, no need to loop 'b' to seek the closest value + int b = (int)(a * (freq_diff / (double)clk_cfg->mclk) + 0.5); + ma = freq_diff * a; + mb = clk_cfg->mclk * b; + if (ma == mb) { + cal->a = a; + cal->b = b; + return; + } + if (abs((mb - ma)) < min) { + cal->a = a; + cal->b = b; + min = abs(mb - ma); } } } diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 48d745eb2f..c554b34f68 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index d3764aadde..b293331fc6 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -191,10 +191,34 @@ config SOC_I2C_SUPPORT_APB bool default y +config SOC_CLK_APLL_SUPPORTED + bool + default y + +config SOC_APLL_MULTIPLIER_OUT_MIN_HZ + int + default 350000000 + +config SOC_APLL_MULTIPLIER_OUT_MAX_HZ + int + default 500000000 + +config SOC_APLL_MIN_HZ + int + default 5303031 + +config SOC_APLL_MAX_HZ + int + default 125000000 + config SOC_I2S_NUM int default 2 +config SOC_I2S_SUPPORTS_APLL + bool + default y + config SOC_I2S_SUPPORTS_PDM_TX bool default y @@ -211,22 +235,6 @@ config SOC_I2S_SUPPORTS_DAC bool default y -config SOC_I2S_SUPPORTS_APLL - bool - default y - -config SOC_I2S_APLL_MIN_FREQ - int - default 250000000 - -config SOC_I2S_APLL_MAX_FREQ - int - default 500000000 - -config SOC_I2S_APLL_MIN_RATE - int - default 10675 - config SOC_I2S_TRANS_SIZE_ALIGN_WORD bool default y diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index bbbf3c7550..1ca2c4707d 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -1,16 +1,8 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once #include @@ -54,7 +46,6 @@ extern "C" { * - rtc_init: initialization */ - /** * @brief Possible main XTAL frequency values. * @@ -260,13 +251,33 @@ bool rtc_clk_8md256_enabled(void); * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. * * @param enable true to enable, false to disable + */ +void rtc_clk_apll_enable(bool enable); + +/** + * @brief Calculate APLL clock coeffifcients + * + * @param freq expected APLL frequency + * @param o_div frequency divider, 0..31 * @param sdm0 frequency adjustment parameter, 0..255 * @param sdm1 frequency adjustment parameter, 0..255 * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 + * + * @return + * - 0 Failed + * - else Sucess */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, - uint32_t sdm2, uint32_t o_div); +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2); + +/** + * @brief Set APLL clock coeffifcients + * + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + */ +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2); /** * @brief Select source for RTC_SLOW_CLK diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 2c672d56dc..39521e4426 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -157,18 +157,23 @@ #define SOC_I2C_SUPPORT_APB (1) +/*-------------------------- APLL CAPS ----------------------------------------*/ +#define SOC_CLK_APLL_SUPPORTED (1) +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz +#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz +#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + /*-------------------------- I2S CAPS ----------------------------------------*/ // ESP32 have 2 I2S -#define SOC_I2S_NUM (2) +#define SOC_I2S_NUM (2U) +#define SOC_I2S_SUPPORTS_APLL (1) // ESP32 support APLL #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) #define SOC_I2S_SUPPORTS_ADC (1) // ESP32 support ADC and DAC #define SOC_I2S_SUPPORTS_DAC (1) -#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware #define SOC_I2S_TRANS_SIZE_ALIGN_WORD (1) // I2S DMA transfer size must be aligned to word #define SOC_I2S_LCD_I80_VARIANT (1) // I2S has a special LCD mode that can generate Intel 8080 TX timing diff --git a/components/soc/esp32c3/include/soc/rtc.h b/components/soc/esp32c3/include/soc/rtc.h index dccd7a0778..2fbf1431d0 100644 --- a/components/soc/esp32c3/include/soc/rtc.h +++ b/components/soc/esp32c3/include/soc/rtc.h @@ -157,7 +157,6 @@ typedef enum { RTC_CPU_FREQ_SRC_XTAL, //!< XTAL RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M) RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator - RTC_CPU_FREQ_SRC_APLL //!< APLL } rtc_cpu_freq_src_t; /** @@ -363,24 +362,6 @@ bool rtc_clk_8m_enabled(void); */ bool rtc_clk_8md256_enabled(void); -/** - * @brief Enable or disable APLL - * - * Output frequency is given by the formula: - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * - * @param enable true to enable, false to disable - * @param sdm0 frequency adjustment parameter, 0..255 - * @param sdm1 frequency adjustment parameter, 0..255 - * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 - */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div); - /** * @brief Select source for RTC_SLOW_CLK * @param slow_freq clock source (one of rtc_slow_freq_t values) diff --git a/components/soc/esp32h2/include/soc/rtc.h b/components/soc/esp32h2/include/soc/rtc.h index fb288fb4ef..d04d815ae2 100644 --- a/components/soc/esp32h2/include/soc/rtc.h +++ b/components/soc/esp32h2/include/soc/rtc.h @@ -369,24 +369,6 @@ bool rtc_clk_8m_enabled(void); */ bool rtc_clk_8md256_enabled(void); -/** - * @brief Enable or disable APLL - * - * Output frequency is given by the formula: - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * - * @param enable true to enable, false to disable - * @param sdm0 frequency adjustment parameter, 0..255 - * @param sdm1 frequency adjustment parameter, 0..255 - * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 - */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div); - /** * @brief Select source for RTC_SLOW_CLK * @param slow_freq clock source (one of rtc_slow_freq_t values) diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index fbef980458..0d670294da 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -279,6 +279,26 @@ config SOC_I2C_SUPPORT_APB bool default y +config SOC_CLK_APLL_SUPPORTED + bool + default y + +config SOC_APLL_MULTIPLIER_OUT_MIN_HZ + int + default 350000000 + +config SOC_APLL_MULTIPLIER_OUT_MAX_HZ + int + default 500000000 + +config SOC_APLL_MIN_HZ + int + default 5303031 + +config SOC_APLL_MAX_HZ + int + default 125000000 + config SOC_I2S_NUM int default 1 @@ -291,18 +311,6 @@ config SOC_I2S_SUPPORTS_DMA_EQUAL bool default y -config SOC_I2S_APLL_MIN_FREQ - int - default 250000000 - -config SOC_I2S_APLL_MAX_FREQ - int - default 500000000 - -config SOC_I2S_APLL_MIN_RATE - int - default 10675 - config SOC_I2S_LCD_I80_VARIANT bool default y diff --git a/components/soc/esp32s2/include/soc/rtc.h b/components/soc/esp32s2/include/soc/rtc.h index 11b13fb6aa..91cad6f860 100644 --- a/components/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/esp32s2/include/soc/rtc.h @@ -1,16 +1,8 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once #include @@ -406,12 +398,33 @@ bool rtc_clk_8md256_enabled(void); * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. * * @param enable true to enable, false to disable + */ +void rtc_clk_apll_enable(bool enable); + +/** + * @brief Calculate APLL clock coeffifcients + * + * @param freq expected APLL frequency + * @param o_div frequency divider, 0..31 * @param sdm0 frequency adjustment parameter, 0..255 * @param sdm1 frequency adjustment parameter, 0..255 * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 + * + * @return + * - 0 Failed + * - else Sucess */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div); +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2); + +/** + * @brief Set APLL clock coeffifcients + * + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + */ +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2); /** * @brief Select source for RTC_SLOW_CLK diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 273fdb9f1e..1f73d62f5a 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -153,14 +153,19 @@ #define SOC_I2C_SUPPORT_REF_TICK (1) #define SOC_I2C_SUPPORT_APB (1) +/*-------------------------- APLL CAPS ----------------------------------------*/ +#define SOC_CLK_APLL_SUPPORTED (1) +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz +#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz +#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + /*-------------------------- I2S CAPS ----------------------------------------*/ // ESP32-S2 have 1 I2S #define SOC_I2S_NUM (1U) -#define SOC_I2S_SUPPORTS_APLL (1)// ESP32-S2 support APLL +#define SOC_I2S_SUPPORTS_APLL (1) // ESP32-S2 support APLL #define SOC_I2S_SUPPORTS_DMA_EQUAL (1) -#define SOC_I2S_APLL_MIN_FREQ (250000000) -#define SOC_I2S_APLL_MAX_FREQ (500000000) -#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware #define SOC_I2S_LCD_I80_VARIANT (1) /*-------------------------- LCD CAPS ----------------------------------------*/ diff --git a/components/soc/esp32s3/include/soc/rtc.h b/components/soc/esp32s3/include/soc/rtc.h index aa09874f2c..70323192fa 100644 --- a/components/soc/esp32s3/include/soc/rtc.h +++ b/components/soc/esp32s3/include/soc/rtc.h @@ -157,7 +157,6 @@ typedef enum { RTC_CPU_FREQ_SRC_XTAL, //!< XTAL RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M) RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator - RTC_CPU_FREQ_SRC_APLL //!< APLL } rtc_cpu_freq_src_t; /** @@ -371,24 +370,6 @@ bool rtc_clk_8m_enabled(void); */ bool rtc_clk_8md256_enabled(void); -/** - * @brief Enable or disable APLL - * - * Output frequency is given by the formula: - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * - * @param enable true to enable, false to disable - * @param sdm0 frequency adjustment parameter, 0..255 - * @param sdm1 frequency adjustment parameter, 0..255 - * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 - */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div); - /** * @brief Select source for RTC_SLOW_CLK * @param slow_freq clock source (one of rtc_slow_freq_t values) diff --git a/components/soc/esp8684/include/soc/rtc.h b/components/soc/esp8684/include/soc/rtc.h index 4e6140bdce..c65b49ddba 100644 --- a/components/soc/esp8684/include/soc/rtc.h +++ b/components/soc/esp8684/include/soc/rtc.h @@ -150,7 +150,6 @@ typedef enum { RTC_CPU_FREQ_SRC_XTAL, //!< XTAL RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M) RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator - RTC_CPU_FREQ_SRC_APLL //!< APLL } rtc_cpu_freq_src_t; /** @@ -349,24 +348,6 @@ bool rtc_clk_8m_enabled(void); */ bool rtc_clk_8md256_enabled(void); -/** - * @brief Enable or disable APLL - * - * Output frequency is given by the formula: - * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) - * - * The dividend in this expression should be in the range of 240 - 600 MHz. - * - * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. - * - * @param enable true to enable, false to disable - * @param sdm0 frequency adjustment parameter, 0..255 - * @param sdm1 frequency adjustment parameter, 0..255 - * @param sdm2 frequency adjustment parameter, 0..63 - * @param o_div frequency divider, 0..31 - */ -void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div); - /** * @brief Select source for RTC_SLOW_CLK * @param slow_freq clock source (one of rtc_slow_freq_t values) diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index fe147ec8fb..f84beac2c3 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1135,7 +1135,6 @@ components/hal/include/hal/esp_flash_err.h components/hal/include/hal/gpio_hal.h components/hal/include/hal/i2c_hal.h components/hal/include/hal/i2c_types.h -components/hal/include/hal/i2s_types.h components/hal/include/hal/interrupt_controller_hal.h components/hal/include/hal/interrupt_controller_types.h components/hal/include/hal/ledc_hal.h @@ -1632,7 +1631,6 @@ components/soc/esp32/include/soc/pid.h components/soc/esp32/include/soc/reset_reasons.h components/soc/esp32/include/soc/rmt_reg.h components/soc/esp32/include/soc/rmt_struct.h -components/soc/esp32/include/soc/rtc.h components/soc/esp32/include/soc/rtc_cntl_reg.h components/soc/esp32/include/soc/rtc_cntl_struct.h components/soc/esp32/include/soc/rtc_i2c_reg.h @@ -1855,7 +1853,6 @@ components/soc/esp32s2/include/soc/pcnt_struct.h components/soc/esp32s2/include/soc/reset_reasons.h components/soc/esp32s2/include/soc/rmt_reg.h components/soc/esp32s2/include/soc/rmt_struct.h -components/soc/esp32s2/include/soc/rtc.h components/soc/esp32s2/include/soc/rtc_cntl_reg.h components/soc/esp32s2/include/soc/rtc_cntl_struct.h components/soc/esp32s2/include/soc/rtc_i2c_reg.h