diff --git a/components/bootloader_support/src/bootloader_console.c b/components/bootloader_support/src/bootloader_console.c index 2029ea31b6..f248434e59 100644 --- a/components/bootloader_support/src/bootloader_console.c +++ b/components/bootloader_support/src/bootloader_console.c @@ -106,6 +106,7 @@ void bootloader_console_init(void) esp_rom_uart_set_as_console(ESP_ROM_USB_OTG_NUM); esp_rom_install_channel_putc(1, bootloader_console_write_char_usb); #if SOC_USB_SERIAL_JTAG_SUPPORTED + usb_phy_ll_usb_wrap_pad_enable(&USB_WRAP, true); usb_phy_ll_int_otg_enable(&USB_WRAP); #endif } diff --git a/components/driver/usb_serial_jtag/usb_serial_jtag.c b/components/driver/usb_serial_jtag/usb_serial_jtag.c index 01df0ae39c..e63da82bf5 100644 --- a/components/driver/usb_serial_jtag/usb_serial_jtag.c +++ b/components/driver/usb_serial_jtag/usb_serial_jtag.c @@ -15,7 +15,15 @@ #include "esp_intr_alloc.h" #include "driver/usb_serial_jtag.h" #include "soc/periph_defs.h" +#include "soc/soc_caps.h" #include "esp_check.h" +#include "esp_private/periph_ctrl.h" + +#if !SOC_RCC_IS_INDEPENDENT +#define USJ_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define USJ_RCC_ATOMIC() +#endif // The hardware buffer max size is 64 #define USB_SER_JTAG_ENDP_SIZE (64) @@ -151,6 +159,11 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se goto _exit; } + // Enable USB-Serial-JTAG peripheral module clock + USJ_RCC_ATOMIC() { + usb_serial_jtag_ll_enable_bus_clock(true); + } + // Configure PHY usb_phy_ll_int_jtag_enable(&USB_SERIAL_JTAG); @@ -214,6 +227,7 @@ esp_err_t usb_serial_jtag_driver_uninstall(void) return ESP_OK; } + /* Not disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */ //Disable tx/rx interrupt. usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); esp_intr_free(p_usb_serial_jtag_obj->intr_handle); diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index f996e17e52..63e160c918 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -27,6 +27,7 @@ if(NOT BOOTLOADER_BUILD) "revision.c" "rtc_module.c" "sleep_modes.c" + "sleep_console.c" "sleep_gpio.c" "sleep_event.c" "sleep_modem.c" diff --git a/components/esp_hw_support/include/esp_private/sleep_console.h b/components/esp_hw_support/include/esp_private/sleep_console.h new file mode 100644 index 0000000000..612c51692c --- /dev/null +++ b/components/esp_hw_support/include/esp_private/sleep_console.h @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_USB_SERIAL_JTAG_SUPPORTED +typedef struct { + bool usj_clock_enabled; + bool usj_pad_enabled; +} sleep_console_usj_enable_state_t; + +/** + * @brief Disable usb-serial-jtag pad during light sleep to avoid current leakage and + * backup the enable state before light sleep + */ +void sleep_console_usj_pad_backup_and_disable(void); + +/** + * @brief Restore initial usb-serial-jtag pad enable state when wakeup from light sleep + */ +void sleep_console_usj_pad_restore(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index f7b88173cb..4f366e13f5 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -23,6 +23,8 @@ entries: rtc_time (noflash_text) if SOC_PMU_SUPPORTED = y: pmu_sleep (noflash) + if SOC_USB_SERIAL_JTAG_SUPPORTED = y: + sleep_console (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_console.c b/components/esp_hw_support/sleep_console.c new file mode 100644 index 0000000000..02a0f5bb27 --- /dev/null +++ b/components/esp_hw_support/sleep_console.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/soc_caps.h" +#include "esp_private/sleep_console.h" +#include "esp_attr.h" + +#if SOC_USB_SERIAL_JTAG_SUPPORTED +#include "hal/usb_serial_jtag_ll.h" + +static sleep_console_usj_enable_state_t s_usj_state = {0}; + +void sleep_console_usj_pad_backup_and_disable(void) +{ + // This function can be called in sleep process only, and sleep process code + // is in critical region and thread safe already, so to avoid build errors/warnings + // declare __DECLARE_RCC_ATOMIC_ENV here. + int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); + + s_usj_state.usj_clock_enabled = usb_serial_jtag_ll_module_is_enabled(); + if (!s_usj_state.usj_clock_enabled) { + // Enable USJ clock and clear reset + usb_serial_jtag_ll_enable_bus_clock(true); + usb_serial_jtag_ll_reset_register(); + } + s_usj_state.usj_pad_enabled = usb_serial_jtag_ll_pad_backup_and_disable(); + // Disable USJ clock + usb_serial_jtag_ll_enable_bus_clock(false); +} + +void sleep_console_usj_pad_restore(void) +{ + // This function can be called in sleep process only, and sleep process code + // is in critical region and thread safe already, so to avoid build errors/warnings + // declare __DECLARE_RCC_ATOMIC_ENV here. + int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); + + usb_serial_jtag_ll_enable_bus_clock(true); + usb_serial_jtag_ll_enable_pad(s_usj_state.usj_pad_enabled); + if (!s_usj_state.usj_clock_enabled) { + usb_serial_jtag_ll_enable_bus_clock(false); + } +} +#endif diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 6f8d6a07ef..01957e43f9 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -58,6 +58,7 @@ #include "esp_rom_uart.h" #include "esp_rom_sys.h" #include "esp_private/brownout.h" +#include "esp_private/sleep_console.h" #include "esp_private/sleep_cpu.h" #include "esp_private/sleep_modem.h" #include "esp_private/esp_clk.h" @@ -538,6 +539,10 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) } } } else { +#if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_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 CONFIG_MAC_BB_PD mac_bb_power_down_cb_execute(); #endif @@ -566,6 +571,9 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) */ FORCE_INLINE_ATTR void misc_modules_wake_prepare(void) { +#if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP + sleep_console_usj_pad_restore(); +#endif #if SOC_PM_RETENTION_HAS_REGDMA_POWER_BUG sleep_retention_do_system_retention(false); #endif diff --git a/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h index 0a6e382efd..2f8b667eb2 100644 --- a/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +7,11 @@ // The LL layer of the USB-serial-jtag controller #pragma once +#include +#include "esp_attr.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -168,6 +171,65 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void) USB_SERIAL_JTAG.ep1_conf.wr_done=1; } +/** + * @brief Disable usb serial jtag pad during light sleep to avoid current leakage + * + * @return Initial configuration of usb serial jtag pad enable before light sleep + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_pad_backup_and_disable(void) +{ + bool pad_enabled = USB_SERIAL_JTAG.conf0.usb_pad_enable; + + // Disable USB pad function + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + + return pad_enabled; +} + +/** + * @brief Enable the internal USJ PHY control to D+/D- pad + * + * @param enable_pad Enable the USJ PHY control to D+/D- pad + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_pad(bool enable_pad) +{ + USB_SERIAL_JTAG.conf0.usb_pad_enable = enable_pad; +} + +/** + * @brief Enable the bus clock for USB Serial_JTAG module + * @param clk_en True if enable the clock of USB Serial_JTAG module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + SYSTEM.perip_clk_en0.reg_usb_device_clk_en = clk_en; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_serial_jtag_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_serial_jtag_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the usb serial jtag module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + SYSTEM.perip_rst_en0.reg_usb_device_rst = 1; + SYSTEM.perip_rst_en0.reg_usb_device_rst = 0; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_serial_jtag_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_serial_jtag_ll_reset_register(__VA_ARGS__) + +/** + * Get the enable status USB Serial_JTAG module + * + * @return Return true if USB Serial_JTAG module is enabled + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (SYSTEM.perip_clk_en0.reg_usb_device_clk_en && !SYSTEM.perip_rst_en0.reg_usb_device_rst); +} + #ifdef __cplusplus } diff --git a/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h index 56abbf38b9..f29f12604a 100644 --- a/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h @@ -7,6 +7,9 @@ // The LL layer of the USB-serial-jtag controller #pragma once +#include +#include "esp_attr.h" +#include "soc/pcr_struct.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" @@ -169,6 +172,59 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void) } +/** + * @brief Disable usb serial jtag pad during light sleep to avoid current leakage + * + * @return Initial configuration of usb serial jtag pad enable before light sleep + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_pad_backup_and_disable(void) +{ + bool pad_enabled = USB_SERIAL_JTAG.conf0.usb_pad_enable; + + // Disable USB pad function + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + + return pad_enabled; +} + +/** + * @brief Enable the internal USJ PHY control to D+/D- pad + * + * @param enable_pad Enable the USJ PHY control to D+/D- pad + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_pad(bool enable_pad) +{ + USB_SERIAL_JTAG.conf0.usb_pad_enable = enable_pad; +} + +/** + * @brief Enable the bus clock for USB Serial_JTAG module + * @param clk_en True if enable the clock of USB Serial_JTAG module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + PCR.usb_device_conf.usb_device_clk_en = clk_en; +} + +/** + * @brief Reset the usb serial jtag module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + PCR.usb_device_conf.usb_device_rst_en = 1; + PCR.usb_device_conf.usb_device_rst_en = 0; +} + +/** + * Get the enable status USB Serial_JTAG module + * + * @return Return true if USB Serial_JTAG module is enabled + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (PCR.usb_device_conf.usb_device_clk_en && !PCR.usb_device_conf.usb_device_rst_en); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h index 0ad3980213..cdd5031615 100644 --- a/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h @@ -7,6 +7,9 @@ // The LL layer of the USB-serial-jtag controller #pragma once +#include +#include "esp_attr.h" +#include "soc/pcr_struct.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" @@ -168,6 +171,58 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void) USB_SERIAL_JTAG.ep1_conf.wr_done=1; } +/** + * @brief Disable usb serial jtag pad during light sleep to avoid current leakage + * + * @return Initial configuration of usb serial jtag pad enable before light sleep + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_pad_backup_and_disable(void) +{ + bool pad_enabled = USB_SERIAL_JTAG.conf0.usb_pad_enable; + + // Disable USB pad function + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + + return pad_enabled; +} + +/** + * @brief Enable the internal USJ PHY control to D+/D- pad + * + * @param enable_pad Enable the USJ PHY control to D+/D- pad + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_pad(bool enable_pad) +{ + USB_SERIAL_JTAG.conf0.usb_pad_enable = enable_pad; +} + +/** + * @brief Enable the bus clock for USB Serial_JTAG module + * @param clk_en True if enable the clock of USB Serial_JTAG module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + PCR.usb_device_conf.usb_device_clk_en = clk_en; +} + +/** + * @brief Reset the usb serial jtag module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + PCR.usb_device_conf.usb_device_rst_en = 1; + PCR.usb_device_conf.usb_device_rst_en = 0; +} + +/** + * Get the enable status USB Serial_JTAG module + * + * @return Return true if USB Serial_JTAG module is enabled + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (PCR.usb_device_conf.usb_device_clk_en && !PCR.usb_device_conf.usb_device_rst_en); +} #ifdef __cplusplus } diff --git a/components/hal/esp32s2/include/hal/usb_phy_ll.h b/components/hal/esp32s2/include/hal/usb_phy_ll.h index 9eaaa4ca9d..9c561cbb40 100644 --- a/components/hal/esp32s2/include/hal/usb_phy_ll.h +++ b/components/hal/esp32s2/include/hal/usb_phy_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #pragma once #include +#include "esp_attr.h" #include "soc/soc.h" #include "soc/system_reg.h" #include "soc/usb_wrap_struct.h" @@ -22,8 +23,6 @@ extern "C" { */ static inline void usb_phy_ll_int_otg_enable(usb_wrap_dev_t *hw) { - //Enable internal PHY - hw->otg_conf.pad_enable = 1; hw->otg_conf.phy_sel = 0; } @@ -59,6 +58,16 @@ static inline void usb_phy_ll_int_load_conf(usb_wrap_dev_t *hw, bool dp_pu, bool hw->otg_conf.val = conf.val; } +/** + * @brief Enable the internal PHY control to D+/D- pad + * @param hw Start address of the USB Wrap registers + * @param pad_en Enable the PHY control to D+/D- pad + */ +static inline void usb_phy_ll_usb_wrap_pad_enable(usb_wrap_dev_t *hw, bool pad_en) +{ + hw->otg_conf.pad_enable = pad_en; +} + /** * @brief Enable the internal PHY's test mode * @@ -79,6 +88,30 @@ static inline void usb_phy_ll_int_enable_test_mode(usb_wrap_dev_t *hw, bool en) } } +/** + * Enable the bus clock for USB Wrap module + * @param clk_en True if enable the clock of USB Wrap module + */ +FORCE_INLINE_ATTR void usb_phy_ll_usb_wrap_enable_bus_clock(bool clk_en) +{ + REG_SET_FIELD(DPORT_PERIP_CLK_EN0_REG, DPORT_USB_CLK_EN, clk_en); +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_phy_ll_usb_wrap_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_phy_ll_usb_wrap_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the USB Wrap module + */ +FORCE_INLINE_ATTR void usb_phy_ll_usb_wrap_reset_register(void) +{ + REG_SET_FIELD(DPORT_PERIP_RST_EN0_REG, DPORT_USB_RST, 1); + REG_SET_FIELD(DPORT_PERIP_RST_EN0_REG, DPORT_USB_RST, 0); +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_phy_ll_usb_wrap_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_phy_ll_usb_wrap_reset_register(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/usb_phy_ll.h b/components/hal/esp32s3/include/hal/usb_phy_ll.h index f9685ea36a..0045bc13a4 100644 --- a/components/hal/esp32s3/include/hal/usb_phy_ll.h +++ b/components/hal/esp32s3/include/hal/usb_phy_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +7,9 @@ #pragma once #include +#include "esp_attr.h" #include "soc/soc.h" -#include "soc/system_reg.h" +#include "soc/system_struct.h" #include "soc/usb_wrap_struct.h" #include "soc/rtc_cntl_struct.h" #include "soc/usb_serial_jtag_struct.h" @@ -24,7 +25,6 @@ extern "C" { */ static inline void usb_phy_ll_int_otg_enable(usb_wrap_dev_t *hw) { - hw->otg_conf.pad_enable = 1; // USB_OTG use internal PHY hw->otg_conf.phy_sel = 0; // phy_sel is controlled by the following register value @@ -107,6 +107,16 @@ static inline void usb_phy_ll_int_load_conf(usb_wrap_dev_t *hw, bool dp_pu, bool hw->otg_conf.val = conf.val; } +/** + * @brief Enable the internal PHY control to D+/D- pad + * @param hw Start address of the USB Wrap registers + * @param pad_en Enable the PHY control to D+/D- pad + */ +static inline void usb_phy_ll_usb_wrap_pad_enable(usb_wrap_dev_t *hw, bool pad_en) +{ + hw->otg_conf.pad_enable = pad_en; +} + /** * @brief Enable the internal PHY's test mode * @@ -127,6 +137,30 @@ static inline void usb_phy_ll_int_enable_test_mode(usb_wrap_dev_t *hw, bool en) } } +/** + * Enable the bus clock for USB Wrap module + * @param clk_en True if enable the clock of USB Wrap module + */ +FORCE_INLINE_ATTR void usb_phy_ll_usb_wrap_enable_bus_clock(bool clk_en) +{ + SYSTEM.perip_clk_en0.usb_clk_en = clk_en; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_phy_ll_usb_wrap_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_phy_ll_usb_wrap_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the USB Wrap module + */ +FORCE_INLINE_ATTR void usb_phy_ll_usb_wrap_reset_register(void) +{ + SYSTEM.perip_rst_en0.usb_rst = 1; + SYSTEM.perip_rst_en0.usb_rst = 0; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_phy_ll_usb_wrap_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_phy_ll_usb_wrap_reset_register(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h index 3c0053385c..3eecc0702f 100644 --- a/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,9 @@ // The LL layer of the USB-serial-jtag controller #pragma once +#include +#include "esp_attr.h" +#include "soc/system_struct.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" @@ -165,6 +168,64 @@ static inline void usb_serial_jtag_ll_txfifo_flush(void) USB_SERIAL_JTAG.ep1_conf.wr_done=1; } +/** + * @brief Disable usb serial jtag pad during light sleep to avoid current leakage + * + * @return Initial configuration of usb serial jtag pad enable before light sleep + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_pad_backup_and_disable(void) +{ + bool pad_enabled = USB_SERIAL_JTAG.conf0.usb_pad_enable; + + // Disable USB pad function + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + + return pad_enabled; +} + +/** + * @brief Enable the internal USJ PHY control to D+/D- pad + * + * @param enable_pad Enable the USJ PHY control to D+/D- pad + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_pad(bool enable_pad) +{ + USB_SERIAL_JTAG.conf0.usb_pad_enable = enable_pad; +} + +/** + * @brief Enable the bus clock for USB Serial_JTAG module + * @param clk_en True if enable the clock of USB Serial_JTAG module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + SYSTEM.perip_clk_en1.usb_device_clk_en = clk_en; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_serial_jtag_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_serial_jtag_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the usb serial jtag module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + SYSTEM.perip_rst_en1.usb_device_rst = 1; + SYSTEM.perip_rst_en1.usb_device_rst = 0; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_serial_jtag_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_serial_jtag_ll_reset_register(__VA_ARGS__) + +/** + * Get the enable status USB Serial_JTAG module + * + * @return Return true if USB Serial_JTAG module is enabled + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (SYSTEM.perip_clk_en1.usb_device_clk_en && !SYSTEM.perip_rst_en1.usb_device_rst); +} #ifdef __cplusplus } diff --git a/components/hal/usb_phy_hal.c b/components/hal/usb_phy_hal.c index 16a8f60d81..ec24d08aa3 100644 --- a/components/hal/usb_phy_hal.c +++ b/components/hal/usb_phy_hal.c @@ -20,6 +20,7 @@ void usb_phy_hal_otg_conf(usb_phy_hal_context_t *hal, usb_phy_target_t phy_targe if (phy_target == USB_PHY_TARGET_EXT) { usb_phy_ll_ext_otg_enable(hal->wrap_dev); } else if (phy_target == USB_PHY_TARGET_INT) { + usb_phy_ll_usb_wrap_pad_enable(hal->wrap_dev, true); usb_phy_ll_int_otg_enable(hal->wrap_dev); } } diff --git a/components/usb/usb_phy.c b/components/usb/usb_phy.c index 2ba62112bf..ec8dc35856 100644 --- a/components/usb/usb_phy.c +++ b/components/usb/usb_phy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,8 +17,15 @@ #include "esp_rom_gpio.h" #include "driver/gpio.h" #include "hal/gpio_ll.h" +#include "soc/soc_caps.h" #include "soc/usb_pins.h" +#if !SOC_RCC_IS_INDEPENDENT +#define USB_WRAP_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define USB_WRAP_RCC_ATOMIC() +#endif + static const char *USBPHY_TAG = "usb_phy"; #define USBPHY_NOT_INIT_ERR_STR "USB_PHY is not initialized" @@ -219,9 +226,12 @@ static esp_err_t usb_phy_install(void) portEXIT_CRITICAL(&phy_spinlock); goto cleanup; } + // Enable USB peripheral and reset the register portEXIT_CRITICAL(&phy_spinlock); - periph_module_enable(usb_otg_periph_signal.module); - periph_module_reset(usb_otg_periph_signal.module); + USB_WRAP_RCC_ATOMIC() { + usb_phy_ll_usb_wrap_enable_bus_clock(true); + usb_phy_ll_usb_wrap_reset_register(); + } return ESP_OK; cleanup: @@ -311,8 +321,10 @@ static void phy_uninstall(void) if (p_phy_ctrl_obj->ref_count == 0) { p_phy_ctrl_obj_free = p_phy_ctrl_obj; p_phy_ctrl_obj = NULL; - // Disable USB peripheral - periph_module_disable(usb_otg_periph_signal.module); + USB_WRAP_RCC_ATOMIC() { + // Disable USB peripheral without reset the module + usb_phy_ll_usb_wrap_enable_bus_clock(false); + } } portEXIT_CRITICAL(&phy_spinlock); free(p_phy_ctrl_obj_free); @@ -327,8 +339,9 @@ esp_err_t usb_del_phy(usb_phy_handle_t handle) if (handle->target == USB_PHY_TARGET_EXT) { p_phy_ctrl_obj->external_phy = NULL; } else { - // Clear pullup and pulldown loads on D+ / D- + // Clear pullup and pulldown loads on D+ / D-, and disable the pads usb_phy_ll_int_load_conf(handle->hal_context.wrap_dev, false, false, false, false); + usb_phy_ll_usb_wrap_pad_enable(handle->hal_context.wrap_dev, false); p_phy_ctrl_obj->internal_phy = NULL; } portEXIT_CRITICAL(&phy_spinlock);