diff --git a/components/esp_hal_usb/esp32s3/include/hal/usb_wrap_ll.h b/components/esp_hal_usb/esp32s3/include/hal/usb_wrap_ll.h index 23a02a83441..c011f5e397e 100644 --- a/components/esp_hal_usb/esp32s3/include/hal/usb_wrap_ll.h +++ b/components/esp_hal_usb/esp32s3/include/hal/usb_wrap_ll.h @@ -17,6 +17,7 @@ /* ----------------------------- Macros & Types ----------------------------- */ #define USB_WRAP_LL_EXT_PHY_SUPPORTED 1 // Can route to an external FSLS PHY +#define USB_WRAP_LL_DEPENDS_ON_BBPLL 1 // USB PHY depends on BBPLL #ifdef __cplusplus extern "C" { diff --git a/components/esp_hw_support/include/esp_private/rtc_clk.h b/components/esp_hw_support/include/esp_private/rtc_clk.h index 9a27820d969..0f78de1404e 100644 --- a/components/esp_hw_support/include/esp_private/rtc_clk.h +++ b/components/esp_hw_support/include/esp_private/rtc_clk.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,9 +43,10 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void); /** * @brief Notify that the BBPLL has a new in-use consumer * - * Currently, this function is only used for tracking whether USB Serial/JTAG is using the 48MHz PHY clock + * Currently, this function is used for tracking whether USB PHY is using the 48MHz PHY clock. * - * Note: Calling this function only helps to not disable the BBPLL clock in `rtc_clk_cpu_freq_set_config`. + * The first consumer enables BBPLL analog power. Later `rtc_clk_cpu_freq_set_config` will not + * disable BBPLL while any consumer remains. */ void rtc_clk_bbpll_add_consumer(void); diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index 462084da08d..2f9c8808537 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s3/rtc_clk.c @@ -36,22 +36,36 @@ static uint32_t s_apb_freq; void rtc_clk_cpu_freq_to_xtal(int freq, int div); static void rtc_clk_cpu_freq_to_rc_fast(void); +static void rtc_clk_bbpll_enable(void); +static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq); extern uint32_t g_dig_dbias_pvt_240m; extern uint32_t g_rtc_dbias_pvt_240m; extern uint32_t g_dig_dbias_pvt_non_240m; extern uint32_t g_rtc_dbias_pvt_non_240m; -static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it only tracks whether the 48MHz PHY clock is in-use by USB Serial/JTAG +static uint32_t s_bbpll_digi_consumers_ref_count = 0; // Currently, it tracks whether the 48MHz PHY clock is in-use by USB void rtc_clk_bbpll_add_consumer(void) { - s_bbpll_digi_consumers_ref_count += 1; + // Should be refactored in PM-653 + if (s_bbpll_digi_consumers_ref_count == 0) { + if (s_cur_pll_freq == 0) { + rtc_clk_bbpll_enable(); + rtc_clk_bbpll_configure(rtc_clk_xtal_freq_get(), CLK_LL_PLL_480M_FREQ_MHZ); + } + } + s_bbpll_digi_consumers_ref_count++; } void rtc_clk_bbpll_remove_consumer(void) { - s_bbpll_digi_consumers_ref_count -= 1; + // Should be refactored in PM-653 + if (s_bbpll_digi_consumers_ref_count > 0) { + s_bbpll_digi_consumers_ref_count--; + } else { + ESP_HW_LOGW(TAG, "bbpll clk ref cnt mismatched!"); + } } void rtc_clk_32k_enable(bool enable) diff --git a/components/esp_hw_support/usb_phy/usb_phy.c b/components/esp_hw_support/usb_phy/usb_phy.c index 4570dfa0963..d5e78faa296 100644 --- a/components/esp_hw_support/usb_phy/usb_phy.c +++ b/components/esp_hw_support/usb_phy/usb_phy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,9 @@ #include "hal/usb_utmi_hal.h" #include "hal/gpio_ll.h" #include "soc/soc_caps.h" +#if USB_WRAP_LL_DEPENDS_ON_BBPLL +#include "esp_private/rtc_clk.h" +#endif #if SOC_USB_UTMI_PHY_NO_POWER_OFF_ISO #include "esp_private/sleep_usb.h" @@ -322,13 +325,6 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r } #endif - // For FSLS PHY that shares pads with GPIO peripheral, we must set drive capability to 3 (40mA) - if (phy_target == USB_PHY_TARGET_INT) { - assert(usb_dwc_info.controllers[otg11_index].internal_phy_io); - gpio_ll_set_drive_capability(GPIO_LL_GET_HW(0), usb_dwc_info.controllers[otg11_index].internal_phy_io->dm, GPIO_DRIVE_CAP_3); - gpio_ll_set_drive_capability(GPIO_LL_GET_HW(0), usb_dwc_info.controllers[otg11_index].internal_phy_io->dp, GPIO_DRIVE_CAP_3); - } - *handle_ret = (usb_phy_handle_t) phy_context; if (phy_target == USB_PHY_TARGET_EXT) { phy_context->iopins = (usb_phy_ext_io_conf_t *) calloc(1, sizeof(usb_phy_ext_io_conf_t)); @@ -344,6 +340,16 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r const usb_otg_signal_conn_t *otg_sig = usb_dwc_info.controllers[otg11_index].otg_signals; ESP_ERROR_CHECK(phy_otg_iopins_configure(config->otg_io_conf, otg_sig)); } + if (phy_target == USB_PHY_TARGET_INT) { +#if USB_WRAP_LL_DEPENDS_ON_BBPLL + // PHY clock is derived from BBPLL. Do not turn off BBPLL during low-power modes + rtc_clk_bbpll_add_consumer(); +#endif + // For FSLS internal PHY that shares pads with GPIO peripheral, we must set drive capability to 3 (40mA) + assert(usb_dwc_info.controllers[otg11_index].internal_phy_io); + gpio_ll_set_drive_capability(GPIO_LL_GET_HW(0), usb_dwc_info.controllers[otg11_index].internal_phy_io->dm, GPIO_DRIVE_CAP_3); + gpio_ll_set_drive_capability(GPIO_LL_GET_HW(0), usb_dwc_info.controllers[otg11_index].internal_phy_io->dp, GPIO_DRIVE_CAP_3); + } return ESP_OK; cleanup: @@ -389,6 +395,9 @@ esp_err_t usb_del_phy(usb_phy_handle_t handle) // Clear pullup and pulldown loads on D+ / D-, and disable the pads usb_wrap_hal_phy_disable_pull_override(&handle->wrap_hal); p_phy_ctrl_obj->fsls_phy = NULL; +#if USB_WRAP_LL_DEPENDS_ON_BBPLL + rtc_clk_bbpll_remove_consumer(); +#endif } else { // USB_PHY_TARGET_UTMI p_phy_ctrl_obj->utmi_phy = NULL; }