From d02062f91442aaf2637b95c8c2fbe1f93c815f4a Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Fri, 17 Apr 2026 14:21:00 +0200 Subject: [PATCH] refactor(esp_hal_usb): Enable HNP on HNP-capable controllers --- .../esp32h4/include/hal/usb_dwc_ll.h | 37 ++++++++++++++-- .../esp32p4/include/hal/usb_dwc_ll.h | 42 +++++++++++++++---- .../esp32s2/include/hal/usb_dwc_ll.h | 37 ++++++++++++++-- .../esp32s3/include/hal/usb_dwc_ll.h | 37 ++++++++++++++-- .../esp32s31/include/hal/usb_dwc_ll.h | 42 +++++++++++++++---- components/esp_hal_usb/usb_dwc_hal.c | 10 ++++- 6 files changed, 173 insertions(+), 32 deletions(-) diff --git a/components/esp_hal_usb/esp32h4/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32h4/include/hal/usb_dwc_ll.h index 3a29756850..a3b0ceca9a 100644 --- a/components/esp_hal_usb/esp32h4/include/hal/usb_dwc_ll.h +++ b/components/esp_hal_usb/esp32h4/include/hal/usb_dwc_ll.h @@ -107,6 +107,17 @@ extern "C" { #define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) #define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) +/* + * OTG mode configuration values for the GHWCFG2 register + */ +#define USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG 0 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG 1 +#define USB_DWC_LL_GHWCFG_OTG_MODE_OTG 2 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE 3 +#define USB_DWC_LL_GHWCFG_OTG_MODE_DEVICE 4 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST 5 +#define USB_DWC_LL_GHWCFG_OTG_MODE_HOST 6 + /* * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. * Each QTD describes one transfer. Scatter gather mode will automatically split @@ -202,14 +213,14 @@ static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) hw->gusbcfg_reg.forcehstmode = 1; } -static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_hnp_cap(usb_dwc_dev_t *hw, bool hnp_cap) { - hw->gusbcfg_reg.hnpcap = 0; + hw->gusbcfg_reg.hnpcap = hnp_cap; } -static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_srp_cap(usb_dwc_dev_t *hw, bool srp_cap) { - hw->gusbcfg_reg.srpcap = 0; + hw->gusbcfg_reg.srpcap = srp_cap; } static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) @@ -348,6 +359,24 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) // --------------------------- GHWCFGx Register -------------------------------- +static inline void usb_dwc_ll_ghwcfg_get_hnp_srp_cap(usb_dwc_dev_t *hw, bool *hnp_cap, bool *srp_cap) +{ + const uint32_t otg_mode = hw->ghwcfg2_reg.otgmode; + + if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG) { + *hnp_cap = true; + *srp_cap = true; + } else if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST) { + *hnp_cap = false; + *srp_cap = true; + } else { + *hnp_cap = false; + *srp_cap = false; + } +} + static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) { return hw->ghwcfg3_reg.dfifodepth; 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 d79133ca5d..6b34cdc72f 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 @@ -109,6 +109,17 @@ extern "C" { #define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) #define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) +/* + * OTG mode configuration values for the GHWCFG2 register + */ +#define USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG 0 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG 1 +#define USB_DWC_LL_GHWCFG_OTG_MODE_OTG 2 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE 3 +#define USB_DWC_LL_GHWCFG_OTG_MODE_DEVICE 4 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST 5 +#define USB_DWC_LL_GHWCFG_OTG_MODE_HOST 6 + /* * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. * Each QTD describes one transfer. Scatter gather mode will automatically split @@ -204,19 +215,14 @@ static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) hw->gusbcfg_reg.forcehstmode = 1; } -static inline void usb_dwc_ll_gusbcfg_en_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_hnp_cap(usb_dwc_dev_t *hw, bool hnp_cap) { - hw->gusbcfg_reg.hnpcap = 1; + hw->gusbcfg_reg.hnpcap = hnp_cap; } -static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_srp_cap(usb_dwc_dev_t *hw, bool srp_cap) { - hw->gusbcfg_reg.hnpcap = 0; -} - -static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) -{ - hw->gusbcfg_reg.srpcap = 0; + hw->gusbcfg_reg.srpcap = srp_cap; } static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) @@ -371,6 +377,24 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) // --------------------------- GHWCFGx Register -------------------------------- +static inline void usb_dwc_ll_ghwcfg_get_hnp_srp_cap(usb_dwc_dev_t *hw, bool *hnp_cap, bool *srp_cap) +{ + const uint32_t otg_mode = hw->ghwcfg2_reg.otgmode; + + if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG) { + *hnp_cap = true; + *srp_cap = true; + } else if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST) { + *hnp_cap = false; + *srp_cap = true; + } else { + *hnp_cap = false; + *srp_cap = false; + } +} + static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) { return hw->ghwcfg3_reg.dfifodepth; diff --git a/components/esp_hal_usb/esp32s2/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32s2/include/hal/usb_dwc_ll.h index 5ba840c13e..f09b5b3913 100644 --- a/components/esp_hal_usb/esp32s2/include/hal/usb_dwc_ll.h +++ b/components/esp_hal_usb/esp32s2/include/hal/usb_dwc_ll.h @@ -107,6 +107,17 @@ extern "C" { #define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) #define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) +/* + * OTG mode configuration values for the GHWCFG2 register + */ +#define USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG 0 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG 1 +#define USB_DWC_LL_GHWCFG_OTG_MODE_OTG 2 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE 3 +#define USB_DWC_LL_GHWCFG_OTG_MODE_DEVICE 4 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST 5 +#define USB_DWC_LL_GHWCFG_OTG_MODE_HOST 6 + /* * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. * Each QTD describes one transfer. Scatter gather mode will automatically split @@ -202,14 +213,14 @@ static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) hw->gusbcfg_reg.forcehstmode = 1; } -static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_hnp_cap(usb_dwc_dev_t *hw, bool hnp_cap) { - hw->gusbcfg_reg.hnpcap = 0; + hw->gusbcfg_reg.hnpcap = hnp_cap; } -static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_srp_cap(usb_dwc_dev_t *hw, bool srp_cap) { - hw->gusbcfg_reg.srpcap = 0; + hw->gusbcfg_reg.srpcap = srp_cap; } static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) @@ -346,6 +357,24 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) // --------------------------- GHWCFGx Register -------------------------------- +static inline void usb_dwc_ll_ghwcfg_get_hnp_srp_cap(usb_dwc_dev_t *hw, bool *hnp_cap, bool *srp_cap) +{ + const uint32_t otg_mode = hw->ghwcfg2_reg.otgmode; + + if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG) { + *hnp_cap = true; + *srp_cap = true; + } else if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST) { + *hnp_cap = false; + *srp_cap = true; + } else { + *hnp_cap = false; + *srp_cap = false; + } +} + static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) { return hw->ghwcfg3_reg.dfifodepth; diff --git a/components/esp_hal_usb/esp32s3/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32s3/include/hal/usb_dwc_ll.h index 93ea797ec2..fee252cab8 100644 --- a/components/esp_hal_usb/esp32s3/include/hal/usb_dwc_ll.h +++ b/components/esp_hal_usb/esp32s3/include/hal/usb_dwc_ll.h @@ -107,6 +107,17 @@ extern "C" { #define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) #define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) +/* + * OTG mode configuration values for the GHWCFG2 register + */ +#define USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG 0 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG 1 +#define USB_DWC_LL_GHWCFG_OTG_MODE_OTG 2 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE 3 +#define USB_DWC_LL_GHWCFG_OTG_MODE_DEVICE 4 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST 5 +#define USB_DWC_LL_GHWCFG_OTG_MODE_HOST 6 + /* * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. * Each QTD describes one transfer. Scatter gather mode will automatically split @@ -202,14 +213,14 @@ static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) hw->gusbcfg_reg.forcehstmode = 1; } -static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_hnp_cap(usb_dwc_dev_t *hw, bool hnp_cap) { - hw->gusbcfg_reg.hnpcap = 0; + hw->gusbcfg_reg.hnpcap = hnp_cap; } -static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_srp_cap(usb_dwc_dev_t *hw, bool srp_cap) { - hw->gusbcfg_reg.srpcap = 0; + hw->gusbcfg_reg.srpcap = srp_cap; } static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) @@ -346,6 +357,24 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) // --------------------------- GHWCFGx Register -------------------------------- +static inline void usb_dwc_ll_ghwcfg_get_hnp_srp_cap(usb_dwc_dev_t *hw, bool *hnp_cap, bool *srp_cap) +{ + const uint32_t otg_mode = hw->ghwcfg2_reg.otgmode; + + if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG) { + *hnp_cap = true; + *srp_cap = true; + } else if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST) { + *hnp_cap = false; + *srp_cap = true; + } else { + *hnp_cap = false; + *srp_cap = false; + } +} + static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) { return hw->ghwcfg3_reg.dfifodepth; diff --git a/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h index 96be68454e..ad043ebb3a 100644 --- a/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h +++ b/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h @@ -107,6 +107,17 @@ extern "C" { #define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) #define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) +/* + * OTG mode configuration values for the GHWCFG2 register + */ +#define USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG 0 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG 1 +#define USB_DWC_LL_GHWCFG_OTG_MODE_OTG 2 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE 3 +#define USB_DWC_LL_GHWCFG_OTG_MODE_DEVICE 4 +#define USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST 5 +#define USB_DWC_LL_GHWCFG_OTG_MODE_HOST 6 + /* * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. * Each QTD describes one transfer. Scatter gather mode will automatically split @@ -202,19 +213,14 @@ static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) hw->gusbcfg_reg.forcehstmode = 1; } -static inline void usb_dwc_ll_gusbcfg_en_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_hnp_cap(usb_dwc_dev_t *hw, bool hnp_cap) { - hw->gusbcfg_reg.hnpcap = 1; + hw->gusbcfg_reg.hnpcap = hnp_cap; } -static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +static inline void usb_dwc_ll_gusbcfg_set_srp_cap(usb_dwc_dev_t *hw, bool srp_cap) { - hw->gusbcfg_reg.hnpcap = 0; -} - -static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) -{ - hw->gusbcfg_reg.srpcap = 0; + hw->gusbcfg_reg.srpcap = srp_cap; } static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) @@ -360,6 +366,24 @@ static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) // --------------------------- GHWCFGx Register -------------------------------- +static inline void usb_dwc_ll_ghwcfg_get_hnp_srp_cap(usb_dwc_dev_t *hw, bool *hnp_cap, bool *srp_cap) +{ + const uint32_t otg_mode = hw->ghwcfg2_reg.otgmode; + + if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_HNP_SRP_OTG) { + *hnp_cap = true; + *srp_cap = true; + } else if (otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_OTG || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_DEVICE || + otg_mode == USB_DWC_LL_GHWCFG_OTG_MODE_SRP_HOST) { + *hnp_cap = false; + *srp_cap = true; + } else { + *hnp_cap = false; + *srp_cap = false; + } +} + static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) { return hw->ghwcfg3_reg.dfifodepth; diff --git a/components/esp_hal_usb/usb_dwc_hal.c b/components/esp_hal_usb/usb_dwc_hal.c index d6a5d6bedc..d90b8612f3 100644 --- a/components/esp_hal_usb/usb_dwc_hal.c +++ b/components/esp_hal_usb/usb_dwc_hal.c @@ -125,9 +125,15 @@ static void set_defaults(usb_dwc_hal_context_t *hal) usb_dwc_ll_set_stoppclk(hal->dev, false); #endif // SOC_IS(ESP32P4) || SOC_IS(ESP32S31) usb_dwc_ll_gahbcfg_set_hbstlen(hal->dev, hbstlen); //Set AHB burst mode + //GUSBCFG register - usb_dwc_ll_gusbcfg_dis_hnp_cap(hal->dev); //Disable HNP - usb_dwc_ll_gusbcfg_dis_srp_cap(hal->dev); //Disable SRP + bool hnp_cap, srp_cap; + usb_dwc_ll_ghwcfg_get_hnp_srp_cap(hal->dev, &hnp_cap, &srp_cap); + + // On targets where the USB controller is HNP capable, the data lines pull-downs are controlled by the USB controller. + // Enabling HNP capability will also enable the data line pull-downs in deep-sleep mode eliminating leakage current. + usb_dwc_ll_gusbcfg_set_hnp_cap(hal->dev, hnp_cap); + usb_dwc_ll_gusbcfg_set_srp_cap(hal->dev, false); //Disable SRP // If this USB-DWC supports HS PHY, use it if (hal->constant_config.hsphy_type != 0) {