From 1f524131b095af8dca28fd35534a02f931e094e8 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Sat, 28 Feb 2026 16:48:46 +0800 Subject: [PATCH] fix(esp_hw_support): fix analog i2c master race cause by phy retention link --- .../include/esp_private/sleep_modem.h | 7 ++++ .../lowpower/port/esp32c5/sleep_modem_state.c | 38 +++++++++++++++++- .../lowpower/port/esp32c6/sleep_modem_state.c | 40 ++++++++++++++++++- .../port/esp32c61/sleep_modem_state.c | 37 ++++++++++++++++- components/esp_hw_support/sleep_modem.c | 2 + 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/sleep_modem.h b/components/esp_hw_support/include/esp_private/sleep_modem.h index 6ff4517766..5e6aa72fa3 100644 --- a/components/esp_hw_support/include/esp_private/sleep_modem.h +++ b/components/esp_hw_support/include/esp_private/sleep_modem.h @@ -246,6 +246,13 @@ esp_err_t sleep_modem_state_phy_link_init(void **link_head); * - ESP_ERR_INVALID_STATE if the phy module retention state is invalid */ esp_err_t sleep_modem_state_phy_link_deinit(void *link_head); + +/** + * @brief Function to configure PHY link regdma description at runtime + * @param link_context PHY link regdma description conteoxt pointer + * @param flags A bitmap to indicate the PHY link regdma description configuration flag + */ +void sleep_modem_state_phy_link_config(void *link_context, uint32_t flags); #endif #ifdef __cplusplus diff --git a/components/esp_hw_support/lowpower/port/esp32c5/sleep_modem_state.c b/components/esp_hw_support/lowpower/port/esp32c5/sleep_modem_state.c index d4e029131b..b161ed38fa 100644 --- a/components/esp_hw_support/lowpower/port/esp32c5/sleep_modem_state.c +++ b/components/esp_hw_support/lowpower/port/esp32c5/sleep_modem_state.c @@ -5,6 +5,7 @@ */ #include "esp_log.h" #include "esp_check.h" +#include "esp_attr.h" #include "soc/soc_caps.h" #include "soc/i2c_ana_mst_reg.h" @@ -37,6 +38,13 @@ ESP_LOG_ATTR_TAG(TAG, "sleep"); #if SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC + +typedef struct { +#define DESC_IDX_I2C_MST_ENA (0) +#define DESC_IDX_I2C_MST_DIS (1) + void *regdma_desc[DESC_IDX_I2C_MST_DIS + 1]; +} sleep_modem_state_phy_link_context_t; + static esp_err_t sleep_modem_state_phy_wifi_init(void *arg) { #define WIFIMAC_ENTRY() (BIT(SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC)) @@ -98,13 +106,41 @@ esp_err_t sleep_modem_state_phy_link_init(void **link_head) if (err == ESP_OK) { err = sleep_retention_module_allocate(SLEEP_RETENTION_MODULE_MODEM_PHY); if (err == ESP_OK) { - *link_head = sleep_retention_find_link_by_id(REGDMA_PHY_LINK(0x00)); + const int id_array[] = { REGDMA_PHY_LINK(0x00), REGDMA_PHY_LINK(0x14) }; + static DRAM_ATTR sleep_modem_state_phy_link_context_t phy_link_context; + + for (int i = 0; (err == ESP_OK) && (i < ARRAY_SIZE(phy_link_context.regdma_desc)); i++) { + void *desc = sleep_retention_find_link_by_id(id_array[i]); + if (desc) { + phy_link_context.regdma_desc[i] = desc; + } else { + err = ESP_ERR_NOT_FOUND; + } + } + if (err == ESP_OK) { + *link_head = (void *)&phy_link_context; + } } } #endif return err; } +void IRAM_ATTR sleep_modem_state_phy_link_config(void *link_context, uint32_t flags) +{ +#if SOC_PM_PAU_REGDMA_LINK_IDX_WIFIMAC + sleep_modem_state_phy_link_context_t *phy_link_context = (sleep_modem_state_phy_link_context_t *)link_context; + + if (flags & BIT(0)) { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, true); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], true, true); + } else { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, false); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], false, true); + } +#endif +} + esp_err_t sleep_modem_state_phy_link_deinit(void *link_head) { esp_err_t err = ESP_OK; diff --git a/components/esp_hw_support/lowpower/port/esp32c6/sleep_modem_state.c b/components/esp_hw_support/lowpower/port/esp32c6/sleep_modem_state.c index b374b70669..3d12d1f080 100644 --- a/components/esp_hw_support/lowpower/port/esp32c6/sleep_modem_state.c +++ b/components/esp_hw_support/lowpower/port/esp32c6/sleep_modem_state.c @@ -3,6 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_attr.h" + #include "soc/soc_caps.h" #include "soc/i2c_ana_mst_reg.h" #include "soc/pmu_reg.h" @@ -32,6 +34,13 @@ #define MODEM_FE_DATA_BASE (0x600a0400) #define MODEM_FE_CTRL_BASE (0x600a0800) +typedef struct { +#define DESC_IDX_I2C_MST_ENA (0) +#define DESC_IDX_I2C_MST_SEL (1) +#define DESC_IDX_I2C_MST_DIS (2) + void *regdma_desc[DESC_IDX_I2C_MST_DIS + 1]; +} sleep_modem_state_phy_link_context_t; + esp_err_t sleep_modem_state_phy_link_init(void **link_head) { esp_err_t err = ESP_OK; @@ -105,12 +114,41 @@ esp_err_t sleep_modem_state_phy_link_init(void **link_head) } if (err == ESP_OK) { pau_regdma_set_modem_link_addr(link); - *link_head = link; + + const int id_array[] = { REGDMA_PHY_LINK(0x00), REGDMA_PHY_LINK(0x01), REGDMA_PHY_LINK(0x1b) }; + static DRAM_ATTR sleep_modem_state_phy_link_context_t phy_link_context; + + for (int i = 0; (err == ESP_OK) && (i < ARRAY_SIZE(phy_link_context.regdma_desc)); i++) { + void *desc = regdma_find_link_by_id(link, 0, id_array[i]); + if (desc) { + phy_link_context.regdma_desc[i] = desc; + } else { + err = ESP_ERR_NOT_FOUND; + } + } + if (err == ESP_OK) { + *link_head = (void *)&phy_link_context; + } } #endif return err; } +void IRAM_ATTR sleep_modem_state_phy_link_config(void *link_context, uint32_t flags) +{ + sleep_modem_state_phy_link_context_t *phy_link_context = (sleep_modem_state_phy_link_context_t *)link_context; + + if (flags & BIT(0)) { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, true); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_SEL], true, true); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], true, true); + } else { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, false); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_SEL], true, false); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], false, true); + } +} + esp_err_t sleep_modem_state_phy_link_deinit(void *link_head) { #if SOC_PM_PAU_REGDMA_LINK_WIFIMAC diff --git a/components/esp_hw_support/lowpower/port/esp32c61/sleep_modem_state.c b/components/esp_hw_support/lowpower/port/esp32c61/sleep_modem_state.c index b343bbe64b..55dfa60f14 100644 --- a/components/esp_hw_support/lowpower/port/esp32c61/sleep_modem_state.c +++ b/components/esp_hw_support/lowpower/port/esp32c61/sleep_modem_state.c @@ -3,6 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_attr.h" + #include "soc/soc_caps.h" #include "soc/i2c_ana_mst_reg.h" #include "soc/pmu_reg.h" @@ -30,6 +32,12 @@ #define WDEVTXQ_BLOCK (0x600a4ca8) #define WDEV_RXBLOCK (BIT(12)) +typedef struct { +#define DESC_IDX_I2C_MST_ENA (0) +#define DESC_IDX_I2C_MST_DIS (1) + void *regdma_desc[DESC_IDX_I2C_MST_DIS + 1]; +} sleep_modem_state_phy_link_context_t; + esp_err_t sleep_modem_state_phy_link_init(void **link_head) { esp_err_t err = ESP_OK; @@ -101,12 +109,39 @@ esp_err_t sleep_modem_state_phy_link_init(void **link_head) } if (err == ESP_OK) { pau_regdma_set_modem_link_addr(link); - *link_head = link; + + const int id_array[] = { REGDMA_PHY_LINK(0x00), REGDMA_PHY_LINK(0x1a) }; + static DRAM_ATTR sleep_modem_state_phy_link_context_t phy_link_context; + + for (int i = 0; (err == ESP_OK) && (i < ARRAY_SIZE(phy_link_context.regdma_desc)); i++) { + void *desc = regdma_find_link_by_id(link, 0, id_array[i]); + if (desc) { + phy_link_context.regdma_desc[i] = desc; + } else { + err = ESP_ERR_NOT_FOUND; + } + } + if (err == ESP_OK) { + *link_head = (void *)&phy_link_context; + } } #endif return err; } +void IRAM_ATTR sleep_modem_state_phy_link_config(void *link_context, uint32_t flags) +{ + sleep_modem_state_phy_link_context_t *phy_link_context = (sleep_modem_state_phy_link_context_t *)link_context; + + if (flags & BIT(0)) { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, true); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], true, true); + } else { + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_ENA], true, false); + regdma_link_set_skip_flag(phy_link_context->regdma_desc[DESC_IDX_I2C_MST_DIS], false, true); + } +} + esp_err_t sleep_modem_state_phy_link_deinit(void *link_head) { #if SOC_PM_PAU_REGDMA_LINK_WIFIMAC diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index ef8dc89bee..9bc27d130b 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -173,7 +173,9 @@ __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void) void IRAM_ATTR sleep_modem_wifi_do_phy_retention(bool restore) { + sleep_modem_state_phy_link_config(s_sleep_modem.wifi.phy_link, 1); sleep_retention_do_phy_retention(!restore); + sleep_modem_state_phy_link_config(s_sleep_modem.wifi.phy_link, 0); if (!restore) { s_sleep_modem.wifi.modem_state_phy_done = 1; }