diff --git a/components/esp_hw_support/include/esp_private/esp_regdma.h b/components/esp_hw_support/include/esp_private/esp_regdma.h index 03b551d64b..9e904997f7 100644 --- a/components/esp_hw_support/include/esp_private/esp_regdma.h +++ b/components/esp_hw_support/include/esp_private/esp_regdma.h @@ -269,6 +269,13 @@ void *regdma_link_new_branch_wait_default(void *backup, uint32_t value, uint32_t */ void *regdma_link_init(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, ...); +/** + * @brief Get REGDMA linked list node mode through configuration parameters + * @param config REGDMA linked node configuration parameters + * @return REGDMA linked list node mode + */ +regdma_link_mode_t regdma_link_get_config_mode(const regdma_link_config_t *config); + /** * @brief Recurse the REGDMA linked list and call the hook subroutine for each node * @param link The REGDMA linkded list head pointer diff --git a/components/esp_hw_support/port/regdma_link.c b/components/esp_hw_support/port/regdma_link.c index 0af808ae32..a090ea0b25 100644 --- a/components/esp_hw_support/port/regdma_link.c +++ b/components/esp_hw_support/port/regdma_link.c @@ -842,3 +842,10 @@ void regdma_link_dump(FILE *out, void *link, int entry) fprintf(out, "This REGDMA linked list is empty!\n"); } } + + +regdma_link_mode_t regdma_link_get_config_mode(const regdma_link_config_t *config) +{ + assert(config != NULL); + return (regdma_link_mode_t)config->head.mode; +} diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c index ee9a512c13..8f57dbd136 100644 --- a/components/esp_hw_support/sleep_retention.c +++ b/components/esp_hw_support/sleep_retention.c @@ -21,6 +21,9 @@ #include "sdkconfig.h" #include "esp_pmu.h" +#if SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE && CONFIG_IDF_TARGET_ESP32C5 // TODO: PM-202 +#include "soc/pmu_reg.h" // for PMU_DATE_REG, it can provide full 32 bit read and write access +#endif #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "hal/cache_ll.h" #endif @@ -493,8 +496,9 @@ static void sleep_retention_entries_destroy(sleep_retention_module_t module) static esp_err_t sleep_retention_entries_create_impl(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, sleep_retention_module_t module) { + esp_err_t err = ESP_OK; _lock_acquire_recursive(&s_retention.lock); - for (int i = num - 1; i >= 0; i--) { + for (int i = num - 1; (i >= 0) && (err == ESP_OK); i--) { #if SOC_PM_RETENTION_HAS_CLOCK_BUG if ((retent[i].owner > BIT(EXTRA_LINK_NUM)) && (retent[i].config.id != 0xffff)) { _lock_release_recursive(&s_retention.lock); @@ -502,16 +506,40 @@ static esp_err_t sleep_retention_entries_create_impl(const sleep_retention_entri return ESP_ERR_NOT_SUPPORTED; } #endif - void *link = sleep_retention_entries_try_create(&retent[i].config, retent[i].owner, priority, module); - if (link == NULL) { - _lock_release_recursive(&s_retention.lock); - sleep_retention_entries_do_destroy(module); - return ESP_ERR_NO_MEM; +#if SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE && CONFIG_IDF_TARGET_ESP32C5 // TODO: PM-202 + /* There is a bug in REGDMA wait mode, when two wait nodes need to wait for the + * same value (_val & _mask), the second wait node will immediately return to + * wait done, The reason is that the wait mode comparison output logic immediate + * compares the value of the previous wait register cached inside the + * digital logic before reading out he register contents specified by _backup. + */ + #define config_is_wait_mode(_config) (regdma_link_get_config_mode(_config) == REGDMA_LINK_MODE_WAIT) + if ((retent[i].config.id != 0xffff) && config_is_wait_mode(&(retent[i].config)) && (retent[i].config.id != 0xfffe)) { + uint32_t value = retent[i].config.write_wait.value; + uint32_t mask = retent[i].config.write_wait.mask; + bool skip_b = retent[i].config.head.skip_b; + bool skip_r = retent[i].config.head.skip_r; + sleep_retention_entries_config_t wait_bug_workaround[] = { + [0] = { .config = REGDMA_LINK_WRITE_INIT(0xfffe, PMU_DATE_REG, ~value, mask, skip_b, skip_r), .owner = retent[i].owner }, + [1] = { .config = REGDMA_LINK_WAIT_INIT (0xfffe, PMU_DATE_REG, ~value, mask, skip_b, skip_r), .owner = retent[i].owner } + }; + err = sleep_retention_entries_create_impl(wait_bug_workaround, ARRAY_SIZE(wait_bug_workaround), priority, module); + } +#endif + if (err == ESP_OK) { + void *link = sleep_retention_entries_try_create(&retent[i].config, retent[i].owner, priority, module); + if (link == NULL) { + _lock_release_recursive(&s_retention.lock); + sleep_retention_entries_do_destroy(module); + return ESP_ERR_NO_MEM; + } + sleep_retention_entries_update(retent[i].owner, link, priority); + } else { + break; } - sleep_retention_entries_update(retent[i].owner, link, priority); } _lock_release_recursive(&s_retention.lock); - return ESP_OK; + return err; } static esp_err_t sleep_retention_entries_create_bonding(regdma_link_priority_t priority, sleep_retention_module_t module) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 6ec7747d57..25f36e8e62 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1275,6 +1275,10 @@ config SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE bool default y +config SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE + bool + default y + config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 46bd1478b5..53c9f88693 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -566,6 +566,8 @@ #define SOC_PM_PAU_LINK_NUM (5) #define SOC_PM_PAU_REGDMA_LINK_CONFIGURABLE (1) +#define SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE (1) + /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (1) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index e8efdea1d2..b622e04558 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1411,6 +1411,10 @@ config SOC_PM_PAU_REGDMA_LINK_WIFIMAC bool default y +config SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE + bool + default y + config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index e72de5f3c1..e432d7c75a 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -556,6 +556,8 @@ #define SOC_PM_PAU_REGDMA_LINK_MULTI_ADDR (1) #define SOC_PM_PAU_REGDMA_LINK_WIFIMAC (1) +#define SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE (1) + /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (1) diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index c269b8285b..153d9499fa 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1351,6 +1351,10 @@ config SOC_PM_PAU_REGDMA_LINK_WIFIMAC bool default y +config SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE + bool + default y + config SOC_EXT_MEM_CACHE_TAG_IN_CPU_DOMAIN bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index b3d94ff610..81792da712 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -533,6 +533,8 @@ #define SOC_PM_PAU_REGDMA_LINK_MULTI_ADDR (1) #define SOC_PM_PAU_REGDMA_LINK_WIFIMAC (1) +#define SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE (1) + #define SOC_EXT_MEM_CACHE_TAG_IN_CPU_DOMAIN (1) #define SOC_PM_CPU_RETENTION_BY_SW (1) #define SOC_PM_MODEM_RETENTION_BY_REGDMA (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 2f4baf4dc8..5b2a8cef8d 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1783,6 +1783,10 @@ config SOC_CPU_IN_TOP_DOMAIN bool default y +config SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE + bool + default y + config SOC_PSRAM_VDD_POWER_MPLL bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 5a13faef8a..effc31f236 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -684,6 +684,8 @@ #define SOC_PAU_IN_TOP_DOMAIN (1) #define SOC_CPU_IN_TOP_DOMAIN (1) +#define SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE (1) + /*-------------------------- PSRAM CAPS ----------------------------*/ #define SOC_PSRAM_VDD_POWER_MPLL (1)