From 51777a68626cf48ee3741013e2d71337c7c16d52 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Sun, 26 Feb 2023 23:09:02 +0800 Subject: [PATCH] gpio: Fix io hold functionality on esp32c6 and esp32h2 --- components/driver/gpio/gpio.c | 5 ++- components/driver/gpio/include/driver/gpio.h | 9 ++-- .../driver/test_apps/gpio/main/test_rtcio.c | 6 +-- components/esp_system/port/cpu_start.c | 2 + components/hal/esp32c6/include/hal/gpio_ll.h | 42 +++++++++--------- .../hal/esp32c6/include/hal/rtc_io_ll.h | 24 +--------- components/hal/esp32h2/include/hal/gpio_ll.h | 44 ++++++++++--------- components/hal/include/hal/gpio_hal.h | 6 ++- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32c6/include/soc/soc_caps.h | 4 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32h2/include/soc/soc_caps.h | 4 +- .../deep_sleep/main/deep_sleep_example_main.c | 2 + 13 files changed, 78 insertions(+), 78 deletions(-) diff --git a/components/driver/gpio/gpio.c b/components/driver/gpio/gpio.c index 610d38efcf..971b2ac5d7 100644 --- a/components/driver/gpio/gpio.c +++ b/components/driver/gpio/gpio.c @@ -734,6 +734,7 @@ esp_err_t gpio_hold_dis(gpio_num_t gpio_num) return ret; } +#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP void gpio_deep_sleep_hold_en(void) { portENTER_CRITICAL(&gpio_context.gpio_spinlock); @@ -747,9 +748,9 @@ void gpio_deep_sleep_hold_dis(void) gpio_hal_deep_sleep_hold_dis(gpio_context.gpio_hal); portEXIT_CRITICAL(&gpio_context.gpio_spinlock); } +#endif //!SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #if SOC_GPIO_SUPPORT_FORCE_HOLD - esp_err_t IRAM_ATTR gpio_force_hold_all() { #if SOC_RTCIO_HOLD_SUPPORTED @@ -771,7 +772,7 @@ esp_err_t IRAM_ATTR gpio_force_unhold_all() #endif return ESP_OK; } -#endif +#endif //SOC_GPIO_SUPPORT_FORCE_HOLD void gpio_iomux_in(uint32_t gpio, uint32_t signal_idx) { diff --git a/components/driver/gpio/include/driver/gpio.h b/components/driver/gpio/include/driver/gpio.h index f22d3d1e84..cc8cf8c9f5 100644 --- a/components/driver/gpio/include/driver/gpio.h +++ b/components/driver/gpio/include/driver/gpio.h @@ -374,10 +374,9 @@ esp_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t *stren * in output mode: the output level of the GPIO will be locked and can not be changed. * in input mode: the input read value can still reflect the changes of the input signal. * - * However, this function cannot be used to hold the state of a digital GPIO during Deep-sleep. Even if this - * function is enabled, the digital GPIO will be reset to its default state when the chip wakes up from - * Deep-sleep. If you want to hold the state of a digital GPIO during Deep-sleep, please call - * `gpio_deep_sleep_hold_en`. + * However, on ESP32/S2/C3/S3/C2, this function cannot be used to hold the state of a digital GPIO during Deep-sleep. + * Even if this function is enabled, the digital GPIO will be reset to its default state when the chip wakes up from + * Deep-sleep. If you want to hold the state of a digital GPIO during Deep-sleep, please call `gpio_deep_sleep_hold_en`. * * Power down or call `gpio_hold_dis` will disable this function. * @@ -408,6 +407,7 @@ esp_err_t gpio_hold_en(gpio_num_t gpio_num); */ esp_err_t gpio_hold_dis(gpio_num_t gpio_num); +#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP /** * @brief Enable all digital gpio pads hold function during Deep-sleep. * @@ -426,6 +426,7 @@ void gpio_deep_sleep_hold_en(void); * @brief Disable all digital gpio pads hold function during Deep-sleep. */ void gpio_deep_sleep_hold_dis(void); +#endif //!SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP /** * @brief Set pad input to a peripheral signal through the IOMUX. diff --git a/components/driver/test_apps/gpio/main/test_rtcio.c b/components/driver/test_apps/gpio/main/test_rtcio.c index 971711dcfd..a74ecdaaec 100644 --- a/components/driver/test_apps/gpio/main/test_rtcio.c +++ b/components/driver/test_apps/gpio/main/test_rtcio.c @@ -326,10 +326,9 @@ TEST_CASE("RTCIO_output_hold_test", "[rtcio]") ESP_LOGI(TAG, "RTCIO hold test over"); } -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6) // TODO: IDF-5349 Remove when deep sleep is supported on ESP32C6 // It is not necessary to test every rtcio pin, it will take too much ci testing time for deep sleep // Only tests on s_test_map[TEST_RTCIO_DEEP_SLEEP_PIN_INDEX] pin -// (ESP32: IO25, ESP32S2, S3: IO6) these pads' default configuration is low level +// (ESP32: IO25, ESP32S2, S3: IO6, C6: IO5) these pads' default configuration is low level #define TEST_RTCIO_DEEP_SLEEP_PIN_INDEX 5 static void rtcio_deep_sleep_hold_test_first_stage(void) @@ -375,5 +374,4 @@ static void rtcio_deep_sleep_hold_test_second_stage(void) TEST_CASE_MULTIPLE_STAGES("RTCIO_deep_sleep_output_hold_test", "[rtcio]", rtcio_deep_sleep_hold_test_first_stage, rtcio_deep_sleep_hold_test_second_stage) -#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C6, ESP32H2) -#endif // #if SOC_RTCIO_HOLD_SUPPORTED +#endif //SOC_RTCIO_HOLD_SUPPORTED diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index f641fdc7c0..c2aba37a42 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -541,10 +541,12 @@ void IRAM_ATTR call_start_cpu0(void) #endif #endif +#if !CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-6268 // Need to unhold the IOs that were hold right before entering deep sleep, which are used as wakeup pins if (rst_reas[0] == RESET_REASON_CORE_DEEP_SLEEP) { esp_deep_sleep_wakeup_io_reset(); } +#endif #if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP esp_cache_err_int_init(); diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index a6e64e3e5b..e92c1bc332 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -21,7 +21,7 @@ #include "soc/gpio_struct.h" #include "soc/lp_aon_struct.h" #include "soc/lp_io_struct.h" -#include "soc/pmu_reg.h" +#include "soc/pmu_struct.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/pcr_struct.h" #include "soc/clk_tree_defs.h" @@ -355,26 +355,6 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu *strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, FUN_DRV_S); } -/** - * @brief Enable all digital gpio pads hold function during Deep-sleep. - * - * @param hw Peripheral GPIO hardware instance address. - */ -static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) -{ - REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_HIGH_HP_PAD_HOLD_ALL); -} - -/** - * @brief Disable all digital gpio pads hold function during Deep-sleep. - * - * @param hw Peripheral GPIO hardware instance address. - */ -static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) -{ - REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_LOW_HP_PAD_HOLD_ALL); -} - /** * @brief Enable gpio pad hold function. * @@ -497,6 +477,26 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) } } +/** + * @brief Force hold digital io pad. + * @note GPIO force hold, whether the chip in sleep mode or wakeup mode. + */ +static inline void gpio_ll_force_hold_all(void) +{ + // WT flag, it gets self-cleared after the configuration is done + PMU.imm.pad_hold_all.tie_high_hp_pad_hold_all = 1; +} + +/** + * @brief Force unhold digital io pad. + * @note GPIO force unhold, whether the chip in sleep mode or wakeup mode. + */ +static inline void gpio_ll_force_unhold_all(void) +{ + // WT flag, it gets self-cleared after the configuration is done + PMU.imm.pad_hold_all.tie_low_hp_pad_hold_all = 1; +} + /** * @brief Enable GPIO pin to use sleep mode pin functions during light sleep. * diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index 7cf23de8ae..159e0fcdd1 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -30,8 +30,6 @@ extern "C" { #define RTCIO_LL_PIN_FUNC 0 -#define RTCIO_LL_PIN_MASK_ALL ((1 << SOC_RTCIO_PIN_COUNT) - 1) - typedef enum { RTCIO_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ @@ -244,22 +242,6 @@ static inline void rtcio_ll_force_hold_disable(int rtcio_num) LP_AON.gpio_hold0.gpio_hold0 &= ~BIT(rtcio_num); } -/** - * @brief Enable all LP IO pads hold function during Deep-sleep - */ -static inline void rtcio_ll_deep_sleep_hold_en_all(void) -{ - PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1; -} - -/** - * @brief Disable all LP IO pads hold function during Deep-sleep - */ -static inline void rtcio_ll_deep_sleep_hold_dis_all(void) -{ - PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1; -} - /** * Enable force hold function for all RTC IO pads * @@ -270,8 +252,7 @@ static inline void rtcio_ll_deep_sleep_hold_dis_all(void) */ static inline void rtcio_ll_force_hold_all(void) { - // No such a 'hold_all' bit on C6, use bit hold instead - LP_AON.gpio_hold0.gpio_hold0 |= RTCIO_LL_PIN_MASK_ALL; + PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1; } /** @@ -281,8 +262,7 @@ static inline void rtcio_ll_force_hold_all(void) */ static inline void rtcio_ll_force_unhold_all(void) { - // No such a 'hold_all' bit on C6, use bit hold instead - LP_AON.gpio_hold0.gpio_hold0 &= ~RTCIO_LL_PIN_MASK_ALL; + PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1; } /** diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h index 6d2e2abc71..e999d4e9f8 100644 --- a/components/hal/esp32h2/include/hal/gpio_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -20,7 +20,7 @@ #include "soc/gpio_periph.h" #include "soc/gpio_struct.h" #include "soc/lp_aon_struct.h" -#include "soc/pmu_reg.h" +#include "soc/pmu_struct.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/pcr_struct.h" #include "soc/clk_tree_defs.h" @@ -398,26 +398,6 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ *strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, FUN_DRV_S); } -/** - * @brief Enable all digital gpio pad hold function during Deep-sleep. - * - * @param hw Peripheral GPIO hardware instance address. - */ -static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw) -{ - REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_HIGH_HP_PAD_HOLD_ALL); -} - -/** - * @brief Disable all digital gpio pad hold function during Deep-sleep. - * - * @param hw Peripheral GPIO hardware instance address. - */ -static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw) -{ - REG_SET_BIT(PMU_IMM_PAD_HOLD_ALL_REG, PMU_TIE_LOW_HP_PAD_HOLD_ALL); -} - /** * @brief Enable gpio pad hold function. * @@ -522,6 +502,28 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) } } +/** + * @brief Force hold all digital(VDDPST2) and lp(VDDPST1) io pads. + * @note GPIO force hold, whether the chip in sleep mode or wakeup mode. + */ +static inline void gpio_ll_force_hold_all(void) +{ + // WT flags, they get self-cleared after the configuration is done + PMU.imm.pad_hold_all.tie_high_hp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1; +} + +/** + * @brief Force unhold all digital(VDDPST2) and lp(VDDPST1) io pads. + * @note GPIO force unhold, whether the chip in sleep mode or wakeup mode. + */ +static inline void gpio_ll_force_unhold_all(void) +{ + // WT flags, they get self-cleared after the configuration is done + PMU.imm.pad_hold_all.tie_low_hp_pad_hold_all = 1; + PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1; +} + /** * @brief Enable GPIO pin to use sleep mode pin functions during light sleep. * diff --git a/components/hal/include/hal/gpio_hal.h b/components/hal/include/hal/gpio_hal.h index b765e7c0b9..22fba943f7 100644 --- a/components/hal/include/hal/gpio_hal.h +++ b/components/hal/include/hal/gpio_hal.h @@ -242,8 +242,8 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, uint32_t gpio_num); * in output mode: the output level of the pad will be force locked and can not be changed. * in input mode: the input value read will not change, regardless the changes of input signal. * - * The state of digital gpio cannot be held during Deep-sleep, and it will resume the hold function - * when the chip wakes up from Deep-sleep. If the digital gpio also needs to be held during Deep-sleep, + * On ESP32/S2/C3/S3/C2, the state of digital gpio cannot be held during Deep-sleep, and it will resume the hold + * function when the chip wakes up from Deep-sleep. If the digital gpio also needs to be held during Deep-sleep, * `gpio_deep_sleep_hold_en` should also be called. * * Power down or call gpio_hold_dis will disable this function. @@ -285,6 +285,7 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, uint32_t gpio_num); */ #define gpio_hal_is_digital_io_hold(hal, gpio_num) gpio_ll_is_digital_io_hold((hal)->dev, gpio_num) +#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP /** * @brief Enable all digital gpio pad hold function during Deep-sleep. * @@ -315,6 +316,7 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, uint32_t gpio_num); * - false deep sleep hold is disabled */ #define gpio_hal_deep_sleep_hold_is_en(hal) gpio_ll_deep_sleep_hold_is_en((hal)->dev) +#endif //!SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP /** * @brief Set pad input to a peripheral signal through the IOMUX. diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 098dd3904d..49d9ca8f38 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -403,6 +403,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x000000007FFFFF00 +config SOC_GPIO_SUPPORT_FORCE_HOLD + bool + default y + config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 62f0120329..96e2a9c345 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -184,7 +184,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_8~GPIO_NUM_30) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x000000007FFFFF00ULL -// Support to hold a single GPIO when the digital domain is powered off +// Support to force hold all IOs +#define SOC_GPIO_SUPPORT_FORCE_HOLD (1) +// Support to hold a single digital I/O when the digital domain is powered off #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) /*-------------------------- RTCIO CAPS --------------------------------------*/ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index c66e51f6dc..795a6379c0 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -371,6 +371,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x000000000FFF807F +config SOC_GPIO_SUPPORT_FORCE_HOLD + bool + default y + config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index c1ad381f06..439b99a112 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -181,7 +181,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_0~6. GPIO_NUM_15~27) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x000000000FFF807FULL -// Support to hold a single GPIO when the digital domain is powered off +// Support to force hold all IOs +#define SOC_GPIO_SUPPORT_FORCE_HOLD (1) +// Support to hold a single digital I/O when the digital domain is powered off #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) /*-------------------------- Dedicated GPIO CAPS -----------------------------*/ diff --git a/examples/system/deep_sleep/main/deep_sleep_example_main.c b/examples/system/deep_sleep/main/deep_sleep_example_main.c index 4ae570e79d..b8e60afc6e 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -133,7 +133,9 @@ void app_main(void) * during deepsleep. However, RTC IO relies on the RTC_PERIPH power domain. Keeping this power domain on will * increase some power comsumption. */ # if CONFIG_EXAMPLE_EXT1_USE_INTERNAL_PULLUPS +#if SOC_PM_SUPPORT_RTC_PERIPH_PD ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON)); +#endif ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_1)); ESP_ERROR_CHECK(rtc_gpio_pulldown_en(ext_wakeup_pin_1)); ESP_ERROR_CHECK(rtc_gpio_pullup_dis(ext_wakeup_pin_2));