diff --git a/components/esp_hw_support/lowpower/port/esp32h21/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32h21/sleep_clock.c index 7c2b48457a..3222682b24 100644 --- a/components/esp_hw_support/lowpower/port/esp32h21/sleep_clock.c +++ b/components/esp_hw_support/lowpower/port/esp32h21/sleep_clock.c @@ -1,37 +1,27 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "esp_private/sleep_clock.h" #include "soc/pcr_reg.h" -#include "modem/i2c_ana_mst_reg.h" #include "modem/modem_syscon_reg.h" #include "modem/modem_lpcon_reg.h" - +#include "modem/i2c_ana_mst_reg.h" +#include "soc/pmu_reg.h" +#include "soc/lp_analog_peri_reg.h" ESP_LOG_ATTR_TAG(TAG, "sleep_clock"); esp_err_t sleep_clock_system_retention_init(void *arg) { #define N_REGS_PCR() (((PCR_PWDET_SAR_CLK_CONF_REG - DR_REG_PCR_BASE) / 4) + 1) - const static sleep_retention_entries_config_t pcr_regs_retention[] = { - /* Enable i2c master clock */ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(0), MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN, MODEM_LPCON_CLK_I2C_MST_EN_M, 1, 0), .owner = ENTRY(0) }, - /* Start BBPLL self-calibration */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(1), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, - [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(2), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, - /* Wait calibration done */ - [3] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(3), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE, I2C_MST_BBPLL_CAL_DONE, 1, 0), .owner = ENTRY(0) }, - /* Stop BBPLL self-calibration */ - [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(4), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, - [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(5), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, /* Clock configuration retention */ - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(6), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(7), PCR_BUS_CLK_UPDATE_REG, PCR_BUS_CLOCK_UPDATE, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [8] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(8), PCR_BUS_CLK_UPDATE_REG, 0x0, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PCR_LINK(0), DR_REG_PCR_BASE, DR_REG_PCR_BASE, N_REGS_PCR(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_PCR_LINK(2), PCR_BUS_CLK_UPDATE_REG, PCR_BUS_CLOCK_UPDATE, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_PCR_LINK(3), PCR_BUS_CLK_UPDATE_REG, 0x0, PCR_BUS_CLOCK_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; esp_err_t err = sleep_retention_entries_create(pcr_regs_retention, ARRAY_SIZE(pcr_regs_retention), REGDMA_LINK_PRI_SYS_CLK, SLEEP_RETENTION_MODULE_CLOCK_SYSTEM); @@ -42,14 +32,29 @@ esp_err_t sleep_clock_system_retention_init(void *arg) #undef N_REGS_PCR } -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_CONF_RETENTION esp_err_t sleep_clock_modem_retention_init(void *arg) { #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) - #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) + #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) + /* In ESP32H21, the I2C control registers, syscon is placed in the modem domain, lpcon is placed in the top domain, + and the BBPL requires I2C for calibration. This is the reason why the code for the BPLL enableq + section needs to be placed in this function.*/ const static sleep_retention_entries_config_t modem_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + /* SYSCON LPCON configuration retention */ + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK (0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM LPCON */ + /* Enable i2c master clock */ + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(1), MODEM_LPCON_CLK_CONF_REG, MODEM_LPCON_CLK_I2C_MST_EN, MODEM_LPCON_CLK_I2C_MST_EN_M, 1, 0), .owner = ENTRY(0) }, + /* Start BBPLL self-calibration */ + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(2), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(3), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_LOW, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, + /* Wait calibration done */ + [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_MODEMSYSCON_LINK(4), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_CAL_DONE, I2C_MST_BBPLL_CAL_DONE, 1, 0), .owner = ENTRY(0) }, + /* Stop BBPLL self-calibration */ + [6] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(5), I2C_ANA_MST_ANA_CONF0_REG, 0, I2C_MST_BBPLL_STOP_FORCE_LOW, 1, 0), .owner = ENTRY(0) }, + [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(6), I2C_ANA_MST_ANA_CONF0_REG, I2C_MST_BBPLL_STOP_FORCE_HIGH, I2C_MST_BBPLL_STOP_FORCE_HIGH, 1, 0), .owner = ENTRY(0) }, }; esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); @@ -68,12 +73,14 @@ bool clock_domain_pd_allowed(void) const sleep_retention_module_bitmap_t created_modules = sleep_retention_get_created_modules(); const sleep_retention_module_bitmap_t sys_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap[SLEEP_RETENTION_MODULE_SYS_PERIPH >> 5] = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH % 32) }; - /* The clock and reset of MODEM (WiFi, BLE and 15.4) modules are managed + /* The clock and reset of MODEM (BLE and 15.4) modules are managed * through MODEM_SYSCON, when one or more MODEMs are initialized, it is * necessary to check the state of CLOCK_MODEM to determine MODEM domain on * or off. The clock and reset of digital peripherals are managed through * PCR, with TOP domain similar to MODEM domain. */ - __attribute__((unused)) sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; +#if SOC_BLE_SUPPORTED || SOC_IEEE802154_SUPPORTED + sleep_retention_module_bitmap_t modem_clk_dep_modules = (sleep_retention_module_bitmap_t){ .bitmap = { 0 } }; +#endif #if SOC_BT_SUPPORTED modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BLE_MAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_BLE_MAC % 32); modem_clk_dep_modules.bitmap[SLEEP_RETENTION_MODULE_BT_BB >> 5] |= BIT(SLEEP_RETENTION_MODULE_BT_BB % 32); @@ -96,7 +103,9 @@ bool clock_domain_pd_allowed(void) mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); } #endif - +#if SOC_PM_MODEM_CLK_CONF_RETENTION + mask.bitmap[SLEEP_RETENTION_MODULE_CLOCK_MODEM >> 5] |= BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM % 32); +#endif const sleep_retention_module_bitmap_t clock_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask); const sleep_retention_module_bitmap_t clock_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask); return sleep_retention_module_bitmap_eq(clock_domain_inited_modules, clock_domain_created_modules); @@ -110,12 +119,21 @@ ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, SECONDARY, BIT(0), 106) }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM, &init_param); -#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE +#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE || SOC_PM_MODEM_CLK_CONF_RETENTION init_param = (sleep_retention_module_init_param_t) { .cbs = { .create = { .handle = sleep_clock_modem_retention_init, .arg = NULL } }, +#if !SOC_PM_MODEM_CLK_CONF_RETENTION .attribute = SLEEP_RETENTION_MODULE_ATTR_PASSIVE +#endif }; sleep_retention_module_init(SLEEP_RETENTION_MODULE_CLOCK_MODEM, &init_param); #endif +#if SOC_PM_MODEM_CLK_CONF_RETENTION + if (sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_CLOCK_MODEM) != ESP_OK) { + // even though the modem clock retention module create failed, sleep process can be executed without pd the modem domain, so just warning here + ESP_LOGW(TAG, "create retention link failed on modem clock, modem power domain won't be turned off during sleep"); + } +#endif + return ESP_OK; } diff --git a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c index c21c2cb332..3a12d4fd12 100644 --- a/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c +++ b/components/esp_hw_support/lowpower/port/esp32h4/sleep_clock.c @@ -12,7 +12,7 @@ #include "soc/pmu_reg.h" #include "soc/lp_analog_peri_reg.h" -static const char *TAG = "sleep_clock"; +ESP_LOG_ATTR_TAG(TAG, "sleep_clock"); esp_err_t sleep_clock_system_retention_init(void *arg) { @@ -39,7 +39,7 @@ esp_err_t sleep_clock_modem_retention_init(void *arg) #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_RF2_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) #define N_REGS_LPCON() (((MODEM_LPCON_MEM_CONF_REG - MODEM_LPCON_TEST_CONF_REG) / 4) + 1) - /* In ESP32H4, the I2C control registers (syscon, lpcon) are placed in the modem domain, + /* In ESP32H4, the I2C control registers, syscon is placed in the modem domain, lpcon is placed in the top domain, and the BBPL requires I2C for calibration. This is the reason why the code for the BPLL enableq section needs to be placed in this function.*/ const static sleep_retention_entries_config_t modem_regs_retention[] = { diff --git a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in index 67017078ab..eae6f74628 100644 --- a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in @@ -955,6 +955,10 @@ config SOC_PM_MODEM_RETENTION_BY_REGDMA bool default y +config SOC_PM_MODEM_CLK_CONF_RETENTION + bool + default y + config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY bool default y diff --git a/components/soc/esp32h21/include/soc/soc_caps.h b/components/soc/esp32h21/include/soc/soc_caps.h index 295563cda8..75bda62788 100644 --- a/components/soc/esp32h21/include/soc/soc_caps.h +++ b/components/soc/esp32h21/include/soc/soc_caps.h @@ -460,6 +460,7 @@ #define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1) #define SOC_PM_CPU_RETENTION_BY_SW (1) #define SOC_PM_MODEM_RETENTION_BY_REGDMA (1) +#define SOC_PM_MODEM_CLK_CONF_RETENTION (1) /*!< In esp32H21, i2c lpcon is placed in top domain*/ #define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*!