From da785a8f71cdeec8550dd7a3fbf6ddf4d49b83d7 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 3 Sep 2025 19:59:56 +0800 Subject: [PATCH] fix(gpio): add USB PHY1 (USB OTG) pin support for ESP32H4 --- .../test_apps/gpio/main/test_gpio.c | 4 ++-- components/hal/esp32h4/include/hal/gpio_ll.h | 19 ++++++++++++++++--- components/soc/esp32h4/include/soc/reg_base.h | 2 +- .../esp32h4/ld/esp32h4.peripherals.beta5.ld | 2 +- .../soc/esp32h4/ld/esp32h4.peripherals.ld | 2 +- .../soc/esp32h4/register/soc/io_mux_reg.h | 8 ++++++++ .../register/soc/usb_serial_jtag_struct.h | 2 +- .../soc/esp32h4/register/soc/usb_wrap_reg.h | 4 ++-- .../esp32h4/register/soc/usb_wrap_struct.h | 7 ++++--- 9 files changed, 36 insertions(+), 14 deletions(-) diff --git a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c index 5700ce68b5..f4e249a25e 100644 --- a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c +++ b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c @@ -801,7 +801,7 @@ TEST_CASE("GPIO_input_and_output_of_USB_pins_test", "[gpio]") { const int test_pins[] = {USB_INT_PHY0_DP_GPIO_NUM, USB_INT_PHY0_DM_GPIO_NUM, -#if CONFIG_IDF_TARGET_ESP32P4 // TODO: Use proper soc_caps macro +#ifdef USB_INT_PHY1_DP_GPIO_NUM USB_INT_PHY1_DP_GPIO_NUM, USB_INT_PHY1_DM_GPIO_NUM #endif @@ -847,7 +847,7 @@ TEST_CASE("GPIO_USB_DP_pin_pullup_disable_test", "[gpio]") // Therefore, when D+ pin's pull-up value is set to 0, it will also clear USB D+ pull-up value to allow // its full functionality as a normal gpio pin const int test_pins[] = {USB_INT_PHY0_DP_GPIO_NUM, -#if CONFIG_IDF_TARGET_ESP32P4 // TODO: Use proper soc_caps macro +#ifdef USB_INT_PHY1_DP_GPIO_NUM USB_INT_PHY1_DP_GPIO_NUM, #endif }; diff --git a/components/hal/esp32h4/include/hal/gpio_ll.h b/components/hal/esp32h4/include/hal/gpio_ll.h index 82d75b564e..db7e98a5bf 100644 --- a/components/hal/esp32h4/include/hal/gpio_ll.h +++ b/components/hal/esp32h4/include/hal/gpio_ll.h @@ -20,7 +20,9 @@ #include "soc/lp_aon_struct.h" #include "soc/pmu_struct.h" #include "soc/io_mux_struct.h" +#include "soc/io_mux_reg.h" #include "soc/usb_serial_jtag_struct.h" +#include "soc/usb_wrap_struct.h" #include "soc/pcr_struct.h" #include "soc/clk_tree_defs.h" #include "hal/gpio_types.h" @@ -89,10 +91,17 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) // Note that esp32h4 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. // TODO: read the specific efuse with efuse_ll.h - if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + + // One more noticeable point is H4 has two internal PHYs connecting to USJ and USB_WRAP(OTG1.1) separately. + // We only consider the default connection here: PHY0 -> USJ, PHY1 -> USB_OTG + if (gpio_num == USB_USJ_INT_PHY_DP_GPIO_NUM) { USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_pad_pull_override = 1; USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_dp_pullup = 0; + } else if (gpio_num == USB_OTG_INT_PHY_DP_GPIO_NUM) { + USB_WRAP.wrap_otg_conf.wrap_pad_pull_override = 1; + USB_WRAP.wrap_otg_conf.wrap_dp_pullup = 0; } + IO_MUX.gpio[gpio_num].fun_wpu = 0; } @@ -547,9 +556,13 @@ static inline void gpio_ll_set_output_signal_matrix_source(gpio_dev_t *hw, uint3 __attribute__((always_inline)) static inline void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t func) { - // Disable USB Serial JTAG if USB pins needs to select an IOMUX function - if (gpio_num == USB_INT_PHY0_DM_GPIO_NUM || gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + // Disable USB PHY configuration if pins (13, 14) (21, 22) needs to select an IOMUX function + // P4 has two internal PHYs connecting to USJ and USB_WRAP(OTG1.1) separately. + // We only consider the default connection here: PHY0 -> USJ, PHY1 -> USB_OTG + if (gpio_num == USB_USJ_INT_PHY_DM_GPIO_NUM || gpio_num == USB_USJ_INT_PHY_DP_GPIO_NUM) { USB_SERIAL_JTAG.serial_jtag_conf0.serial_jtag_usb_pad_enable = 0; + } else if (gpio_num == USB_OTG_INT_PHY_DM_GPIO_NUM || gpio_num == USB_OTG_INT_PHY_DP_GPIO_NUM) { + USB_WRAP.wrap_otg_conf.wrap_usb_pad_enable = 0; } IO_MUX.gpio[gpio_num].mcu_sel = func; } diff --git a/components/soc/esp32h4/include/soc/reg_base.h b/components/soc/esp32h4/include/soc/reg_base.h index 7a0786329b..2235e84cee 100644 --- a/components/soc/esp32h4/include/soc/reg_base.h +++ b/components/soc/esp32h4/include/soc/reg_base.h @@ -38,7 +38,7 @@ #define DR_REG_ZERO_DET_BASE 0x60029000 #define DR_REG_USB_OTG_FS_CORE0_BASE 0x60040000 #define DR_REG_USB_OTG_FS_CORE1_BASE 0x6007F000 -#define DR_REG_USB_OTG_FS_PHY_BASE 0x60080000 +#define DR_REG_USB_WRAP_BASE 0x60080000 #define DR_REG_TIMERG0_BASE 0x60090000 #define DR_REG_TIMERG1_BASE 0x60091000 #define DR_REG_IO_MUX_BASE 0x60092000 diff --git a/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld b/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld index 4ecd54aa6c..91f7983ffc 100644 --- a/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld +++ b/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld @@ -38,7 +38,7 @@ PROVIDE ( SAMPLE_RATE_CONVERTER = 0x60028000 ); PROVIDE ( ZERO_DET = 0x60029000 ); PROVIDE ( USB_OTG_FS_CORE0 = 0x60040000 ); PROVIDE ( USB_OTG_FS_CORE1 = 0x6007F000 ); -PROVIDE ( USB_OTG_FS_PHY = 0x60080000 ); +PROVIDE ( USB_WRAP = 0x60080000 ); PROVIDE ( TIMERG0 = 0x60090000 ); PROVIDE ( TIMERG1 = 0x60091000 ); PROVIDE ( IO_MUX = 0x60092000 ); diff --git a/components/soc/esp32h4/ld/esp32h4.peripherals.ld b/components/soc/esp32h4/ld/esp32h4.peripherals.ld index 1590a3c3f8..527f946f50 100644 --- a/components/soc/esp32h4/ld/esp32h4.peripherals.ld +++ b/components/soc/esp32h4/ld/esp32h4.peripherals.ld @@ -38,7 +38,7 @@ PROVIDE ( SAMPLE_RATE_CONVERTER = 0x60028000 ); PROVIDE ( ZERO_DET = 0x60029000 ); PROVIDE ( USB_OTG_FS_CORE0 = 0x60040000 ); PROVIDE ( USB_OTG_FS_CORE1 = 0x6007F000 ); -PROVIDE ( USB_OTG_FS_PHY = 0x60080000 ); +PROVIDE ( USB_WRAP = 0x60080000 ); PROVIDE ( TIMERG0 = 0x60090000 ); PROVIDE ( TIMERG1 = 0x60091000 ); PROVIDE ( IO_MUX = 0x60092000 ); diff --git a/components/soc/esp32h4/register/soc/io_mux_reg.h b/components/soc/esp32h4/register/soc/io_mux_reg.h index 434bcc6bae..dc183412cf 100644 --- a/components/soc/esp32h4/register/soc/io_mux_reg.h +++ b/components/soc/esp32h4/register/soc/io_mux_reg.h @@ -128,6 +128,14 @@ extern "C" { #define USB_INT_PHY0_DM_GPIO_NUM 13 #define USB_INT_PHY0_DP_GPIO_NUM 14 +#define USB_INT_PHY1_DM_GPIO_NUM 21 +#define USB_INT_PHY1_DP_GPIO_NUM 22 + +// We would fix the USB PHY usage on H4: PHY0 -> USJ, PHY1 -> USB_OTG +#define USB_USJ_INT_PHY_DM_GPIO_NUM USB_INT_PHY0_DM_GPIO_NUM +#define USB_USJ_INT_PHY_DP_GPIO_NUM USB_INT_PHY0_DP_GPIO_NUM +#define USB_OTG_INT_PHY_DM_GPIO_NUM USB_INT_PHY1_DM_GPIO_NUM +#define USB_OTG_INT_PHY_DP_GPIO_NUM USB_INT_PHY1_DP_GPIO_NUM #define MAX_RTC_GPIO_NUM 5 #define MAX_PAD_GPIO_NUM 39 diff --git a/components/soc/esp32h4/register/soc/usb_serial_jtag_struct.h b/components/soc/esp32h4/register/soc/usb_serial_jtag_struct.h index c9ee7cfe97..22ff951391 100644 --- a/components/soc/esp32h4/register/soc/usb_serial_jtag_struct.h +++ b/components/soc/esp32h4/register/soc/usb_serial_jtag_struct.h @@ -974,7 +974,7 @@ typedef struct { extern usb_serial_jtag_dev_t USB_SERIAL_JTAG; #ifndef __cplusplus -_Static_assert(sizeof(usb_serial_jtag_dev_t) == 0x84, "Invalid size of usb_dev_t structure"); +_Static_assert(sizeof(usb_serial_jtag_dev_t) == 0x84, "Invalid size of usb_serial_jtag_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32h4/register/soc/usb_wrap_reg.h b/components/soc/esp32h4/register/soc/usb_wrap_reg.h index 671d904287..676b6f2f5c 100644 --- a/components/soc/esp32h4/register/soc/usb_wrap_reg.h +++ b/components/soc/esp32h4/register/soc/usb_wrap_reg.h @@ -14,7 +14,7 @@ extern "C" { /** USB_WRAP_OTG_CONF_REG register * USB wrapper configuration registers. */ -#define USB_WRAP_OTG_CONF_REG (DR_REG_USB_BASE + 0x0) +#define USB_WRAP_OTG_CONF_REG (DR_REG_USB_WRAP_BASE + 0x0) /** USB_WRAP_SRP_SESSEND_OVERRIDE : R/W; bitpos: [0]; default: 0; * This bit is used to enable the software over-ride of srp session end signal. 1'b0: * the signal is controlled by the chip input, 1'b1: the signal is controlled by the @@ -154,7 +154,7 @@ extern "C" { /** USB_WRAP_DATE_REG register * Date register. */ -#define USB_WRAP_DATE_REG (DR_REG_USB_BASE + 0x3fc) +#define USB_WRAP_DATE_REG (DR_REG_USB_WRAP_BASE + 0x3fc) /** USB_WRAP_USB_WRAP_DATE : R/W; bitpos: [31:0]; default: 37761536; * Date register. */ diff --git a/components/soc/esp32h4/register/soc/usb_wrap_struct.h b/components/soc/esp32h4/register/soc/usb_wrap_struct.h index 7680b6dc8f..d04c80210a 100644 --- a/components/soc/esp32h4/register/soc/usb_wrap_struct.h +++ b/components/soc/esp32h4/register/soc/usb_wrap_struct.h @@ -114,15 +114,16 @@ typedef union { } usb_wrap_date_reg_t; -typedef struct { +typedef struct usb_wrap_dev_t { volatile usb_wrap_otg_conf_reg_t wrap_otg_conf; uint32_t reserved_004[254]; volatile usb_wrap_date_reg_t wrap_date; -} usb_dev_t; +} usb_wrap_dev_t; +extern usb_wrap_dev_t USB_WRAP; #ifndef __cplusplus -_Static_assert(sizeof(usb_dev_t) == 0x400, "Invalid size of usb_dev_t structure"); +_Static_assert(sizeof(usb_wrap_dev_t) == 0x400, "Invalid size of usb_wrap_dev_t structure"); #endif #ifdef __cplusplus