From 4776f73ca4651a5bb65b4db2407205c0dd39925e Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Tue, 8 Aug 2017 16:58:58 +0800 Subject: [PATCH] Disable some peripheral clocks when cpu starts All peripheral clocks are default enabled after chip is powered on. When CPU starts, if reset reason is CPU reset, disable those clocks that are not enabled before reset. Otherwise, disable all those useless clocks. These peripheral clocks must be enabled when the peripherals are initialized and disabled when they are deinitialized. --- components/esp32/clk.c | 88 ++++++++++++++++++++ components/esp32/cpu_start.c | 1 + components/esp32/include/esp_clk.h | 8 ++ components/soc/esp32/include/soc/dport_reg.h | 2 + 4 files changed, 99 insertions(+) diff --git a/components/esp32/clk.c b/components/esp32/clk.c index ab589fcdc..f9be8dac5 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -25,6 +25,8 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" +#include "soc/dport_reg.h" +#include "soc/i2s_reg.h" /* Number of cycles to wait from the 32k XTAL oscillator to consider it running. * Larger values increase startup delay. Smaller values may cause false positive @@ -125,3 +127,89 @@ static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk) ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); esp_clk_slowclk_cal_set(cal_val); } + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + +#if CONFIG_FREERTOS_UNICORE + RESET_REASON rst_reas[1]; +#else + RESET_REASON rst_reas[2]; +#endif + + rst_reas[0] = rtc_get_reset_reason(0); + +#if !CONFIG_FREERTOS_UNICORE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if ((rst_reas[0] >= TGWDT_CPU_RESET && rst_reas[0] <= RTCWDT_CPU_RESET) +#if !CONFIG_FREERTOS_UNICORE + || (rst_reas[1] >= TGWDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) +#endif + ) { + common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERI_CLK_EN_REG); + wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); + } + else { + common_perip_clk = DPORT_WDG_CLK_EN | + DPORT_I2S0_CLK_EN | + DPORT_UART1_CLK_EN | + DPORT_SPI_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_PCNT_CLK_EN | + DPORT_LEDC_CLK_EN | + DPORT_UHCI1_CLK_EN | + DPORT_TIMERGROUP1_CLK_EN | + DPORT_SPI_CLK_EN_2 | + DPORT_PWM0_CLK_EN | + DPORT_I2C_EXT1_CLK_EN | + DPORT_CAN_CLK_EN | + DPORT_PWM1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI_DMA_CLK_EN | + DPORT_UART2_CLK_EN | + DPORT_PWM2_CLK_EN | + DPORT_PWM3_CLK_EN; + hwcrypto_perip_clk = DPORT_PERI_EN_AES | + DPORT_PERI_EN_SHA | + DPORT_PERI_EN_RSA | + DPORT_PERI_EN_SECUREBOOT; + wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | + DPORT_WIFI_CLK_BT_EN_M | + DPORT_WIFI_CLK_UNUSED_BIT5 | + DPORT_WIFI_CLK_UNUSED_BIT12 | + DPORT_WIFI_CLK_SDIOSLAVE_EN | + DPORT_WIFI_CLK_SDIO_HOST_EN | + DPORT_WIFI_CLK_EMAC_EN; + } + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(0), I2S_CLKA_ENA); + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(1), I2S_CLKA_ENA); + + /* Disable some peripheral clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); + + /* Disable hardware crypto clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, hwcrypto_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); +} diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 7fec14f3c..574179c08 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -238,6 +238,7 @@ void start_cpu0_default(void) trax_start_trace(TRAX_DOWNCOUNT_WORDS); #endif esp_clk_init(); + esp_perip_clk_init(); intr_matrix_clear(); #ifndef CONFIG_CONSOLE_UART_NONE uart_div_modify(CONFIG_CONSOLE_UART_NUM, (rtc_clk_apb_freq_get() << 4) / CONFIG_CONSOLE_UART_BAUDRATE); diff --git a/components/esp32/include/esp_clk.h b/components/esp32/include/esp_clk.h index 7b9c64c69..5c6f5cb87 100644 --- a/components/esp32/include/esp_clk.h +++ b/components/esp32/include/esp_clk.h @@ -54,3 +54,11 @@ uint32_t esp_clk_slowclk_cal_get(); */ void esp_clk_slowclk_cal_set(uint32_t value); +/** + * @brief Disables clock of some peripherals + * + * Called from cpu_start.c, not intended to be called from other places. + * This function disables clock of useless peripherals when cpu starts. + */ +void esp_perip_clk_init(void); + diff --git a/components/soc/esp32/include/soc/dport_reg.h b/components/soc/esp32/include/soc/dport_reg.h index 56e18246d..98e603652 100644 --- a/components/soc/esp32/include/soc/dport_reg.h +++ b/components/soc/esp32/include/soc/dport_reg.h @@ -1055,6 +1055,8 @@ #define DPORT_WIFI_CLK_BT_EN_S 11 /* Remaining single bit clock masks */ #define DPORT_WIFI_CLK_SDIOSLAVE_EN BIT(4) +#define DPORT_WIFI_CLK_UNUSED_BIT5 BIT(5) +#define DPORT_WIFI_CLK_UNUSED_BIT12 BIT(12) #define DPORT_WIFI_CLK_SDIO_HOST_EN BIT(13) #define DPORT_WIFI_CLK_EMAC_EN BIT(14) #define DPORT_WIFI_CLK_RNG_EN BIT(15)