From 7b520d0f5ceab7aa2ca46a17964f63d756872b3d Mon Sep 17 00:00:00 2001 From: "peter.marcisovsky" Date: Thu, 23 Apr 2026 15:31:28 +0200 Subject: [PATCH] fix(usb_host): Fix HNP cap on HS port of esp32p4 for HW version < 3 --- .../esp32p4/include/hal/usb_dwc_ll.h | 18 ++++++++++++++++++ components/esp_hal_usb/usb_dwc_hal.c | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/components/esp_hal_usb/esp32p4/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32p4/include/hal/usb_dwc_ll.h index 6b34cdc72f6..f5b7b79f62d 100644 --- a/components/esp_hal_usb/esp32p4/include/hal/usb_dwc_ll.h +++ b/components/esp_hal_usb/esp32p4/include/hal/usb_dwc_ll.h @@ -1108,6 +1108,24 @@ FORCE_INLINE_ATTR void usb_dwc_ll_enable_bvalid_override(usb_dwc_dev_t *hw, bool hw->gotgctl_reg.bvalidoven = override; } +/** + * @brief Software-anchor OTG session comparators for internal UTMI HS host (ESP32-P4). + * + * The HS USB-DWC instance does not expose ID / VBUSVALID / AVALID through the GPIO matrix + * (see `usb_dwc_periph.c`: `otg_signals` is NULL for controller 0). The FS controller uses + * constant matrix inputs in `usb_phy_otg_set_mode()` instead; + * When GUSBCFG.HNPCap is set, the OTG session logic still runs; floating or + * weak internal sense can make the host port unstable. This mirrors the FS host strap values: + * VBUS valid and A-session valid asserted + */ +FORCE_INLINE_ATTR void usb_dwc_ll_gotgctl_anchor_internal_utmi_a_host(usb_dwc_dev_t *hw, bool set_hst_set_hnp_en) +{ + hw->gotgctl_reg.vbvalidoven = 1; + hw->gotgctl_reg.vbvalidovval = 1; + hw->gotgctl_reg.avalidoven = 1; + hw->gotgctl_reg.avalidovval = 1; +} + // ---------------------------- Power and Clock Gating Register -------------------------------- FORCE_INLINE_ATTR void usb_dwc_ll_set_stoppclk(usb_dwc_dev_t *hw, bool stop) { diff --git a/components/esp_hal_usb/usb_dwc_hal.c b/components/esp_hal_usb/usb_dwc_hal.c index d90b8612f31..6f3c6a71a27 100644 --- a/components/esp_hal_usb/usb_dwc_hal.c +++ b/components/esp_hal_usb/usb_dwc_hal.c @@ -147,6 +147,13 @@ static void set_defaults(usb_dwc_hal_context_t *hal) usb_dwc_ll_gahbcfg_en_global_intr(hal->dev); //Enable interrupt signal //Enable host mode usb_dwc_ll_gusbcfg_force_host_mode(hal->dev); + +#if SOC_IS(ESP32P4) + if (hnp_cap && hal->constant_config.hsphy_type != 0 && !ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300)) { + // ESP32-P4 HW rev < 3.0, HS DWC + UTMI: no GPIO-matrix OTG sense for this instance; when HNPCap is enabled, anchor the A-host session + usb_dwc_ll_gotgctl_anchor_internal_utmi_a_host(hal->dev, true); + } +#endif // SOC_IS(ESP32P4) } void usb_dwc_hal_init(usb_dwc_hal_context_t *hal, int port_id)