Merge branch 'refactor/cleanup_usb_phy' into 'master'

Cleanup USB PHY

See merge request espressif/esp-idf!35783
This commit is contained in:
Tomas Rezucha 2025-01-08 16:11:54 +08:00
commit b92e993d56
20 changed files with 395 additions and 120 deletions

View File

@ -238,7 +238,7 @@ FORCE_INLINE_ATTR void usb_wrap_ll_phy_test_mode_set_signals(usb_wrap_dev_t *hw,
* Enable the bus clock for USB Wrap module and USB_DWC_FS controller * Enable the bus clock for USB Wrap module and USB_DWC_FS controller
* @param clk_en True if enable the clock of USB Wrap module * @param clk_en True if enable the clock of USB Wrap module
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_enable_bus_clock(bool clk_en) FORCE_INLINE_ATTR void _usb_wrap_ll_enable_bus_clock(bool clk_en)
{ {
// Enable/disable system clock for USB_WRAP and USB_DWC_FS // Enable/disable system clock for USB_WRAP and USB_DWC_FS
HP_SYS_CLKRST.soc_clk_ctrl1.reg_usb_otg11_sys_clk_en = clk_en; HP_SYS_CLKRST.soc_clk_ctrl1.reg_usb_otg11_sys_clk_en = clk_en;
@ -247,12 +247,12 @@ FORCE_INLINE_ATTR void usb_wrap_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 // 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_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_enable_bus_clock(__VA_ARGS__) #define usb_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_enable_bus_clock(__VA_ARGS__)
/** /**
* @brief Reset the USB Wrap module and USB_DWC_FS controller * @brief Reset the USB Wrap module and USB_DWC_FS controller
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_reset_register(void) FORCE_INLINE_ATTR void _usb_wrap_ll_reset_register(void)
{ {
// Reset the USB_WRAP and USB_DWC_FS // Reset the USB_WRAP and USB_DWC_FS
LP_AON_CLKRST.hp_usb_clkrst_ctrl1.rst_en_usb_otg11 = 1; LP_AON_CLKRST.hp_usb_clkrst_ctrl1.rst_en_usb_otg11 = 1;
@ -260,7 +260,7 @@ FORCE_INLINE_ATTR void usb_wrap_ll_reset_register(void)
} }
// P_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way // P_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way
#define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_reset_register(__VA_ARGS__) #define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_reset_register(__VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -207,25 +207,25 @@ FORCE_INLINE_ATTR void usb_wrap_ll_phy_test_mode_set_signals(usb_wrap_dev_t *hw,
* Enable the bus clock for USB Wrap module * Enable the bus clock for USB Wrap module
* @param clk_en True if enable the clock of USB Wrap module * @param clk_en True if enable the clock of USB Wrap module
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_enable_bus_clock(bool clk_en) FORCE_INLINE_ATTR void _usb_wrap_ll_enable_bus_clock(bool clk_en)
{ {
REG_SET_FIELD(DPORT_PERIP_CLK_EN0_REG, DPORT_USB_CLK_EN, 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 // SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way
#define usb_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_enable_bus_clock(__VA_ARGS__) #define usb_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_enable_bus_clock(__VA_ARGS__)
/** /**
* @brief Reset the USB Wrap module * @brief Reset the USB Wrap module
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_reset_register(void) FORCE_INLINE_ATTR void _usb_wrap_ll_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, 1);
REG_SET_FIELD(DPORT_PERIP_RST_EN0_REG, DPORT_USB_RST, 0); REG_SET_FIELD(DPORT_PERIP_RST_EN0_REG, DPORT_USB_RST, 0);
} }
// SYSTEM.perip_rst_enx are shared registers, so this function must be used in an atomic way // SYSTEM.perip_rst_enx are shared registers, so this function must be used in an atomic way
#define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_reset_register(__VA_ARGS__) #define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_reset_register(__VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -216,25 +216,25 @@ FORCE_INLINE_ATTR void usb_wrap_ll_phy_test_mode_set_signals(usb_wrap_dev_t *hw,
* Enable the bus clock for USB Wrap module * Enable the bus clock for USB Wrap module
* @param clk_en True if enable the clock of USB Wrap module * @param clk_en True if enable the clock of USB Wrap module
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_enable_bus_clock(bool clk_en) FORCE_INLINE_ATTR void _usb_wrap_ll_enable_bus_clock(bool clk_en)
{ {
SYSTEM.perip_clk_en0.usb_clk_en = 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 // SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way
#define usb_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_enable_bus_clock(__VA_ARGS__) #define usb_wrap_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_enable_bus_clock(__VA_ARGS__)
/** /**
* @brief Reset the USB Wrap module * @brief Reset the USB Wrap module
*/ */
FORCE_INLINE_ATTR void usb_wrap_ll_reset_register(void) FORCE_INLINE_ATTR void _usb_wrap_ll_reset_register(void)
{ {
SYSTEM.perip_rst_en0.usb_rst = 1; SYSTEM.perip_rst_en0.usb_rst = 1;
SYSTEM.perip_rst_en0.usb_rst = 0; SYSTEM.perip_rst_en0.usb_rst = 0;
} }
// SYSTEM.perip_rst_enx are shared registers, so this function must be used in an atomic way // SYSTEM.perip_rst_enx are shared registers, so this function must be used in an atomic way
#define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_reset_register(__VA_ARGS__) #define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_ll_reset_register(__VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -22,7 +22,8 @@ extern "C"
* @brief USB PHY target * @brief USB PHY target
*/ */
typedef enum { typedef enum {
USB_PHY_TARGET_INT, /**< USB target is internal PHY */ USB_PHY_TARGET_INT, /**< USB target is internal FSLS PHY */
USB_PHY_TARGET_UTMI, /**< USB target is internal UTMI PHY */
USB_PHY_TARGET_EXT, /**< USB target is external PHY */ USB_PHY_TARGET_EXT, /**< USB target is external PHY */
USB_PHY_TARGET_MAX, USB_PHY_TARGET_MAX,
} usb_phy_target_t; } usb_phy_target_t;

View File

@ -32,7 +32,30 @@ typedef struct {
* *
* @param hal USB WRAP HAL context * @param hal USB WRAP HAL context
*/ */
void usb_wrap_hal_init(usb_wrap_hal_context_t *hal); void _usb_wrap_hal_init(usb_wrap_hal_context_t *hal);
#if SOC_RCC_IS_INDEPENDENT
#define usb_wrap_hal_init(...) _usb_wrap_hal_init(__VA_ARGS__)
#else
// Use a macro to wrap the function, force the caller to use it in a critical section
// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define usb_wrap_hal_init(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_hal_init(__VA_ARGS__);} while(0)
#endif
/**
* @brief Disable USB WRAP
*
* Disable clock to the peripheral
*/
void _usb_wrap_hal_disable(void);
#if SOC_RCC_IS_INDEPENDENT
#define usb_wrap_hal_disable(...) _usb_wrap_hal_disable(__VA_ARGS__)
#else
// Use a macro to wrap the function, force the caller to use it in a critical section
// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define usb_wrap_hal_disable(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; _usb_wrap_hal_disable(__VA_ARGS__);} while(0)
#endif
/* ---------------------------- USB PHY Control ---------------------------- */ /* ---------------------------- USB PHY Control ---------------------------- */

View File

@ -8,14 +8,21 @@
#include "hal/usb_wrap_ll.h" #include "hal/usb_wrap_ll.h"
#include "hal/usb_wrap_hal.h" #include "hal/usb_wrap_hal.h"
void usb_wrap_hal_init(usb_wrap_hal_context_t *hal) void _usb_wrap_hal_init(usb_wrap_hal_context_t *hal)
{ {
hal->dev = &USB_WRAP; hal->dev = &USB_WRAP;
_usb_wrap_ll_enable_bus_clock(true);
_usb_wrap_ll_reset_register();
#if !USB_WRAP_LL_EXT_PHY_SUPPORTED #if !USB_WRAP_LL_EXT_PHY_SUPPORTED
usb_wrap_ll_phy_set_defaults(hal->dev); usb_wrap_ll_phy_set_defaults(hal->dev);
#endif #endif
} }
void _usb_wrap_hal_disable(void)
{
_usb_wrap_ll_enable_bus_clock(false);
}
#if USB_WRAP_LL_EXT_PHY_SUPPORTED #if USB_WRAP_LL_EXT_PHY_SUPPORTED
void usb_wrap_hal_phy_set_external(usb_wrap_hal_context_t *hal, bool external) void usb_wrap_hal_phy_set_external(usb_wrap_hal_context_t *hal, bool external)
{ {

View File

@ -25,7 +25,7 @@ Configuration Set ID: 11
#define OTG20_MULTI_PROC_INTRPT 1 #define OTG20_MULTI_PROC_INTRPT 1
/* 3.2 USB Physical Layer Interface Parameters */ /* 3.2 USB Physical Layer Interface Parameters */
#define OTG20_HSPHY_INTERFACE 3 #define OTG20_HSPHY_INTERFACE 3 // Although we support both UTMI+ and ULPI, the ULPI is not wired out of the USB-DWC. Hence only UTMI+ can be used
#define OTG20_HSPHY_DWIDTH 2 #define OTG20_HSPHY_DWIDTH 2
#define OTG20_FSPHY_INTERFACE 2 #define OTG20_FSPHY_INTERFACE 2
#define OTG20_ENABLE_IC_USB 0 #define OTG20_ENABLE_IC_USB 0

View File

@ -12,7 +12,7 @@
/* -------------------------------- Private --------------------------------- */ /* -------------------------------- Private --------------------------------- */
static const usb_utmi_otg_signal_conn_t dwc_fs_otg_signals = { static const usb_otg_signal_conn_t dwc_fs_otg_signals = {
// Inputs // Inputs
.iddig = USB_OTG11_IDDIG_PAD_IN_IDX, .iddig = USB_OTG11_IDDIG_PAD_IN_IDX,
.avalid = USB_OTG11_AVALID_PAD_IN_IDX, .avalid = USB_OTG11_AVALID_PAD_IN_IDX,

View File

@ -24,7 +24,7 @@ static const usb_fsls_serial_signal_conn_t fsls_signals = {
.fs_edge_sel = USB_EXTPHY_SPEED_IDX, .fs_edge_sel = USB_EXTPHY_SPEED_IDX,
}; };
static const usb_utmi_otg_signal_conn_t otg_signals = { static const usb_otg_signal_conn_t otg_signals = {
// Inputs // Inputs
.iddig = USB_OTG_IDDIG_IN_IDX, .iddig = USB_OTG_IDDIG_IN_IDX,
.avalid = USB_OTG_AVALID_IN_IDX, .avalid = USB_OTG_AVALID_IN_IDX,

View File

@ -25,7 +25,7 @@ static const usb_fsls_serial_signal_conn_t fsls_signals = {
.fs_edge_sel = USB_EXTPHY_SPEED_IDX, .fs_edge_sel = USB_EXTPHY_SPEED_IDX,
}; };
static const usb_utmi_otg_signal_conn_t otg_signals = { static const usb_otg_signal_conn_t otg_signals = {
// Inputs // Inputs
.iddig = USB_OTG_IDDIG_IN_IDX, .iddig = USB_OTG_IDDIG_IN_IDX,
.avalid = USB_OTG_AVALID_IN_IDX, .avalid = USB_OTG_AVALID_IN_IDX,

View File

@ -63,7 +63,7 @@ typedef struct {
int drvvbus; int drvvbus;
int chrgvbus; int chrgvbus;
int dischrgvbus; int dischrgvbus;
} usb_utmi_otg_signal_conn_t; } usb_otg_signal_conn_t;
/** /**
* @brief USB Controller Information * @brief USB Controller Information
@ -73,7 +73,7 @@ typedef struct {
typedef struct { typedef struct {
struct { struct {
const usb_fsls_serial_signal_conn_t * const fsls_signals; // Must be set if external PHY is supported by controller const usb_fsls_serial_signal_conn_t * const fsls_signals; // Must be set if external PHY is supported by controller
const usb_utmi_otg_signal_conn_t * const otg_signals; const usb_otg_signal_conn_t * const otg_signals;
const int irq; const int irq;
const int irq_2nd_cpu; // The USB-DWC can provide 2nd interrupt so each CPU can have its own interrupt line. Set to -1 if not supported const int irq_2nd_cpu; // The USB-DWC can provide 2nd interrupt so each CPU can have its own interrupt line. Set to -1 if not supported
} controllers [SOC_USB_OTG_PERIPH_NUM]; } controllers [SOC_USB_OTG_PERIPH_NUM];

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -54,12 +54,16 @@ typedef enum {
* @brief USB external PHY IO pins configuration structure * @brief USB external PHY IO pins configuration structure
*/ */
typedef struct { typedef struct {
// Inputs
int vp_io_num; /**< GPIO pin to USB_EXTPHY_VP_IDX */ int vp_io_num; /**< GPIO pin to USB_EXTPHY_VP_IDX */
int vm_io_num; /**< GPIO pin to USB_EXTPHY_VM_IDX */ int vm_io_num; /**< GPIO pin to USB_EXTPHY_VM_IDX */
int rcv_io_num; /**< GPIO pin to USB_EXTPHY_RCV_IDX */ int rcv_io_num; /**< GPIO pin to USB_EXTPHY_RCV_IDX */
// Outputs
int suspend_n_io_num; /**< GPIO pin to USB_EXTPHY_SUSPND_IDX */
int oen_io_num; /**< GPIO pin to USB_EXTPHY_OEN_IDX */ int oen_io_num; /**< GPIO pin to USB_EXTPHY_OEN_IDX */
int vpo_io_num; /**< GPIO pin to USB_EXTPHY_VPO_IDX */ int vpo_io_num; /**< GPIO pin to USB_EXTPHY_VPO_IDX */
int vmo_io_num; /**< GPIO pin to USB_EXTPHY_VMO_IDX */ int vmo_io_num; /**< GPIO pin to USB_EXTPHY_VMO_IDX */
int fs_edge_sel_io_num; /**< GPIO pin to USB_EXTPHY_SPEED_IDX */
} usb_phy_ext_io_conf_t; } usb_phy_ext_io_conf_t;
/** /**
@ -101,14 +105,15 @@ typedef struct phy_context_t *usb_phy_handle_t; /**< USB PHY context handle *
* *
* This function will enable the OTG Controller * This function will enable the OTG Controller
* *
* @param[in] config USB PHY configurtion struct * @param[in] config USB PHY configuration struct
* @param[out] handle_ret USB PHY context handle * @param[out] handle_ret USB PHY context handle
* *
* @return * @return
* - ESP_OK Success * - ESP_OK Success
* - ESP_FAIL USB PHY init error. * - ESP_ERR_INVALID_STATE USB PHY already initialized.
* - ESP_ERR_INVALID_STATE USB PHY not installed. * - ESP_ERR_NO_MEM USB_OTG Installation failed due to no mem.
* - ESP_ERR_NO_MEM USB_OTG installation failed due to no mem. * - ESP_ERR_NOT_SUPPORTED Selected PHY is not supported on this target.
* - ESP_ERR_INVALID_ARG Invalid input argument.
*/ */
esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_ret); esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_ret);

View File

@ -17,3 +17,21 @@ components/usb/test_apps:
- components/soc/include/soc/usb*.h - components/soc/include/soc/usb*.h
- components/soc/esp32*/include/soc/usb_dwc_*.h - components/soc/esp32*/include/soc/usb_dwc_*.h
- components/soc/esp32*/include/soc/usb_wrap_*.h - components/soc/esp32*/include/soc/usb_wrap_*.h
components/usb/test_apps/phy:
enable:
- if: SOC_USB_OTG_SUPPORTED == 1
disable_test:
- if: IDF_TARGET in ["esp32p4"]
temporary: true
reason: ESP32-P4 PHY driver not yet migrated
depends_components:
- usb
depends_filepatterns:
- components/hal/usb*.c
- components/hal/include/hal/usb*.h
- components/hal/esp32*/include/hal/usb*.h
- components/soc/esp32*/usb*.c
- components/soc/include/soc/usb*.h
- components/soc/esp32*/include/soc/usb_dwc_*.h
- components/soc/esp32*/include/soc/usb_wrap_*.h

View File

@ -0,0 +1,9 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
project(test_app_usb_phy)

View File

@ -0,0 +1,4 @@
| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- |
# USB: PHY sanity checks

View File

@ -0,0 +1,6 @@
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
REQUIRES usb unity
WHOLE_ARCHIVE)

View File

@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"
#include "esp_private/usb_phy.h"
#include "hal/usb_wrap_ll.h" // For USB_WRAP_LL_EXT_PHY_SUPPORTED symbol
#include "soc/soc_caps.h" // For SOC_USB_UTMI_PHY_NUM symbol
#if USB_WRAP_LL_EXT_PHY_SUPPORTED
#define EXT_PHY_SUPPORTED 1
#else
#define EXT_PHY_SUPPORTED 0
#endif
#if SOC_USB_UTMI_PHY_NUM > 0
#define UTMI_PHY_SUPPORTED 1
#else
#define UTMI_PHY_SUPPORTED 0
#endif
void setUp(void)
{
unity_utils_record_free_mem();
}
void tearDown(void)
{
unity_utils_evaluate_leaks();
}
void app_main(void)
{
// ____ ___ ___________________ __ __
// | | \/ _____/\______ \ _/ |_ ____ _______/ |_
// | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\.
// | | / / \ | | \ | | \ ___/ \___ \ | |
// |______/ /_______ / |______ / |__| \___ >____ > |__|
// \/ \/ \/ \/
printf(" ____ ___ ___________________ __ __ \r\n");
printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n");
printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n");
printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n");
printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n");
printf(" \\/ \\/ \\/ \\/ \r\n");
unity_utils_setup_heap_record(80);
unity_utils_set_leak_level(128);
unity_run_menu();
}
/**
* Test init and deinit of internal FSLS PHY
*/
TEST_CASE("Init internal FSLS PHY", "[phy]")
{
usb_phy_handle_t phy_handle = NULL;
const usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NOT_NULL(phy_handle);
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle));
}
/**
* Test init and deinit of external FSLS PHY
*/
TEST_CASE("Init external FSLS PHY", "[phy]")
{
usb_phy_handle_t phy_handle = NULL;
usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_EXT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
#if EXT_PHY_SUPPORTED
// Init ext PHY without ext_io_conf -> FAIL
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NULL(phy_handle);
// Init ext PHY with ext_io_conf -> PASS
const usb_phy_ext_io_conf_t ext_io_conf = { // Some random values
.vp_io_num = 1,
.vm_io_num = 1,
.rcv_io_num = 1,
.suspend_n_io_num = 1,
.oen_io_num = 1,
.vpo_io_num = 1,
.vmo_io_num = 1,
.fs_edge_sel_io_num = 1,
};
phy_config.ext_io_conf = &ext_io_conf;
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NOT_NULL(phy_handle);
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle));
#else
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NULL(phy_handle);
#endif
}
/**
* Test init and deinit of internal UTMI PHY
*/
TEST_CASE("Init internal UTMI PHY", "[phy]")
{
usb_phy_handle_t phy_handle = NULL;
const usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_UTMI,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
#if UTMI_PHY_SUPPORTED
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NOT_NULL(phy_handle);
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle));
#else
TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NULL(phy_handle);
#endif
}
/**
* Test init and deinit of all PHYs at the same time
*/
TEST_CASE("Init all PHYs", "[phy]")
{
usb_phy_handle_t phy_handle = NULL;
usb_phy_handle_t phy_handle_2 = NULL;
usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle));
TEST_ASSERT_NOT_NULL(phy_handle);
// Our current targets support either UTMI or external PHY
// so if/else suffice here
#if UTMI_PHY_SUPPORTED
phy_config.target = USB_PHY_TARGET_UTMI;
#else
const usb_phy_ext_io_conf_t ext_io_conf = { // Some random values
.vp_io_num = 1,
.vm_io_num = 1,
.rcv_io_num = 1,
.suspend_n_io_num = 1,
.oen_io_num = 1,
.vpo_io_num = 1,
.vmo_io_num = 1,
.fs_edge_sel_io_num = 1,
};
phy_config.target = USB_PHY_TARGET_EXT;
phy_config.ext_io_conf = &ext_io_conf;
#endif
TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle_2));
TEST_ASSERT_NOT_NULL(phy_handle_2);
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle));
TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle_2));
}

