diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 7ede9c33d7..443121273a 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -29,6 +29,7 @@ if(NOT BOOTLOADER_BUILD) "sleep_modem.c" "sleep_modes.c" "sleep_console.c" + "sleep_usb.c" "sleep_gpio.c" "sleep_event.c" "regi2c_ctrl.c" diff --git a/components/esp_hw_support/include/esp_private/sleep_usb.h b/components/esp_hw_support/include/esp_private/sleep_usb.h new file mode 100644 index 0000000000..6ad693470a --- /dev/null +++ b/components/esp_hw_support/include/esp_private/sleep_usb.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD +/** + * @brief Backup usb OTG phy bus_clock / stoppclk configuration and + * before light sleep to avoid current leakage + */ +void sleep_usb_otg_phy_backup_and_disable(void); + +/** + * @brief Restore initial usb OTG phy configuration when wakeup from light sleep + */ +void sleep_usb_otg_phy_restore(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index 00bcae6634..4ba3061253 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -26,6 +26,8 @@ entries: pmu_param (noflash) if SOC_USB_SERIAL_JTAG_SUPPORTED = y: sleep_console (noflash) + if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD = y: + sleep_usb (noflash) if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y: rtc_wdt (noflash_text) if PERIPH_CTRL_FUNC_IN_IRAM = y: diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 122a21d6f3..b07b3c4ec4 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -69,6 +69,7 @@ #include "esp_private/sleep_console.h" #include "esp_private/sleep_cpu.h" #include "esp_private/sleep_modem.h" +#include "esp_private/sleep_usb.h" #include "esp_private/esp_clk.h" #include "esp_private/esp_task_wdt.h" #include "esp_private/sar_periph_ctrl.h" @@ -638,7 +639,7 @@ FORCE_INLINE_ATTR bool light_sleep_uart_prepare(uint32_t pd_flags, int64_t sleep /** * These save-restore workaround should be moved to lower layer */ -FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) +FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep, uint32_t pd_flags) { if (deep_sleep){ for (int n = 0; n < MAX_DSLP_HOOKS; n++) { @@ -651,6 +652,11 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) // Only avoid USJ pad leakage here, USB OTG pad leakage is prevented through USB Host driver. sleep_console_usj_pad_backup_and_disable(); #endif +#if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD + if (!(pd_flags & PMU_SLEEP_PD_CNNT)) { + sleep_usb_otg_phy_backup_and_disable(); + } +#endif #if CONFIG_MAC_BB_PD mac_bb_power_down_cb_execute(); #endif @@ -689,6 +695,11 @@ FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t pd_flags) #if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP sleep_console_usj_pad_restore(); +#endif +#if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD + if (!(pd_flags & PMU_SLEEP_PD_CNNT)) { + sleep_usb_otg_phy_restore(); + } #endif sar_periph_ctrl_power_enable(); #if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_RTCCNTL @@ -841,7 +852,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m } #endif // CONFIG_ULP_COPROC_ENABLED - misc_modules_sleep_prepare(deep_sleep); + misc_modules_sleep_prepare(deep_sleep, pd_flags); #if SOC_TOUCH_SENSOR_VERSION >= 2 if (deep_sleep) { diff --git a/components/esp_hw_support/sleep_usb.c b/components/esp_hw_support/sleep_usb.c new file mode 100644 index 0000000000..d6f88bd5ce --- /dev/null +++ b/components/esp_hw_support/sleep_usb.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/soc_caps.h" +#include "esp_private/sleep_usb.h" +#include "esp_attr.h" + +#if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD +#include "hal/usb_utmi_ll.h" +#include "hal/usb_dwc_ll.h" + +static bool s_usb_utmi_bus_clock_state, s_usb_utmi_stoppclk_state; + +void sleep_usb_otg_phy_backup_and_disable(void) +{ + s_usb_utmi_bus_clock_state = _usb_utmi_ll_bus_clock_is_enabled(); + if (!s_usb_utmi_bus_clock_state) { + _usb_utmi_ll_enable_bus_clock(true); + } + s_usb_utmi_stoppclk_state = usb_dwc_ll_get_stoppclk_st(&USB_DWC_HS); + usb_dwc_ll_set_stoppclk(&USB_DWC_HS, true); +} + +void sleep_usb_otg_phy_restore(void) +{ + _usb_utmi_ll_enable_bus_clock(true); + usb_dwc_ll_set_stoppclk(&USB_DWC_HS, s_usb_utmi_stoppclk_state); + if (!s_usb_utmi_bus_clock_state) { + _usb_utmi_ll_enable_bus_clock(false); + } +} +#endif diff --git a/components/hal/esp32p4/include/hal/usb_dwc_ll.h b/components/hal/esp32p4/include/hal/usb_dwc_ll.h index 6bb1b67480..c62df33089 100644 --- a/components/hal/esp32p4/include/hal/usb_dwc_ll.h +++ b/components/hal/esp32p4/include/hal/usb_dwc_ll.h @@ -6,8 +6,10 @@ #pragma once +#include #include #include +#include "esp_attr.h" #include "soc/usb_dwc_struct.h" #include "hal/usb_dwc_types.h" #include "hal/misc.h" @@ -987,6 +989,17 @@ static inline void usb_dwc_ll_qtd_get_status(usb_dwc_ll_dma_qtd_t *qtd, int *rem qtd->buffer_status_val = 0; } +// ---------------------------- Power and Clock Gating Register -------------------------------- +FORCE_INLINE_ATTR void usb_dwc_ll_set_stoppclk(usb_dwc_dev_t *hw, bool stop) +{ + hw->pcgcctl_reg.stoppclk = stop; +} + +FORCE_INLINE_ATTR bool usb_dwc_ll_get_stoppclk_st(usb_dwc_dev_t *hw) +{ + return hw->pcgcctl_reg.stoppclk; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/usb_utmi_ll.h b/components/hal/esp32p4/include/hal/usb_utmi_ll.h index f2ea99d8b6..1e1d078eb0 100644 --- a/components/hal/esp32p4/include/hal/usb_utmi_ll.h +++ b/components/hal/esp32p4/include/hal/usb_utmi_ll.h @@ -50,6 +50,16 @@ FORCE_INLINE_ATTR void _usb_utmi_ll_enable_bus_clock(bool clk_en) // HP_SYS_CLKRST.soc_clk_ctrlx and LP_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way #define usb_utmi_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_utmi_ll_enable_bus_clock(__VA_ARGS__) +/** + * Get the enable status of the USB UTMI PHY bus clock + * + * @return Return true if USB UTMI PHY bus clock is enabled + */ +FORCE_INLINE_ATTR bool _usb_utmi_ll_bus_clock_is_enabled(void) +{ + return (HP_SYS_CLKRST.soc_clk_ctrl1.reg_usb_otg20_sys_clk_en && LP_AON_CLKRST.hp_usb_clkrst_ctrl1.usb_otg20_phyref_clk_en); +} + /** * @brief Reset the USB UTMI PHY and USB_DWC_HS controller */