From 1e9ef469dc91d2a3e4f2f030a6ce37c1e25151ed Mon Sep 17 00:00:00 2001 From: chenwen Date: Thu, 20 Aug 2020 09:03:13 -0300 Subject: [PATCH] xtensa/esp32: Add functions to switch CPU frequency from 80MHz to 240Mhz --- arch/xtensa/src/esp32/Kconfig | 20 ++ arch/xtensa/src/esp32/esp32_clockconfig.c | 332 +++++++++++++++--- arch/xtensa/src/esp32/hardware/esp32_soc.h | 158 ++++++++- .../xtensa/esp32/esp32-core/include/board.h | 6 +- 4 files changed, 471 insertions(+), 45 deletions(-) diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index 2935651f05..5f085035f9 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -5,6 +5,26 @@ if ARCH_CHIP_ESP32 +choice ESP32_DEFAULT_CPU_FREQ_MHZ + prompt "CPU frequency" + default ESP32_DEFAULT_CPU_FREQ_240 + help + CPU frequency to be set on application startup. + + config ESP32_DEFAULT_CPU_FREQ_80 + bool "80 MHz" + config ESP32_DEFAULT_CPU_FREQ_160 + bool "160 MHz" + config ESP32_DEFAULT_CPU_FREQ_240 + bool "240 MHz" +endchoice # CPU frequency + +config ESP32_DEFAULT_CPU_FREQ_MHZ + int + default 80 if ESP32_DEFAULT_CPU_FREQ_80 + default 160 if ESP32_DEFAULT_CPU_FREQ_160 + default 240 if ESP32_DEFAULT_CPU_FREQ_240 + menu "ESP32 Peripheral Selection" config ESP32_UART diff --git a/arch/xtensa/src/esp32/esp32_clockconfig.c b/arch/xtensa/src/esp32/esp32_clockconfig.c index 59c5fb1d05..ecf488b270 100644 --- a/arch/xtensa/src/esp32/esp32_clockconfig.c +++ b/arch/xtensa/src/esp32/esp32_clockconfig.c @@ -31,20 +31,14 @@ #include #include "xtensa.h" -#ifndef CONFIG_SUPPRESS_CLOCK_CONFIG -#warning REVISIT ... function prototypes - -void phy_get_romfunc_addr(void); -void rtc_init_lite(void); -void rtc_set_cpu_freq(xtal_freq_t xtal_freq, enum xtal_freq_e cpu_freq); -#endif +#include "hardware/esp32_dport.h" +#include "hardware/esp32_soc.h" /**************************************************************************** * Private Types ****************************************************************************/ -#ifndef CONFIG_SUPPRESS_CLOCK_CONFIG -enum xtal_freq_e +enum xtal_freq_t { XTAL_40M = 40, XTAL_26M = 26, @@ -52,13 +46,276 @@ enum xtal_freq_e XTAL_AUTO = 0 }; -enum xtal_freq_e +enum cpu_freq_t { - CPU_80M = 1, - CPU_160M = 2, - CPU_240M = 3, + CPU_80M = 0, + CPU_160M = 1, + CPU_240M = 2, }; -#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_set_cpu_freq + * + * Description: + * Switch to one of PLL-based frequencies. + * Current frequency can be XTAL or PLL. + * + * Input Parameters: + * cpu_freq_mhz - new CPU frequency + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_set_cpu_freq(int cpu_freq_mhz) +{ + int dbias = DIG_DBIAS_80M_160M; + int per_conf; + uint32_t value; + + switch (cpu_freq_mhz) + { + case 160: + per_conf = CPU_160M; + break; + case 240: + dbias = DIG_DBIAS_240M; + per_conf = CPU_240M; + break; + case 80: + per_conf = CPU_80M; + default: + break; + } + + value = (((80 * MHZ) >> 12) & UINT16_MAX) + | ((((80 * MHZ) >> 12) & UINT16_MAX) << 16); + putreg32(value, RTC_APB_FREQ_REG); + putreg32(per_conf, DPORT_CPU_PER_CONF_REG); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias); + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, + RTC_CNTL_SOC_CLK_SEL_PLL); +} + +/**************************************************************************** + * Name: esp32_bbpll_configure + * + * Description: + * Configure main XTAL frequency values according to pll_freq. + * + * Input Parameters: + * xtal_freq - XTAL frequency values + * pll_freq - PLL frequency values + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_bbpll_configure(enum xtal_freq_t xtal_freq, int pll_freq) +{ + uint8_t div_ref; + uint8_t div7_0; + uint8_t div10_8; + uint8_t lref; + uint8_t dcur; + uint8_t bw; + uint8_t i2c_bbpll_lref; + uint8_t i2c_bbpll_div_7_0; + uint8_t i2c_bbpll_dcur; + + if (pll_freq == RTC_PLL_FREQ_320M) + { + /* Raise the voltage, if needed */ + + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, + DIG_DBIAS_80M_160M); + + /* Configure 320M PLL */ + + switch (xtal_freq) + { + case XTAL_40M: + div_ref = 0; + div7_0 = 32; + div10_8 = 0; + lref = 0; + dcur = 6; + bw = 3; + break; + case XTAL_26M: + div_ref = 12; + div7_0 = 224; + div10_8 = 4; + lref = 1; + dcur = 0; + bw = 1; + break; + case XTAL_24M: + div_ref = 11; + div7_0 = 224; + div10_8 = 4; + lref = 1; + dcur = 0; + bw = 1; + break; + default: + div_ref = 12; + div7_0 = 224; + div10_8 = 4; + lref = 0; + dcur = 0; + bw = 0; + break; + } + + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_320M); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_BBADC_DSMP, + BBPLL_BBADC_DSMP_VAL_320M); + } + else + { + /* Raise the voltage */ + + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M); + ets_delay_us(DELAY_PLL_DBIAS_RAISE); + + /* Configure 480M PLL */ + + switch (xtal_freq) + { + case XTAL_40M: + div_ref = 0; + div7_0 = 28; + div10_8 = 0; + lref = 0; + dcur = 6; + bw = 3; + break; + case XTAL_26M: + div_ref = 12; + div7_0 = 144; + div10_8 = 4; + lref = 1; + dcur = 0; + bw = 1; + break; + case XTAL_24M: + div_ref = 11; + div7_0 = 144; + div10_8 = 4; + lref = 1; + dcur = 0; + bw = 1; + break; + default: + div_ref = 12; + div7_0 = 224; + div10_8 = 4; + lref = 0; + dcur = 0; + bw = 0; + break; + } + + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_ENDIV5, BBPLL_ENDIV5_VAL_480M); + I2C_WRITEREG_RTC(I2C_BBPLL, + I2C_BBPLL_BBADC_DSMP, BBPLL_BBADC_DSMP_VAL_480M); + } + + i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref); + i2c_bbpll_div_7_0 = div7_0; + i2c_bbpll_dcur = (bw << 6) | dcur; + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur); +} + +/**************************************************************************** + * Name: esp32_bbpll_enable + * + * Description: + * Reset BBPLL configuration. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32_bbpll_enable(void) +{ + modifyreg32(RTC_CNTL_OPTIONS0_REG, + RTC_CNTL_BIAS_I2C_FORCE_PD | RTC_CNTL_BB_I2C_FORCE_PD | + RTC_CNTL_BBPLL_FORCE_PD | RTC_CNTL_BBPLL_I2C_FORCE_PD, 0); + + /* reset BBPLL configuration */ + + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_IR_CAL_DELAY, + BBPLL_IR_CAL_DELAY_VAL); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_IR_CAL_EXT_CAP, + BBPLL_IR_CAL_EXT_CAP_VAL); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_ENB_FCAL, + BBPLL_OC_ENB_FCAL_VAL); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_ENB_VCON, + BBPLL_OC_ENB_VCON_VAL); + I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_BBADC_CAL_7_0, + BBPLL_BBADC_CAL_7_0_VAL); +} + +/**************************************************************************** + * Name: esp32_update_to_xtal + * + * Description: + * Switch to XTAL frequency, does not disable the PLL + * + * Input Parameters: + * freq - XTAL frequency + * div - REF_TICK divider + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void esp32_update_to_xtal(int freq, int div) +{ + uint32_t value = (((freq * MHZ) >> 12) & UINT16_MAX) + | ((((freq * MHZ) >> 12) & UINT16_MAX) << 16); + putreg32(value, RTC_APB_FREQ_REG); + + /* set divider from XTAL to APB clock */ + + REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, div - 1); + + /* switch clock source */ + + REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, + RTC_CNTL_SOC_CLK_SEL_XTL); + + /* adjust ref_tick */ + + modifyreg32(APB_CTRL_XTAL_TICK_CONF_REG, 0, + (freq * MHZ) / REF_CLK_FREQ - 1); + + /* lower the voltage */ + + if (freq <= 2) + { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_2M); + } + else + { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); + } +} /**************************************************************************** * Public Functions @@ -76,40 +333,29 @@ enum xtal_freq_e void esp32_clockconfig(void) { -#ifdef CONFIG_SUPPRESS_CLOCK_CONFIG -# warning WARNING: Clock configuration disabled -#else uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - enum xtal_freq_e freq; - - phy_get_romfunc_addr(); - - /* Frequency will be changed to 40MHz in rtc_init_lite */ - - rtc_init_lite(); + uint32_t source_freq_mhz; + enum xtal_freq_t xtal_freq = XTAL_40M; + enum cpu_freq_t freq; freq = CPU_80M; switch (freq_mhz) { - case 240: - freq = CPU_240M; - break; - case 160: - freq = CPU_160M; - break; - default: - freq_mhz = 80; - - /* no break */ - - case 80: - freq = CPU_80M; - break; + case 240: + freq = CPU_240M; + source_freq_mhz = RTC_PLL_FREQ_480M; + break; + case 160: + freq = CPU_160M; + source_freq_mhz = RTC_PLL_FREQ_320M; + break; + case 80: + default: + return; } - /* Frequency will be changed to freq in rtc_set_cpu_freq */ - - rtc_set_cpu_freq(XTAL_AUTO, freq); - ets_update_cpu_frequency(freq_mhz); -#endif + esp32_update_to_xtal(xtal_freq, 1); + esp32_bbpll_enable(); + esp32_bbpll_configure(xtal_freq, source_freq_mhz); + esp32_set_cpu_freq(freq_mhz); } diff --git a/arch/xtensa/src/esp32/hardware/esp32_soc.h b/arch/xtensa/src/esp32/hardware/esp32_soc.h index 45f84e98d9..f8dddd642f 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_soc.h +++ b/arch/xtensa/src/esp32/hardware/esp32_soc.h @@ -168,7 +168,7 @@ /* Set bits of register controlled by mask */ -#define SET_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))) */ +#define SET_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))) /* Get bits of register controlled by mask */ @@ -192,6 +192,7 @@ #define CPU_CLK_FREQ_ROM APB_CLK_FREQ_ROM #define CPU_CLK_FREQ APB_CLK_FREQ #define APB_CLK_FREQ 80*1000000 /* Unit: Hz */ +#define REF_CLK_FREQ ( 1000000 ) #define UART_CLK_FREQ APB_CLK_FREQ #define WDT_CLK_FREQ APB_CLK_FREQ #define TIMER_CLK_FREQ (80000000>>4) /* 80MHz divided by 16 */ @@ -371,4 +372,159 @@ /* Other interrupt numbers should be managed by the user */ +#define DR_REG_APB_CTRL_BASE 0x3ff66000 /* Old name for SYSCON, to be removed */ +#define APB_CTRL_SYSCLK_CONF_REG (DR_REG_APB_CTRL_BASE + 0x0) +#define APB_CTRL_XTAL_TICK_CONF_REG (DR_REG_APB_CTRL_BASE + 0x4) + +/* APB_CTRL_PRE_DIV_CNT : R/W ;bitpos:[9:0] ;default: 10'h0 ; */ + +#define APB_CTRL_PRE_DIV_CNT 0x000003FF +#define APB_CTRL_PRE_DIV_CNT_M ((APB_CTRL_PRE_DIV_CNT_V)<<(APB_CTRL_PRE_DIV_CNT_S)) +#define APB_CTRL_PRE_DIV_CNT_V 0x3FF +#define APB_CTRL_PRE_DIV_CNT_S 0 + +#define I2C_BBPLL_IR_CAL_DELAY 0 +#define I2C_BBPLL_IR_CAL_EXT_CAP 1 +#define I2C_BBPLL_OC_ENB_FCAL 4 +#define I2C_BBPLL_OC_ENB_VCON 10 +#define I2C_BBPLL_BBADC_CAL_7_0 12 + +#define I2C_BBPLL_OC_LREF 2 +#define I2C_BBPLL_OC_LREF_MSB 7 +#define I2C_BBPLL_OC_LREF_LSB 7 + +#define I2C_BBPLL_OC_DIV_7_0 3 +#define I2C_BBPLL_OC_DIV_7_0_MSB 7 +#define I2C_BBPLL_OC_DIV_7_0_LSB 0 + +#define I2C_BBPLL_BBADC_DSMP 9 +#define I2C_BBPLL_BBADC_DSMP_MSB 7 +#define I2C_BBPLL_BBADC_DSMP_LSB 4 + +#define I2C_BBPLL_OC_DCUR 5 +#define I2C_BBPLL_OC_DCUR_MSB 2 +#define I2C_BBPLL_OC_DCUR_LSB 0 + +#define I2C_BBPLL_ENDIV5 11 + +#define I2C_BBPLL 0x66 +#define I2C_BBPLL_HOSTID 4 + +#define I2C_WRITEREG_RTC(block, reg_add, indata) \ + rom_i2c_writeReg(block, block##_HOSTID, reg_add, indata) + +/* BBPLL configuration values */ + +#define BBPLL_ENDIV5_VAL_320M 0x43 +#define BBPLL_BBADC_DSMP_VAL_320M 0x84 +#define BBPLL_ENDIV5_VAL_480M 0xc3 +#define BBPLL_BBADC_DSMP_VAL_480M 0x74 + +#define BBPLL_IR_CAL_DELAY_VAL 0x18 +#define BBPLL_IR_CAL_EXT_CAP_VAL 0x20 +#define BBPLL_OC_ENB_FCAL_VAL 0x9a +#define BBPLL_OC_ENB_VCON_VAL 0x00 +#define BBPLL_BBADC_CAL_7_0_VAL 0x00 + +#define EFUSE_BLK0_RDATA5_REG (DR_REG_EFUSE_BASE + 0x014) +#define EFUSE_RD_VOL_LEVEL_HP_INV 0x03 +#define EFUSE_RD_VOL_LEVEL_HP_INV_S 22 + +#define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000) +#define TIMG_RTCCALICFG_REG(i) (REG_TIMG_BASE(i) + 0x0068) + +#define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0) +#define RTC_CNTL_STORE5_REG (DR_REG_RTCCNTL_BASE + 0xb4) + +#define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG +#define RTC_CNTL_REG (DR_REG_RTCCNTL_BASE + 0x7c) + +#define RTC_CNTL_CLK_CONF_REG (DR_REG_RTCCNTL_BASE + 0x70) + +#define RTC_CNTL_ANA_CONF_REG (DR_REG_RTCCNTL_BASE + 0x30) + +#define RTC_CNTL_STORE4_REG (DR_REG_RTCCNTL_BASE + 0xb0) +#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG + +/* Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP, + * RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values. + * Valid if RTC_CNTL_DBG_ATTEN is 0. + */ + +#define RTC_CNTL_DBIAS_1V00 2 +#define RTC_CNTL_DBIAS_1V10 4 +#define RTC_CNTL_DBIAS_1V25 7 + +/* RTC_CNTL_DIG_DBIAS_WAK : R/W ;bitpos:[13:11] ;default: 3'd4 ; */ + +#define RTC_CNTL_DIG_DBIAS_WAK 0x00000007 +#define RTC_CNTL_DIG_DBIAS_WAK_S 11 + +/* RTC_CNTL_SOC_CLK_SEL : R/W ;bitpos:[28:27] ;default: 2'd0 ; + * description: SOC clock sel. 0: XTAL 1: PLL 2: CK8M 3: APLL + */ + +#define RTC_CNTL_SOC_CLK_SEL 0x00000003 +#define RTC_CNTL_SOC_CLK_SEL_S 27 +#define RTC_CNTL_SOC_CLK_SEL_XTL 0 +#define RTC_CNTL_SOC_CLK_SEL_PLL 1 +#define RTC_CNTL_SOC_CLK_SEL_8M 2 +#define RTC_CNTL_SOC_CLK_SEL_APLL 3 + +/* Core voltage needs to be increased in two cases: + * 1. running at 240 MHz + * 2. running with 80MHz Flash frequency + * There is a record in efuse which indicates the + * proper voltage for these two cases. + */ + +#define RTC_CNTL_DBIAS_HP_VOLT (RTC_CNTL_DBIAS_1V25 - (REG_GET_FIELD(EFUSE_BLK0_RDATA5_REG, EFUSE_RD_VOL_LEVEL_HP_INV))) +#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M +#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_HP_VOLT +#else +#define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_1V10 +#endif +#define DIG_DBIAS_240M RTC_CNTL_DBIAS_HP_VOLT +#define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10 +#define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00 + +#define DELAY_PLL_DBIAS_RAISE 3 +#define DELAY_PLL_ENABLE_WITH_150K 80 +#define DELAY_PLL_ENABLE_WITH_32K 160 + +/* RTC_CNTL_BB_I2C_FORCE_PD : R/W ;bitpos:[6] ;default: 1'b0 ; + * description: BB_I2C force power down + */ + +#define RTC_CNTL_BB_I2C_FORCE_PD (BIT(6)) + +/* RTC_CNTL_BBPLL_FORCE_PD : R/W ;bitpos:[10] ;default: 1'b0 ; + * description: BB_PLL force power down + */ + +#define RTC_CNTL_BBPLL_FORCE_PD (BIT(10)) + +/* RTC_CNTL_BBPLL_I2C_FORCE_PD : R/W ;bitpos:[8] ;default: 1'b0 ; + * description: BB_PLL _I2C force power down + */ + +#define RTC_CNTL_BBPLL_I2C_FORCE_PD (BIT(8)) + +/* RTC_CNTL_PLLA_FORCE_PD : R/W ;bitpos:[23] ;default: 1'b1 ; + * description: PLLA force power down + */ + +#define RTC_CNTL_PLLA_FORCE_PD (BIT(23)) +#define RTC_CNTL_PLLA_FORCE_PD_S 23 + +/* RTC_CNTL_BIAS_I2C_FORCE_PD : R/W ;bitpos:[18] ;default: 1'b0 ; + * description: BIAS_I2C force power down + */ + +#define RTC_CNTL_BIAS_I2C_FORCE_PD (BIT(18)) + +#define MHZ (1000000) +#define RTC_PLL_FREQ_320M 320 +#define RTC_PLL_FREQ_480M 480 + #endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_SOC_H */ diff --git a/boards/xtensa/esp32/esp32-core/include/board.h b/boards/xtensa/esp32/esp32-core/include/board.h index 264238df0d..088473976c 100644 --- a/boards/xtensa/esp32/esp32-core/include/board.h +++ b/boards/xtensa/esp32/esp32-core/include/board.h @@ -70,13 +70,17 @@ * which is 40MHz by default. * * Reference: - * https://github.com/espressif/esp-idf/blob/6fd855ab8d00d23bad4660216bc2122c2285d5be/components/bootloader_support/src/bootloader_clock.c#L38-L62 + * https://bit.ly/3aJhjPH (shorten URL to avoid nxstyle issues) */ #ifdef CONFIG_ESP32CORE_RUN_IRAM # define BOARD_CLOCK_FREQUENCY (2 * BOARD_XTAL_FREQUENCY) #else +#ifdef CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ +# define BOARD_CLOCK_FREQUENCY (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000) +#else # define BOARD_CLOCK_FREQUENCY 80000000 #endif +#endif #endif /* __BOARDS_XTENSA_ESP32_ESP32_CORE_INCLUDE_BOARD_H */