mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(usb): add ESP32-S31 DWC/UTMI support
Add ESP32-S31 USB DWC/UTMI LL headers, SoC register structures, peripheral descriptors, capabilities, and linker mappings so the HS OTG controller and UTMI PHY can be built in esp_hal_usb. Introduce SOC_USB_FSLS_PHY_NUM on USB-OTG targets to separate FSLS USB_WRAP support from OTG/UTMI support. Use it to gate usb_wrap, the USB PHY driver, docs, and example build rules on targets without an FSLS PHY. Also add UTMI data pulldown control to the HAL, clear the boot-time DWC suspend state on ESP32-S31, alias the legacy internal PHY target to UTMI for backward compatibility, and extend usb_phy tests for UTMI-only targets.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
@@ -25,6 +25,12 @@
|
||||
#include "esp_sleep.h"
|
||||
#endif
|
||||
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
#define USB_PHY_FSLS_EXT_PHY_SUPPORTED USB_WRAP_LL_EXT_PHY_SUPPORTED
|
||||
#else
|
||||
#define USB_PHY_FSLS_EXT_PHY_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
static const char *USBPHY_TAG = "usb_phy";
|
||||
|
||||
#define USBPHY_NOT_INIT_ERR_STR "USB_PHY is not initialized"
|
||||
@@ -37,7 +43,9 @@ struct phy_context_t {
|
||||
usb_phy_status_t status; /**< PHY status */
|
||||
usb_otg_mode_t otg_mode; /**< USB OTG mode */
|
||||
usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
usb_wrap_hal_context_t wrap_hal; /**< USB WRAP HAL context */
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -138,24 +146,15 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
|
||||
// we support only fixed PHY to USB-DWC mapping:
|
||||
// USB-DWC2.0 <-> UTMI PHY
|
||||
// USB-DWC1.1 <-> FSLS PHY
|
||||
#if (SOC_USB_UTMI_PHY_NUM > 0)
|
||||
if (handle->target == USB_PHY_TARGET_UTMI) {
|
||||
// ESP32-P4 v3 changed connection between USB-OTG peripheral and UTMI PHY.
|
||||
// On v3 the 15k pulldown resistors on D+/D- are no longer controlled by USB-OTG,
|
||||
// but must be controlled directly by this software driver.
|
||||
#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
#include "soc/lp_system_struct.h"
|
||||
if (mode == USB_OTG_MODE_HOST) {
|
||||
// Host must connect 15k pulldown resistors on D+ / D-
|
||||
LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dppulldown = 1;
|
||||
LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dmpulldown = 1;
|
||||
} else {
|
||||
// Device must not connect any pulldown resistors on D+ / D-
|
||||
LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dppulldown = 0;
|
||||
LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dmpulldown = 0;
|
||||
}
|
||||
#endif // !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
// On some targets, the 15k pulldown resistors on D+/D- are not controlled
|
||||
// by the USB-OTG peripheral, but must be controlled by software.
|
||||
// Host mode: connect pulldowns; Device mode: disconnect pulldowns.
|
||||
usb_utmi_hal_enable_data_pulldowns(mode == USB_OTG_MODE_HOST);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
const usb_otg_signal_conn_t *otg_sig = usb_dwc_info.controllers[otg11_index].otg_signals;
|
||||
assert(otg_sig);
|
||||
@@ -164,6 +163,7 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
|
||||
gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->bvalid, GPIO_MATRIX_CONST_ZERO_INPUT, false);
|
||||
gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->vbusvalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // receiving a valid Vbus from host
|
||||
gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->avalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // HIGH to force USB host mode
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
if (handle->target == USB_PHY_TARGET_INT) {
|
||||
// Configure pull resistors for host
|
||||
usb_wrap_pull_override_vals_t vals = {
|
||||
@@ -174,6 +174,7 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
|
||||
};
|
||||
usb_wrap_hal_phy_enable_pull_override(&handle->wrap_hal, &vals);
|
||||
}
|
||||
#endif
|
||||
} else if (mode == USB_OTG_MODE_DEVICE) {
|
||||
gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->iddig, GPIO_MATRIX_CONST_ONE_INPUT, false); // connected connector is mini-B side
|
||||
gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->bvalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // HIGH to force USB device mode
|
||||
@@ -233,6 +234,18 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S31
|
||||
/*
|
||||
* ESP32-S31 exposes only the UTMI PHY to the USB OTG controller.
|
||||
* Keep backward compatibility with applications that still request
|
||||
* the legacy internal PHY target by aliasing it to UTMI.
|
||||
*/
|
||||
if (config->controller == USB_PHY_CTRL_OTG && phy_target == USB_PHY_TARGET_INT) {
|
||||
ESP_LOGW(USBPHY_TAG, "Using UTMI PHY instead of requested internal PHY");
|
||||
phy_target = USB_PHY_TARGET_UTMI;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_USB_UTMI_PHY_NO_POWER_OFF_ISO
|
||||
if (phy_target == USB_PHY_TARGET_UTMI) {
|
||||
esp_deep_sleep_register_hook(&sleep_usb_suppress_deepsleep_leakage);
|
||||
@@ -243,7 +256,10 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
|
||||
ESP_RETURN_ON_FALSE(phy_target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified PHY argument is invalid");
|
||||
ESP_RETURN_ON_FALSE(config->controller < USB_PHY_CTRL_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified source argument is invalid");
|
||||
ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT || config->ext_io_conf, ESP_ERR_INVALID_ARG, USBPHY_TAG, "ext_io_conf must be provided for ext PHY");
|
||||
#if !USB_WRAP_LL_EXT_PHY_SUPPORTED
|
||||
#if !SOC_USB_FSLS_PHY_NUM
|
||||
ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_INT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Internal FSLS PHY not supported on this target");
|
||||
ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Ext PHY not supported on this target");
|
||||
#elif !USB_PHY_FSLS_EXT_PHY_SUPPORTED
|
||||
ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Ext PHY not supported on this target");
|
||||
#endif
|
||||
#if !SOC_USB_UTMI_PHY_NUM
|
||||
@@ -276,20 +292,26 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
|
||||
phy_context->controller = config->controller;
|
||||
phy_context->status = USB_PHY_STATUS_IN_USE;
|
||||
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
if (phy_target != USB_PHY_TARGET_UTMI) {
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
usb_wrap_hal_init(&phy_context->wrap_hal);
|
||||
}
|
||||
} else {
|
||||
#if (SOC_USB_UTMI_PHY_NUM > 0)
|
||||
usb_utmi_hal_context_t utmi_hal_context; // Unused for now
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
usb_utmi_hal_init(&utmi_hal_context);
|
||||
}
|
||||
#endif
|
||||
if (phy_target == USB_PHY_TARGET_UTMI) {
|
||||
#if (SOC_USB_UTMI_PHY_NUM > 0)
|
||||
usb_utmi_hal_context_t utmi_hal_context; // Unused for now
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
usb_utmi_hal_init(&utmi_hal_context);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
}
|
||||
#endif
|
||||
if (config->controller == USB_PHY_CTRL_OTG) {
|
||||
#if USB_WRAP_LL_EXT_PHY_SUPPORTED
|
||||
#if USB_PHY_FSLS_EXT_PHY_SUPPORTED
|
||||
usb_wrap_hal_phy_set_external(&phy_context->wrap_hal, (phy_target == USB_PHY_TARGET_EXT));
|
||||
#endif
|
||||
}
|
||||
@@ -345,7 +367,9 @@ static void phy_uninstall(void)
|
||||
p_phy_ctrl_obj = NULL;
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
// Disable USB peripheral without reset the module
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
usb_wrap_hal_disable();
|
||||
#endif
|
||||
#if (SOC_USB_UTMI_PHY_NUM > 0)
|
||||
usb_utmi_hal_disable();
|
||||
#endif
|
||||
@@ -363,10 +387,12 @@ esp_err_t usb_del_phy(usb_phy_handle_t handle)
|
||||
p_phy_ctrl_obj->ref_count--;
|
||||
if (handle->target == USB_PHY_TARGET_EXT) {
|
||||
p_phy_ctrl_obj->external_phy = NULL;
|
||||
#if (SOC_USB_FSLS_PHY_NUM > 0)
|
||||
} else if (handle->target == USB_PHY_TARGET_INT) {
|
||||
// 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;
|
||||
#endif
|
||||
} else { // USB_PHY_TARGET_UTMI
|
||||
p_phy_ctrl_obj->utmi_phy = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user