From: Ivan Grokhotkov Date: Wed, 1 Nov 2017 07:16:32 +0000 (+0800) Subject: soc/rtc: add function to get/set VDDSDIO configuration X-Git-Tag: v3.1-dev~104^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb9c106bcbbcc4e0f30bd7949eebf32824cb7a4d;p=esp-idf soc/rtc: add function to get/set VDDSDIO configuration Also consider case of VDDSDIO force powered on in rtc_sleep. --- diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index 6927716c62..2403638302 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -198,14 +198,22 @@ static void rtc_wdt_disable() * Placed into IRAM as flash may need some time to be powered on. */ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, - rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline)); + rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us, + rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline)); static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, - rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us) + rtc_cpu_freq_t cpu_freq, uint32_t flash_enable_time_us, + rtc_vddsdio_config_t vddsdio_config) { // Enter sleep esp_err_t err = esp_sleep_start(pd_flags); + // If VDDSDIO regulator was controlled by RTC registers before sleep, + // restore the configuration. + if (vddsdio_config.force) { + rtc_vddsdio_set_config(vddsdio_config); + } + // Restore CPU frequency rtc_clk_cpu_freq_set(cpu_freq); @@ -244,6 +252,7 @@ esp_err_t esp_light_sleep_start() s_config.sleep_duration -= flash_enable_time_us; } #endif //CONFIG_SPIRAM_SUPPORT + rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails rtc_wdt_enable(1000); @@ -252,7 +261,8 @@ esp_err_t esp_light_sleep_start() rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get(); // Enter sleep, then wait for flash to be ready on wakeup - esp_err_t err = esp_light_sleep_inner(pd_flags, cpu_freq, flash_enable_time_us); + esp_err_t err = esp_light_sleep_inner(pd_flags, cpu_freq, + flash_enable_time_us, vddsdio_config); // At this point, if FRC1 is used for timekeeping, time will be lagging behind. // This will update the microsecond count based on RTC timer. diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index f13c113b4e..e600e39e3c 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -554,6 +554,36 @@ typedef struct { */ void rtc_init(rtc_config_t cfg); +/** + * Structure describing vddsdio configuration + */ +typedef struct { + uint32_t force : 1; //!< If 1, use configuration from RTC registers; if 0, use EFUSE/bootstrapping pins. + uint32_t enable : 1; //!< Enable VDDSDIO regulator + uint32_t tieh : 1; //!< Select VDDSDIO voltage: 1 — 1.8V, 0 — 3.3V + uint32_t drefh : 2; //!< Tuning parameter for VDDSDIO regulator + uint32_t drefm : 2; //!< Tuning parameter for VDDSDIO regulator + uint32_t drefl : 2; //!< Tuning parameter for VDDSDIO regulator +} rtc_vddsdio_config_t; + +/** + * Get current VDDSDIO configuration + * If VDDSDIO configuration is overridden by RTC, get values from RTC + * Otherwise, if VDDSDIO is configured by EFUSE, get values from EFUSE + * Otherwise, use default values and the level of MTDI bootstrapping pin. + * @return currently used VDDSDIO configuration + */ +rtc_vddsdio_config_t rtc_vddsdio_get_config(); + +/** + * Set new VDDSDIO configuration using RTC registers. + * If config.force == 1, this overrides configuration done using bootstrapping + * pins and EFUSE. + * + * @param config new VDDSDIO configuration + */ +void rtc_vddsdio_set_config(rtc_vddsdio_config_t config); + #ifdef __cplusplus } diff --git a/components/soc/esp32/rtc_init.c b/components/soc/esp32/rtc_init.c index ff7b6b73cc..44786fbcc5 100644 --- a/components/soc/esp32/rtc_init.c +++ b/components/soc/esp32/rtc_init.c @@ -18,6 +18,8 @@ #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" #include "soc/dport_reg.h" +#include "soc/efuse_reg.h" +#include "soc/gpio_reg.h" void rtc_init(rtc_config_t cfg) @@ -94,3 +96,51 @@ void rtc_init(rtc_config_t cfg) CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_NOISO); } } + +rtc_vddsdio_config_t rtc_vddsdio_get_config() +{ + rtc_vddsdio_config_t result; + uint32_t sdio_conf_reg = REG_READ(RTC_CNTL_SDIO_CONF_REG); + result.drefh = (sdio_conf_reg & RTC_CNTL_DREFH_SDIO_M) >> RTC_CNTL_DREFH_SDIO_S; + result.drefm = (sdio_conf_reg & RTC_CNTL_DREFM_SDIO_M) >> RTC_CNTL_DREFM_SDIO_S; + result.drefl = (sdio_conf_reg & RTC_CNTL_DREFL_SDIO_M) >> RTC_CNTL_DREFL_SDIO_S; + if (sdio_conf_reg & RTC_CNTL_SDIO_FORCE) { + // Get configuration from RTC + result.force = 1; + result.enable = (sdio_conf_reg & RTC_CNTL_XPD_SDIO_REG_M) >> RTC_CNTL_XPD_SDIO_REG_S; + result.tieh = (sdio_conf_reg & RTC_CNTL_SDIO_TIEH_M) >> RTC_CNTL_SDIO_TIEH_S; + return result; + } + uint32_t efuse_reg = REG_READ(EFUSE_BLK0_RDATA4_REG); + if (efuse_reg & EFUSE_RD_SDIO_FORCE) { + // Get configuration from EFUSE + result.force = 0; + result.enable = (efuse_reg & EFUSE_RD_XPD_SDIO_REG_M) >> EFUSE_RD_XPD_SDIO_REG_S; + result.tieh = (efuse_reg & EFUSE_RD_SDIO_TIEH_M) >> EFUSE_RD_SDIO_TIEH_S; + // in this case, DREFH/M/L are also set from EFUSE + result.drefh = (efuse_reg & EFUSE_RD_SDIO_DREFH_M) >> EFUSE_RD_SDIO_DREFH_S; + result.drefm = (efuse_reg & EFUSE_RD_SDIO_DREFM_M) >> EFUSE_RD_SDIO_DREFM_S; + result.drefl = (efuse_reg & EFUSE_RD_SDIO_DREFL_M) >> EFUSE_RD_SDIO_DREFL_S; + return result; + } + + // Otherwise, VDD_SDIO is controlled by bootstrapping pin + uint32_t strap_reg = REG_READ(GPIO_STRAP_REG); + result.force = 0; + result.tieh = (strap_reg & BIT(5)) ? 0 : 1; + result.enable = result.tieh == 0; // only power on the regulator if VDD=1.8 + return result; +} + +void rtc_vddsdio_set_config(rtc_vddsdio_config_t config) +{ + uint32_t val = 0; + val |= (config.force << RTC_CNTL_SDIO_FORCE_S); + val |= (config.enable << RTC_CNTL_XPD_SDIO_REG_S); + val |= (config.drefh << RTC_CNTL_DREFH_SDIO_S); + val |= (config.drefm << RTC_CNTL_DREFM_SDIO_S); + val |= (config.drefl << RTC_CNTL_DREFL_SDIO_S); + val |= (config.tieh << RTC_CNTL_SDIO_TIEH_S); + val |= RTC_CNTL_SDIO_PD_EN; + REG_WRITE(RTC_CNTL_SDIO_CONF_REG, val); +} diff --git a/components/soc/esp32/rtc_sleep.c b/components/soc/esp32/rtc_sleep.c index 0b20692fa0..82a04d8cab 100644 --- a/components/soc/esp32/rtc_sleep.c +++ b/components/soc/esp32/rtc_sleep.c @@ -198,11 +198,9 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0); } - if (cfg.vddsdio_pd_en) { - SET_PERI_REG_MASK(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN); - } else { - CLEAR_PERI_REG_MASK(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN); - } + /* enable VDDSDIO control by state machine */ + REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE); + REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en); REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_SLP, cfg.rtc_dbias_slp); REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, cfg.rtc_dbias_wak);