View File

@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.esp32p4
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='P4 PHY not yet migrated')
def test_usb_phy(dut: Dut) -> None:
dut.run_all_single_board_cases(group='phy')

View File

@ -0,0 +1,8 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
# CONFIG_ESP_TASK_WDT_INIT is not set
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
# CONFIG_UNITY_ENABLE_FLOAT is not set
# CONFIG_UNITY_ENABLE_DOUBLE is not set
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,17 +13,14 @@
#include "esp_private/critical_section.h" #include "esp_private/critical_section.h"
#include "soc/usb_dwc_periph.h" #include "soc/usb_dwc_periph.h"
#include "hal/usb_wrap_hal.h" #include "hal/usb_wrap_hal.h"
#include "hal/usb_serial_jtag_hal.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "hal/gpio_ll.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/usb_pins.h"
#if !SOC_RCC_IS_INDEPENDENT #if !SOC_RCC_IS_INDEPENDENT
#define USB_WRAP_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #define USB_PHY_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else #else
#define USB_WRAP_RCC_ATOMIC() #define USB_PHY_RCC_ATOMIC()
#endif #endif
static const char *USBPHY_TAG = "usb_phy"; static const char *USBPHY_TAG = "usb_phy";
@ -40,9 +37,6 @@ struct phy_context_t {
usb_phy_speed_t otg_speed; /**< USB speed */ usb_phy_speed_t otg_speed; /**< USB speed */
usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */ usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */
usb_wrap_hal_context_t wrap_hal; /**< USB WRAP HAL context */ usb_wrap_hal_context_t wrap_hal; /**< USB WRAP HAL context */
#if SOC_USB_SERIAL_JTAG_SUPPORTED
usb_serial_jtag_hal_context_t usj_hal; /**< USJ HAL context */
#endif
}; };
typedef struct { typedef struct {
@ -51,72 +45,78 @@ typedef struct {
uint32_t ref_count; /**< reference count used to protect p_phy_ctrl_obj */ uint32_t ref_count; /**< reference count used to protect p_phy_ctrl_obj */
} phy_ctrl_obj_t; } phy_ctrl_obj_t;
/**
* @brief A pin descriptor for initialize external PHY I/O pins
*/
typedef struct {
int pin; /**< GPIO pin num */
const int func; /**< GPIO matrix signal */
const bool is_output; /**< input/output signal */
} usb_iopin_dsc_t;
static phy_ctrl_obj_t *p_phy_ctrl_obj = NULL; static phy_ctrl_obj_t *p_phy_ctrl_obj = NULL;
DEFINE_CRIT_SECTION_LOCK_STATIC(phy_spinlock); DEFINE_CRIT_SECTION_LOCK_STATIC(phy_spinlock);
#define PHY_ENTER_CRITICAL() esp_os_enter_critical(&phy_spinlock) #define PHY_ENTER_CRITICAL() esp_os_enter_critical(&phy_spinlock)
#define PHY_EXIT_CRITICAL() esp_os_exit_critical(&phy_spinlock) #define PHY_EXIT_CRITICAL() esp_os_exit_critical(&phy_spinlock)
static esp_err_t phy_iopins_configure(const usb_iopin_dsc_t *usb_periph_iopins, int iopins_num) static esp_err_t phy_configure_pin_input(int gpio_pin, int signal_idx)
{ {
for (int i = 0; i < iopins_num; i++) { if (gpio_pin != GPIO_NUM_NC) {
const usb_iopin_dsc_t iopin = usb_periph_iopins[i]; ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_pin),
if (iopin.pin != GPIO_NUM_NC) { ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid");
ESP_RETURN_ON_FALSE((iopin.is_output && GPIO_IS_VALID_OUTPUT_GPIO(iopin.pin)) || esp_rom_gpio_pad_select_gpio(gpio_pin);
(!iopin.is_output && GPIO_IS_VALID_GPIO(iopin.pin)), esp_rom_gpio_connect_in_signal(gpio_pin, signal_idx, false);
ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid"); gpio_input_enable(gpio_pin);
esp_rom_gpio_pad_select_gpio(iopin.pin); esp_rom_gpio_pad_unhold(gpio_pin);
if (iopin.is_output) {
esp_rom_gpio_connect_out_signal(iopin.pin, iopin.func, false, false);
} else {
esp_rom_gpio_connect_in_signal(iopin.pin, iopin.func, false);
gpio_ll_input_enable(&GPIO, iopin.pin);
}
esp_rom_gpio_pad_unhold(iopin.pin);
}
} }
return ESP_OK; return ESP_OK;
} }
static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_io_conf) static esp_err_t phy_configure_pin_output(int gpio_pin, int signal_idx)
{ {
const usb_iopin_dsc_t usb_periph_iopins[] = { if (gpio_pin != GPIO_NUM_NC) {
{ext_io_conf->vp_io_num, usb_otg_periph_signal.extphy_vp_in, false}, ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(gpio_pin),
{ext_io_conf->vm_io_num, usb_otg_periph_signal.extphy_vm_in, false}, ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid");
{ext_io_conf->rcv_io_num, usb_otg_periph_signal.extphy_rcv_in, false}, esp_rom_gpio_pad_select_gpio(gpio_pin);
{ext_io_conf->oen_io_num, usb_otg_periph_signal.extphy_oen_out, true}, esp_rom_gpio_connect_out_signal(gpio_pin, signal_idx, false, false);
{ext_io_conf->vpo_io_num, usb_otg_periph_signal.extphy_vpo_out, true}, esp_rom_gpio_pad_unhold(gpio_pin);
{ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true}, }
}; return ESP_OK;
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t));
} }
static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf) static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_io_conf, const usb_fsls_serial_signal_conn_t *fsls_sig)
{ {
const usb_iopin_dsc_t usb_periph_iopins[] = { ESP_RETURN_ON_FALSE(ext_io_conf && fsls_sig, ESP_ERR_INVALID_ARG, USBPHY_TAG, "argument is invalid");
{otg_io_conf->iddig_io_num, usb_otg_periph_signal.otg_iddig_in, false}, esp_err_t ret = ESP_OK;
{otg_io_conf->avalid_io_num, usb_otg_periph_signal.otg_avalid_in, false},
{otg_io_conf->vbusvalid_io_num, usb_otg_periph_signal.otg_vbusvalid_in, false}, // Inputs
{otg_io_conf->idpullup_io_num, usb_otg_periph_signal.otg_idpullup_out, true}, ret |= phy_configure_pin_input(ext_io_conf->vp_io_num, fsls_sig->rx_dp);
{otg_io_conf->dppulldown_io_num, usb_otg_periph_signal.otg_dppulldown_out, true}, ret |= phy_configure_pin_input(ext_io_conf->vm_io_num, fsls_sig->rx_dm);
{otg_io_conf->dmpulldown_io_num, usb_otg_periph_signal.otg_dmpulldown_out, true}, ret |= phy_configure_pin_input(ext_io_conf->rcv_io_num, fsls_sig->rx_rcv);
{otg_io_conf->drvvbus_io_num, usb_otg_periph_signal.otg_drvvbus_out, true},
{otg_io_conf->bvalid_io_num, usb_otg_periph_signal.srp_bvalid_in, false}, // Outputs
{otg_io_conf->sessend_io_num, usb_otg_periph_signal.srp_sessend_in, false}, ret |= phy_configure_pin_output(ext_io_conf->suspend_n_io_num, fsls_sig->suspend_n);
{otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true}, ret |= phy_configure_pin_output(ext_io_conf->oen_io_num, fsls_sig->tx_enable_n);
{otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true}, ret |= phy_configure_pin_output(ext_io_conf->vpo_io_num, fsls_sig->tx_dp);
}; ret |= phy_configure_pin_output(ext_io_conf->vmo_io_num, fsls_sig->tx_dm);
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t)); ret |= phy_configure_pin_output(ext_io_conf->fs_edge_sel_io_num, fsls_sig->fs_edge_sel);
return ret;
}
static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf, const usb_otg_signal_conn_t *otg_sig)
{
ESP_RETURN_ON_FALSE(otg_io_conf && otg_sig, ESP_ERR_INVALID_ARG, USBPHY_TAG, "argument is invalid");
esp_err_t ret = ESP_OK;
// Inputs
ret |= phy_configure_pin_input(otg_io_conf->iddig_io_num, otg_sig->iddig);
ret |= phy_configure_pin_input(otg_io_conf->avalid_io_num, otg_sig->avalid);
ret |= phy_configure_pin_input(otg_io_conf->vbusvalid_io_num, otg_sig->vbusvalid);
ret |= phy_configure_pin_input(otg_io_conf->bvalid_io_num, otg_sig->bvalid);
ret |= phy_configure_pin_input(otg_io_conf->sessend_io_num, otg_sig->sessend);
// Outputs
ret |= phy_configure_pin_output(otg_io_conf->idpullup_io_num, otg_sig->idpullup);
ret |= phy_configure_pin_output(otg_io_conf->dppulldown_io_num, otg_sig->dppulldown);
ret |= phy_configure_pin_output(otg_io_conf->dmpulldown_io_num, otg_sig->dmpulldown);
ret |= phy_configure_pin_output(otg_io_conf->drvvbus_io_num, otg_sig->drvvbus);
ret |= phy_configure_pin_output(otg_io_conf->chrgvbus_io_num, otg_sig->chrgvbus);
ret |= phy_configure_pin_output(otg_io_conf->dischrgvbus_io_num, otg_sig->dischrgvbus);
return ret;
} }
esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
@ -126,11 +126,13 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
ESP_RETURN_ON_FALSE(handle->controller == USB_PHY_CTRL_OTG, ESP_FAIL, USBPHY_TAG, "phy source is not USB_OTG"); ESP_RETURN_ON_FALSE(handle->controller == USB_PHY_CTRL_OTG, ESP_FAIL, USBPHY_TAG, "phy source is not USB_OTG");
handle->otg_mode = mode; handle->otg_mode = mode;
const usb_otg_signal_conn_t *otg_sig = usb_dwc_info.controllers[0].otg_signals;
assert(otg_sig);
if (mode == USB_OTG_MODE_HOST) { if (mode == USB_OTG_MODE_HOST) {
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is A side esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, otg_sig->iddig, false); // connected connector is A side
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, otg_sig->bvalid, false);
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from host esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, otg_sig->vbusvalid, false); // receiving a valid Vbus from host
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); // HIGH to force USB host mode esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, otg_sig->avalid, false);
if (handle->target == USB_PHY_TARGET_INT) { if (handle->target == USB_PHY_TARGET_INT) {
// Configure pull resistors for host // Configure pull resistors for host
usb_wrap_pull_override_vals_t vals = { usb_wrap_pull_override_vals_t vals = {
@ -142,10 +144,10 @@ 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); usb_wrap_hal_phy_enable_pull_override(&handle->wrap_hal, &vals);
} }
} else if (mode == USB_OTG_MODE_DEVICE) { } else if (mode == USB_OTG_MODE_DEVICE) {
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is mini-B side esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, otg_sig->iddig, false); // connected connector is mini-B side
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); // HIGH to force USB device mode esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, otg_sig->bvalid, false); // HIGH to force USB device mode
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from device esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, otg_sig->vbusvalid, false); // receiving a valid Vbus from device
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, otg_sig->avalid, false);
} }
return ESP_OK; return ESP_OK;
@ -185,6 +187,9 @@ esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action)
ESP_ERR_INVALID_ARG, USBPHY_TAG, "wrong target for the action"); ESP_ERR_INVALID_ARG, USBPHY_TAG, "wrong target for the action");
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
const usb_fsls_serial_signal_conn_t *fsls_sig = usb_dwc_info.controllers[0].fsls_signals;
assert(fsls_sig);
switch (action) { switch (action) {
case USB_PHY_ACTION_HOST_ALLOW_CONN: case USB_PHY_ACTION_HOST_ALLOW_CONN:
if (handle->target == USB_PHY_TARGET_INT) { if (handle->target == USB_PHY_TARGET_INT) {
@ -198,8 +203,8 @@ esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action)
/* /*
Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY. Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY.
*/ */
esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, USB_EXTPHY_VP_IDX, false); esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, fsls_sig->rx_dp, false);
esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, USB_EXTPHY_VM_IDX, false); esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, fsls_sig->rx_dm, false);
} }
break; break;
@ -224,8 +229,8 @@ esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action)
/* /*
Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal. Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal.
*/ */
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VP_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, fsls_sig->rx_dp, false);
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VM_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, fsls_sig->rx_dm, false);
} }
break; break;
@ -259,12 +264,7 @@ static esp_err_t usb_phy_install(void)
PHY_EXIT_CRITICAL(); PHY_EXIT_CRITICAL();
goto cleanup; goto cleanup;
} }
// Enable USB peripheral and reset the register
PHY_EXIT_CRITICAL(); PHY_EXIT_CRITICAL();
USB_WRAP_RCC_ATOMIC() {
usb_wrap_ll_enable_bus_clock(true);
usb_wrap_ll_reset_register();
}
return ESP_OK; return ESP_OK;
cleanup: cleanup:
@ -277,6 +277,13 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, USBPHY_TAG, "config argument is invalid"); ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, USBPHY_TAG, "config argument is invalid");
ESP_RETURN_ON_FALSE(config->target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified PHY argument is invalid"); ESP_RETURN_ON_FALSE(config->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(config->controller < USB_PHY_CTRL_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified source argument is invalid");
ESP_RETURN_ON_FALSE(config->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
ESP_RETURN_ON_FALSE(config->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
ESP_RETURN_ON_FALSE(config->target != USB_PHY_TARGET_UTMI, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "UTMI PHY not supported on this target");
#endif
ESP_RETURN_ON_ERROR(usb_phy_install(), USBPHY_TAG, "usb_phy driver installation failed"); ESP_RETURN_ON_ERROR(usb_phy_install(), USBPHY_TAG, "usb_phy driver installation failed");
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
@ -302,22 +309,14 @@ 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->controller = config->controller;
phy_context->status = USB_PHY_STATUS_IN_USE; phy_context->status = USB_PHY_STATUS_IN_USE;
usb_wrap_hal_init(&phy_context->wrap_hal); USB_PHY_RCC_ATOMIC() {
#if SOC_USB_SERIAL_JTAG_SUPPORTED usb_wrap_hal_init(&phy_context->wrap_hal);
usb_serial_jtag_hal_init(&phy_context->usj_hal); }
#endif
if (config->controller == USB_PHY_CTRL_OTG) { if (config->controller == USB_PHY_CTRL_OTG) {
#if USB_WRAP_LL_EXT_PHY_SUPPORTED #if USB_WRAP_LL_EXT_PHY_SUPPORTED
usb_wrap_hal_phy_set_external(&phy_context->wrap_hal, (config->target == USB_PHY_TARGET_EXT)); usb_wrap_hal_phy_set_external(&phy_context->wrap_hal, (config->target == USB_PHY_TARGET_EXT));
#endif #endif
} }
#if SOC_USB_SERIAL_JTAG_SUPPORTED
else if (config->controller == USB_PHY_CTRL_SERIAL_JTAG) {
usb_serial_jtag_hal_phy_set_external(&phy_context->usj_hal, (config->target == USB_PHY_TARGET_EXT));
phy_context->otg_mode = USB_OTG_MODE_DEVICE;
phy_context->otg_speed = USB_PHY_SPEED_FULL;
}
#endif
if (config->target == USB_PHY_TARGET_INT) { if (config->target == USB_PHY_TARGET_INT) {
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
@ -329,7 +328,8 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
phy_context->iopins = (usb_phy_ext_io_conf_t *) calloc(1, sizeof(usb_phy_ext_io_conf_t)); phy_context->iopins = (usb_phy_ext_io_conf_t *) calloc(1, sizeof(usb_phy_ext_io_conf_t));
ESP_GOTO_ON_FALSE(phy_context->iopins, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for storing I/O pins"); ESP_GOTO_ON_FALSE(phy_context->iopins, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for storing I/O pins");
memcpy(phy_context->iopins, config->ext_io_conf, sizeof(usb_phy_ext_io_conf_t)); memcpy(phy_context->iopins, config->ext_io_conf, sizeof(usb_phy_ext_io_conf_t));
ESP_ERROR_CHECK(phy_external_iopins_configure(phy_context->iopins)); const usb_fsls_serial_signal_conn_t *fsls_sig = usb_dwc_info.controllers[0].fsls_signals;
ESP_ERROR_CHECK(phy_external_iopins_configure(phy_context->iopins, fsls_sig));
} }
if (config->otg_mode != USB_PHY_MODE_DEFAULT) { if (config->otg_mode != USB_PHY_MODE_DEFAULT) {
ESP_ERROR_CHECK(usb_phy_otg_set_mode(*handle_ret, config->otg_mode)); ESP_ERROR_CHECK(usb_phy_otg_set_mode(*handle_ret, config->otg_mode));
@ -338,7 +338,8 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
ESP_ERROR_CHECK(usb_phy_otg_dev_set_speed(*handle_ret, config->otg_speed)); ESP_ERROR_CHECK(usb_phy_otg_dev_set_speed(*handle_ret, config->otg_speed));
} }
if (config->otg_io_conf && (phy_context->controller == USB_PHY_CTRL_OTG)) { if (config->otg_io_conf && (phy_context->controller == USB_PHY_CTRL_OTG)) {
ESP_ERROR_CHECK(phy_otg_iopins_configure(config->otg_io_conf)); const usb_otg_signal_conn_t *otg_sig = usb_dwc_info.controllers[0].otg_signals;
ESP_ERROR_CHECK(phy_otg_iopins_configure(config->otg_io_conf, otg_sig));
} }
return ESP_OK; return ESP_OK;
@ -361,9 +362,9 @@ static void phy_uninstall(void)
if (p_phy_ctrl_obj->ref_count == 0) { if (p_phy_ctrl_obj->ref_count == 0) {
p_phy_ctrl_obj_free = p_phy_ctrl_obj; p_phy_ctrl_obj_free = p_phy_ctrl_obj;
p_phy_ctrl_obj = NULL; p_phy_ctrl_obj = NULL;
USB_WRAP_RCC_ATOMIC() { USB_PHY_RCC_ATOMIC() {
// Disable USB peripheral without reset the module // Disable USB peripheral without reset the module
usb_wrap_ll_enable_bus_clock(false); usb_wrap_hal_disable();
} }
} }
PHY_EXIT_CRITICAL(); PHY_EXIT_CRITICAL();