From d17e9b8584329f24ff3e0fc5daea265ec1a3d0db Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 27 Aug 2024 09:44:27 +0800 Subject: [PATCH] feat(clock): support apll clock on p4 --- .../port/esp32p4/esp_clk_tree.c | 5 +- .../esp_hw_support/port/esp32p4/rtc_clk.c | 74 +++++++++- components/hal/esp32p4/clk_tree_hal.c | 14 ++ .../hal/esp32p4/include/hal/clk_tree_ll.h | 84 +++++++++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 ++ .../soc/esp32p4/include/soc/regi2c_apll.h | 127 ++++++++++++++++++ components/soc/esp32p4/include/soc/soc_caps.h | 4 +- 7 files changed, 307 insertions(+), 9 deletions(-) create mode 100644 components/soc/esp32p4/include/soc/regi2c_apll.h diff --git a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c index 788ddfcfac..546f25c34b 100644 --- a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c @@ -51,8 +51,9 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr case SOC_MOD_CLK_MPLL: clk_src_freq = clk_ll_mpll_get_freq_mhz(clk_hal_xtal_get_freq_mhz()) * MHZ; break; - // case SOC_MOD_CLK_APLL: TODO: IDF-8884 - // break; + case SOC_MOD_CLK_APLL: + clk_src_freq = clk_hal_apll_get_freq_hz(); + break; // case SOC_MOD_CLK_SDIO_PLL: TODO: IDF-8886 // break; case SOC_MOD_CLK_RTC_SLOW: diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 4bcccf422e..63fb3c3ca9 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -473,18 +473,84 @@ uint32_t rtc_clk_apb_freq_get(void) void rtc_clk_apll_enable(bool enable) { - // TODO: IDF-8884 + if (enable) { + clk_ll_apll_enable(); + } else { + clk_ll_apll_disable(); + } } uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2) { - // TODO: IDF-8884 - return 0; + uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get(); + if (rtc_xtal_freq == 0) { + // xtal_freq has not set yet + ESP_HW_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)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2; + if (o_div > 31) { + ESP_HW_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)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2; + if (o_div < 0) { + ESP_HW_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 * MHZ)) - 4; + // numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2 + float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * MHZ)) - 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 * MHZ * (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) { - // TODO: IDF-8884 + clk_ll_apll_set_config(o_div, sdm0, sdm1, sdm2); + + /* calibration */ + clk_ll_apll_set_calibration(); + + /* wait for calibration end */ + while (!clk_ll_apll_calibration_is_done()) { + /* use esp_rom_delay_us so the RTC bus doesn't get flooded */ + esp_rom_delay_us(1); + } } void rtc_dig_clk8m_enable(void) diff --git a/components/hal/esp32p4/clk_tree_hal.c b/components/hal/esp32p4/clk_tree_hal.c index 8b21821507..b8f809dc79 100644 --- a/components/hal/esp32p4/clk_tree_hal.c +++ b/components/hal/esp32p4/clk_tree_hal.c @@ -81,6 +81,20 @@ IRAM_ATTR uint32_t clk_hal_xtal_get_freq_mhz(void) return freq; } +uint32_t clk_hal_apll_get_freq_hz(void) +{ + uint64_t xtal_freq_hz = (uint64_t)clk_hal_xtal_get_freq_mhz() * 1000000ULL; + uint32_t o_div = 0; + uint32_t sdm0 = 0; + uint32_t sdm1 = 0; + uint32_t sdm2 = 0; + clk_ll_apll_get_config(&o_div, &sdm0, &sdm1, &sdm2); + uint32_t numerator = ((4 + sdm2) << 16) | (sdm1 << 8) | sdm0; + uint32_t denominator = (o_div + 2) << 17; + uint32_t apll_freq_hz = (uint32_t)((xtal_freq_hz * numerator) / denominator); + return apll_freq_hz; +} + void clk_hal_clock_output_setup(soc_clkout_sig_id_t clk_sig, clock_out_channel_t channel_id) { clk_ll_set_dbg_clk_ctrl(clk_sig, channel_id); diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index c989681f77..80f3979752 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -17,6 +17,7 @@ #include "soc/pmu_reg.h" #include "hal/regi2c_ctrl.h" #include "soc/regi2c_cpll.h" +#include "soc/regi2c_apll.h" #include "soc/regi2c_mpll.h" #include "soc/regi2c_bias.h" #include "hal/assert.h" @@ -45,8 +46,17 @@ extern "C" { #define CLK_LL_PLL_480M_FREQ_MHZ (480) #define CLK_LL_PLL_500M_FREQ_MHZ (500) +/* APLL configuration parameters */ +#define CLK_LL_APLL_SDM_STOP_VAL_1 0x09 +#define CLK_LL_APLL_SDM_STOP_VAL_2_REV0 0x69 +#define CLK_LL_APLL_SDM_STOP_VAL_2_REV1 0x49 + +/* APLL calibration parameters */ +#define CLK_LL_APLL_CAL_DELAY_1 0x0f +#define CLK_LL_APLL_CAL_DELAY_2 0x3f +#define CLK_LL_APLL_CAL_DELAY_3 0x1f + /* APLL multiplier output frequency range */ -// TODO: IDF-8884 check if the APLL frequency range is same as before // apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) #define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz #define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz @@ -99,6 +109,24 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_disable(void) SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_CPLL | PMU_TIE_LOW_XPD_CPLL_I2C); } +/** + * @brief Power up APLL circuit + */ +static inline __attribute__((always_inline)) void clk_ll_apll_enable(void) +{ + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_APLL | PMU_TIE_HIGH_XPD_APLL_I2C); + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_APLL_ICG); +} + +/** + * @brief Power down APLL circuit + */ +static inline __attribute__((always_inline)) void clk_ll_apll_disable(void) +{ + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_GLOBAL_APLL_ICG) ; + SET_PERI_REG_MASK(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_LOW_XPD_APLL | PMU_TIE_LOW_XPD_APLL_I2C); +} + /** * @brief Enable the internal oscillator output for LP_PLL_CLK */ @@ -424,6 +452,60 @@ static inline __attribute__((always_inline)) void clk_ll_mpll_set_config(uint32_ REGI2C_WRITE(I2C_MPLL, I2C_MPLL_DIV_REG_ADDR, val); } +/** + * @brief Get APLL configuration which can be used to calculate APLL frequency + * + * @param[out] o_div Frequency divider, 0..31 + * @param[out] sdm0 Frequency adjustment parameter, 0..255 + * @param[out] sdm1 Frequency adjustment parameter, 0..255 + * @param[out] sdm2 Frequency adjustment parameter, 0..63 + */ +static inline __attribute__((always_inline)) void clk_ll_apll_get_config(uint32_t *o_div, uint32_t *sdm0, uint32_t *sdm1, uint32_t *sdm2) +{ + *o_div = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV); + *sdm0 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM0); + *sdm1 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM1); + *sdm2 = REGI2C_READ_MASK(I2C_APLL, I2C_APLL_DSDM2); +} + +/** + * @brief Set APLL configuration + * + * @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 + */ +static inline __attribute__((always_inline)) void clk_ll_apll_set_config(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, CLK_LL_APLL_SDM_STOP_VAL_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, CLK_LL_APLL_SDM_STOP_VAL_2_REV1); + REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div); +} + +/** + * @brief Set APLL calibration parameters + */ +static inline __attribute__((always_inline)) void clk_ll_apll_set_calibration(void) +{ + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_1); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_2); + REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, CLK_LL_APLL_CAL_DELAY_3); +} + +/** + * @brief Check whether APLL calibration is done + * + * @return True if calibration is done; otherwise false + */ +static inline __attribute__((always_inline)) bool clk_ll_apll_calibration_is_done(void) +{ + return REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END); +} + /** * @brief To enable the change of cpu_div_num, mem_div_num, sys_div_num, and apb_div_num */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b85306c91f..c075754637 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -783,6 +783,10 @@ config SOC_I2S_SUPPORTS_XTAL bool default y +config SOC_I2S_SUPPORTS_APLL + bool + default y + config SOC_I2S_SUPPORTS_PCM bool default y @@ -1771,6 +1775,10 @@ config SOC_MODEM_CLOCK_IS_INDEPENDENT bool default n +config SOC_CLK_APLL_SUPPORTED + bool + default y + config SOC_CLK_MPLL_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/regi2c_apll.h b/components/soc/esp32p4/include/soc/regi2c_apll.h new file mode 100644 index 0000000000..8174d9e158 --- /dev/null +++ b/components/soc/esp32p4/include/soc/regi2c_apll.h @@ -0,0 +1,127 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file regi2c_apll.h + * @brief Register definitions for audio PLL (APLL) + * + * 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_freq_set and rtc_clk_apll_enable function in rtc_clk.c. + */ + +#define I2C_APLL 0X6F +#define I2C_APLL_HOSTID 1 + +#define I2C_APLL_IR_CAL_DELAY 0 +#define I2C_APLL_IR_CAL_DELAY_MSB 3 +#define I2C_APLL_IR_CAL_DELAY_LSB 0 + +#define I2C_APLL_IR_CAL_RSTB 0 +#define I2C_APLL_IR_CAL_RSTB_MSB 4 +#define I2C_APLL_IR_CAL_RSTB_LSB 4 + +#define I2C_APLL_IR_CAL_START 0 +#define I2C_APLL_IR_CAL_START_MSB 5 +#define I2C_APLL_IR_CAL_START_LSB 5 + +#define I2C_APLL_IR_CAL_UNSTOP 0 +#define I2C_APLL_IR_CAL_UNSTOP_MSB 6 +#define I2C_APLL_IR_CAL_UNSTOP_LSB 6 + +#define I2C_APLL_OC_ENB_FCAL 0 +#define I2C_APLL_OC_ENB_FCAL_MSB 7 +#define I2C_APLL_OC_ENB_FCAL_LSB 7 + +#define I2C_APLL_IR_CAL_EXT_CAP 1 +#define I2C_APLL_IR_CAL_EXT_CAP_MSB 4 +#define I2C_APLL_IR_CAL_EXT_CAP_LSB 0 + +#define I2C_APLL_IR_CAL_ENX_CAP 1 +#define I2C_APLL_IR_CAL_ENX_CAP_MSB 5 +#define I2C_APLL_IR_CAL_ENX_CAP_LSB 5 + +#define I2C_APLL_OC_LBW 1 +#define I2C_APLL_OC_LBW_MSB 6 +#define I2C_APLL_OC_LBW_LSB 6 + +#define I2C_APLL_IR_CAL_CK_DIV 2 +#define I2C_APLL_IR_CAL_CK_DIV_MSB 3 +#define I2C_APLL_IR_CAL_CK_DIV_LSB 0 + +#define I2C_APLL_OC_DCHGP 2 +#define I2C_APLL_OC_DCHGP_MSB 6 +#define I2C_APLL_OC_DCHGP_LSB 4 + +#define I2C_APLL_OC_ENB_VCON 2 +#define I2C_APLL_OC_ENB_VCON_MSB 7 +#define I2C_APLL_OC_ENB_VCON_LSB 7 + +#define I2C_APLL_OR_CAL_CAP 3 +#define I2C_APLL_OR_CAL_CAP_MSB 4 +#define I2C_APLL_OR_CAL_CAP_LSB 0 + +#define I2C_APLL_OR_CAL_UDF 3 +#define I2C_APLL_OR_CAL_UDF_MSB 5 +#define I2C_APLL_OR_CAL_UDF_LSB 5 + +#define I2C_APLL_OR_CAL_OVF 3 +#define I2C_APLL_OR_CAL_OVF_MSB 6 +#define I2C_APLL_OR_CAL_OVF_LSB 6 + +#define I2C_APLL_OR_CAL_END 3 +#define I2C_APLL_OR_CAL_END_MSB 7 +#define I2C_APLL_OR_CAL_END_LSB 7 + +#define I2C_APLL_OR_OUTPUT_DIV 4 +#define I2C_APLL_OR_OUTPUT_DIV_MSB 4 +#define I2C_APLL_OR_OUTPUT_DIV_LSB 0 + +#define I2C_APLL_OC_TSCHGP 4 +#define I2C_APLL_OC_TSCHGP_MSB 6 +#define I2C_APLL_OC_TSCHGP_LSB 6 + +#define I2C_APLL_EN_FAST_CAL 4 +#define I2C_APLL_EN_FAST_CAL_MSB 7 +#define I2C_APLL_EN_FAST_CAL_LSB 7 + +#define I2C_APLL_OC_DHREF_SEL 5 +#define I2C_APLL_OC_DHREF_SEL_MSB 1 +#define I2C_APLL_OC_DHREF_SEL_LSB 0 + +#define I2C_APLL_OC_DLREF_SEL 5 +#define I2C_APLL_OC_DLREF_SEL_MSB 3 +#define I2C_APLL_OC_DLREF_SEL_LSB 2 + +#define I2C_APLL_SDM_DITHER 5 +#define I2C_APLL_SDM_DITHER_MSB 4 +#define I2C_APLL_SDM_DITHER_LSB 4 + +#define I2C_APLL_SDM_STOP 5 +#define I2C_APLL_SDM_STOP_MSB 5 +#define I2C_APLL_SDM_STOP_LSB 5 + +#define I2C_APLL_SDM_RSTB 5 +#define I2C_APLL_SDM_RSTB_MSB 6 +#define I2C_APLL_SDM_RSTB_LSB 6 + +#define I2C_APLL_OC_DVDD 6 +#define I2C_APLL_OC_DVDD_MSB 4 +#define I2C_APLL_OC_DVDD_LSB 0 + +#define I2C_APLL_DSDM2 7 +#define I2C_APLL_DSDM2_MSB 5 +#define I2C_APLL_DSDM2_LSB 0 + +#define I2C_APLL_DSDM1 8 +#define I2C_APLL_DSDM1_MSB 7 +#define I2C_APLL_DSDM1_LSB 0 + +#define I2C_APLL_DSDM0 9 +#define I2C_APLL_DSDM0_MSB 7 +#define I2C_APLL_DSDM0_LSB 0 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 683ae77543..23bdb9cab2 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -314,7 +314,7 @@ #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_ETM (1) #define SOC_I2S_SUPPORTS_XTAL (1) -// #define SOC_I2S_SUPPORTS_APLL (1) // TODO: IDF-8884 +#define SOC_I2S_SUPPORTS_APLL (1) #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) @@ -684,7 +684,7 @@ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (0) -// #define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ TODO: IDF-8884 +#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ #define SOC_CLK_MPLL_SUPPORTED (1) /*!< Support MSPI PLL */ #define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */ #define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */ -- 2.37.1 (Apple Git-137.1)