Răsfoiți Sursa

apll: add lock for apll

laokaiyao 4 ani în urmă
părinte
comite
4f28b33bbc

+ 27 - 11
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"
@@ -931,19 +930,29 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
 {
 #if SOC_I2S_SUPPORTS_APLL
     if (use_apll) {
-        int div_min = (int)(RTC_APLL_FREQ_MIN / (float)mclk + 1);
-        int div_max = (int)(RTC_APLL_FREQ_MAX / (float)mclk);
-        div_min = div_min < 2 ? 2 : div_min;  // APLL / mclk >= 2
-        if (div_min > div_max) {
-            ESP_LOGE(TAG, "mclk frequency is too big for APLL colck source");
+        /* 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;
         }
-        uint32_t expt_freq = div_min * mclk;
-        rtc_clk_apll_freq_set(expt_freq);
+        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 expt_freq;
+        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);
@@ -1883,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;
@@ -1937,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
 

+ 1 - 1
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
  */
 
 /**

+ 22 - 24
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;

+ 70 - 0
components/esp_hw_support/clk_ctrl_os.c

@@ -6,6 +6,7 @@
 
 #include <freertos/FreeRTOS.h>
 #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

+ 34 - 0
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

+ 1 - 1
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

+ 71 - 57
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"
@@ -33,10 +34,6 @@
 #define RTC_SLOW_CLK_FREQ_8MD256    (RTC_FAST_CLK_FREQ_8M / 256)
 #define RTC_SLOW_CLK_FREQ_32K       32768
 
-/* APLL numerator frequency range */
-#define RTC_APLL_NUMERATOR_FREQ_MAX     500000000   // 500MHz
-#define RTC_APLL_NUMERATOR_FREQ_MIN     350000000   // 350MHz
-
 /* BBPLL configuration values */
 #define BBPLL_ENDIV5_VAL_320M       0x43
 #define BBPLL_BBADC_DSMP_VAL_320M   0x84
@@ -272,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);
@@ -283,76 +280,93 @@ 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;
-        }
-        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);
-
-        /* 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_freq_set(uint32_t freq)
+uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
 {
-    if (freq < RTC_APLL_FREQ_MIN || freq > RTC_APLL_FREQ_MAX) {
-        return 0;
-    }
-    /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
     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();
     }
-    uint32_t o_div = 0;
-    uint32_t sdm0 = 0;
-    uint32_t sdm1 = 0;
-    uint32_t sdm2 = 0;
-    /**
-     * This formula is to satisfy the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz
-     * '+ 1' in this formular is to get the ceil value
-     * We can also choose the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz
-     * Then the formula should be o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MAX / (float)(freq * 2)) - 2; */
-    o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MIN / (float)(freq * 2) + 1) - 2;
-    // sdm2 = (uint32_t)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
-    sdm2 = (uint32_t)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
+    /* 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 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 = (uint32_t)(numrator * 65536.0 + 0.5) / 256;
+        sdm1 = (int)(numrator * 65536.0 + 0.5) / 256;
         // Get the closest sdm0
-        sdm0 = (uint32_t)(numrator * 65536.0 + 0.5) % 256;
+        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)
+{
+    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);
+
+    /* 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);
     }
-    rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, o_div);
-    float real_freq = (float)rtc_xtal_freq * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2);
-    SOC_LOGD(TAG, "APLL is working at %d Hz with coefficient [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
-             (uint32_t)(real_freq * 1000000), sdm0, sdm1, sdm2, o_div);
-    return (uint32_t)(real_freq * 1000000);
 }
 
 void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)

+ 1 - 1
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

+ 64 - 50
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"
@@ -31,10 +32,6 @@ static const char *TAG = "rtc_clk";
 #define RTC_PLL_FREQ_480M   480
 #define DELAY_RTC_CLK_SWITCH 5
 
-/* APLL numerator frequency range */
-#define RTC_APLL_NUMERATOR_FREQ_MAX     500000000   // 500MHz
-#define RTC_APLL_NUMERATOR_FREQ_MIN     350000000   // 350MHz
-
 // Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
 // On the ESP32-S2, 480MHz PLL is enabled at reset.
 static uint32_t s_cur_pll_freq = RTC_PLL_FREQ_480M;
