feat(clock): support apll clock on p4

This commit is contained in:
laokaiyao 2024-08-27 09:44:27 +08:00 committed by Kevin (Lao Kaiyao)
parent 2526ebdaa9
commit 3937e225ec
7 changed files with 307 additions and 9 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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);

View File

@ -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
*/

View File

@ -787,6 +787,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
@ -1811,6 +1815,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

View File

@ -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

View File

@ -316,7 +316,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)
@ -695,7 +695,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 */