@@ -123,73 +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_freq_set(uint32_t freq)
+uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
 {
-    if (freq < RTC_APLL_FREQ_MIN || freq > RTC_APLL_FREQ_MAX) {
-        return 0;
-    }
-    /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
     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();
     }
-    uint32_t o_div = 0;
-    uint32_t sdm0 = 0;
-    uint32_t sdm1 = 0;
-    uint32_t sdm2 = 0;
-    /**
-     * This formula is to satisfy the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz
-     * '+ 1' in this formular is to get the ceil value
-     * We can also choose the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz
-     * Then the formula should be o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MAX / (float)(freq * 2)) - 2; */
-    o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MIN / (float)(freq * 2) + 1) - 2;
-    // sdm2 = (uint32_t)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
-    sdm2 = (uint32_t)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
+    /* 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 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 = (uint32_t)(numrator * 65536.0 + 0.5) / 256;
+        sdm1 = (int)(numrator * 65536.0 + 0.5) / 256;
         // Get the closest sdm0
-        sdm0 = (uint32_t)(numrator * 65536.0 + 0.5) % 256;
+        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);
     }
-    rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, o_div);
-    float real_freq = (float)rtc_xtal_freq * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2);
-    SOC_LOGD(TAG, "APLL is working at %d Hz with coefficient [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
-             (uint32_t)(real_freq * 1000000), sdm0, sdm1, sdm2, o_div);
-    return (uint32_t)(real_freq * 1000000);
 }
 
 void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)

+ 7 - 1
components/hal/i2s_hal.c

@@ -27,10 +27,16 @@ static void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mc
     cal->a = 1;
     cal->b = 0;
 
-    uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div;
+    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 min = ~0;
     for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
         // Calculate the closest 'b' in this loop, no need to loop 'b' to seek the closest value

+ 5 - 13
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
 

+ 24 - 16
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

+ 20 - 13
components/soc/esp32/include/soc/rtc.h

@@ -46,10 +46,6 @@ extern "C" {
  * - rtc_init: initialization
  */
 
-/* APLL frequency range */
-#define RTC_APLL_FREQ_MAX               128000000   // 128MHz
-#define RTC_APLL_FREQ_MIN               16000000    // 16MHz
-
 /**
  * @brief Possible main XTAL frequency values.
  *
@@ -255,22 +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 freqency
- * @param freq Expected APLL freqency (unit: Hz)
- * @return
- *      - 0: Failed, the expected APLL frequency is out of range
- *      - else:  The true APLL clock (unit: Hz)
+ * @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
  */
-uint32_t rtc_clk_apll_freq_set(uint32_t freq);
+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

+ 10 - 5
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
 

+ 20 - 12
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

+ 20 - 12
components/soc/esp32s2/include/soc/rtc.h

@@ -73,10 +73,6 @@ extern "C" {
 #define DELAY_SLOW_CLK_SWITCH           300
 #define DELAY_8M_ENABLE                 50
 
-/* APLL frequency range */
-#define RTC_APLL_FREQ_MAX               128000000   // 128MHz
-#define RTC_APLL_FREQ_MIN               16000000    // 16MHz
-
 /* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
  * 10 cycles will take approximately 300 microseconds.
  */
@@ -402,21 +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 freqency
- * @param freq Expected APLL freqency (unit: Hz)
- * @return
- *      - 0: Failed, the expected APLL frequency is out of range
- *      - else:  The true APLL clock (unit: Hz)
+ * @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
  */
-uint32_t rtc_clk_apll_freq_set(uint32_t freq);
+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

+ 9 - 4
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 ----------------------------------------*/

+ 0 - 1
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