Skip to content

uhc: dwc2: vendor quirks for nRF54LM20#95723

Draft
josuah wants to merge 5 commits intozephyrproject-rtos:mainfrom
josuah:feature/usb_dwc2_host_support_nrf54lm20
Draft

uhc: dwc2: vendor quirks for nRF54LM20#95723
josuah wants to merge 5 commits intozephyrproject-rtos:mainfrom
josuah:feature/usb_dwc2_host_support_nrf54lm20

Conversation

@josuah
Copy link
Copy Markdown
Contributor

@josuah josuah commented Sep 9, 2025

Dependencies:

For testing, provide power externally using an USB OTG adapter with external power supply.

@josuah josuah added the DNM This PR should not be merged (Do Not Merge) label Sep 9, 2025
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch 3 times, most recently from c6292fb to c7b19bc Compare September 9, 2025 13:11
@roma-jam
Copy link
Copy Markdown
Contributor

roma-jam commented Sep 9, 2025

Hi @josuah,
oh, good to see that it works somehow for you.

But please, wait for a moment, I will remove the LL-layer completely and make everything udc_dwc2-alike soon.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Sep 9, 2025

@josuah
Copy link
Copy Markdown
Contributor Author

josuah commented Sep 9, 2025

But please, wait for a moment, I will remove the LL-layer completely and make everything udc_dwc2-alike soon.

No problem. I am now pursuing with the host class API.
Thanks for chiming in and for the DWC2 implementation!

@roma-jam
Copy link
Copy Markdown
Contributor

Hi @josuah,

I have removed the LL-layer, so please, feel free to rebase.

Also, I can see that the log is from uhc and then in the end - the udc: uhc_dwc2_enable: Enable device 0x50020000.

Just in case - is that intentional? Because I didn't check the possibility to run udc after uhc, so there could be some moments, that need to be fixed.

@josuah
Copy link
Copy Markdown
Contributor Author

josuah commented Sep 11, 2025

Thanks! I will do this soon.

uhc_dwc2_enable: Enable device 0x50020000 is just leftover from code imported to initialize DWC2 from the nRF54LM20.

https://github.com/zephyrproject-rtos/zephyr/pull/95723/files#diff-a5c1ac2b1e9f1d28cb96d97ecee24e3b15ab543cf1f0d4cfbe650471bae2c02aR2546

No problem with you refactoring in the meantime, please feel free to keep doing so.

@josuah
Copy link
Copy Markdown
Contributor Author

josuah commented Nov 6, 2025

Some script showing the difference in hardware configuration registers of ESP32-S3 and nRF54LM20.

dwc2_decode_regs.py

output
GHWCFG1 (ESP32): 0x00000000
 EpDir:32 = 0
32 bits

GHWCFG1 (nRF54): 0x00000000
 EpDir:32 = 0
32 bits

GHWCFG2 (ESP32): 0x224dd930
 OtgMode:3 = 0
 OtgArch:2 = 2
 SingPnt:1 = 1
 HsPhyType:2 = 0
 FsPhyType:2 = 1
 NumDevEps:4 = 6
 NumHstChnl:4 = 7
 PerioSupport:1 = 1
 DynFifoSizing:1 = 1
 MultiProcIntrpt:1 = 0
 Reserved:1 = 0
 NPTxQDepth:2 = 1
 PTxQDepth:2 = 2
 TknQDepth:5 = 8
 OTG_ENABLE_IC_USB:1 = 0
32 bits

GHWCFG2 (nRF54): 0x22affc52
 OtgMode:3 = 2
 OtgArch:2 = 2
 SingPnt:1 = 0
 HsPhyType:2 = 1
 FsPhyType:2 = 0
 NumDevEps:4 = 15
 NumHstChnl:4 = 15
 PerioSupport:1 = 1
 DynFifoSizing:1 = 1
 MultiProcIntrpt:1 = 0
 Reserved:1 = 1
 NPTxQDepth:2 = 2
 PTxQDepth:2 = 2
 TknQDepth:5 = 8
 OTG_ENABLE_IC_USB:1 = 0
32 bits

GHWCFG3 (ESP32): 0x00c804b5
 XferSizeWidth:4 = 5
 PktSizeWidth:3 = 3
 OtgEn:1 = 1
 I2CIntSel:1 = 0
 VndctlSupt:1 = 0
 OptFeature:1 = 1
 RstType:1 = 0
 ADPSupport:1 = 0
 HSICMode:1 = 0
 BCSupport:1 = 0
 LPMMode:1 = 0
 DfifoDepth:16 = 200
32 bits

GHWCFG3 (nRF54): 0x0be0c0e8
 XferSizeWidth:4 = 8
 PktSizeWidth:3 = 6
 OtgEn:1 = 1
 I2CIntSel:1 = 0
 VndctlSupt:1 = 0
 OptFeature:1 = 0
 RstType:1 = 0
 ADPSupport:1 = 0
 HSICMode:1 = 0
 BCSupport:1 = 1
 LPMMode:1 = 1
 DfifoDepth:16 = 3040
32 bits

GHWCFG4 (ESP32): 0xd3f0a030
 NumDevPerioEps:4 = 0
 PartialPwrDn:1 = 1
 AhbFreq:1 = 1
 Hibernation:1 = 0
 ExtendedHibernation:1 = 0
 Reserved_8:1 = 0
 EnhancedLPMSupt1:1 = 0
 ServIntFlow:1 = 0
 ipgisocSupt:1 = 0
 ACGSupt:1 = 0
 EnhancedLPMSupt:1 = 1
 PhyDataWidth:2 = 2
 NumCtlEps:4 = 0
 IddgFltr:1 = 1
 VBusValidFltr:1 = 1
 AValidFltr:1 = 1
 BValidFltr:1 = 1
 SessEndFltr:1 = 1
 DedFifoMode:1 = 1
 INEps:4 = 4
 DescDMAEnabled:1 = 1
 DescDMA:1 = 1
32 bits

GHWCFG4 (nRF54): 0x3e10aa60
 NumDevPerioEps:4 = 0
 PartialPwrDn:1 = 0
 AhbFreq:1 = 1
 Hibernation:1 = 1
 ExtendedHibernation:1 = 0
 Reserved_8:1 = 0
 EnhancedLPMSupt1:1 = 1
 ServIntFlow:1 = 0
 ipgisocSupt:1 = 1
 ACGSupt:1 = 0
 EnhancedLPMSupt:1 = 1
 PhyDataWidth:2 = 2
 NumCtlEps:4 = 0
 IddgFltr:1 = 1
 VBusValidFltr:1 = 0
 AValidFltr:1 = 0
 BValidFltr:1 = 0
 SessEndFltr:1 = 0
 DedFifoMode:1 = 1
 INEps:4 = 15
 DescDMAEnabled:1 = 0
 DescDMA:1 = 0
32 bits

GOTGCTL (ESP32): 0x00240000
 SesReqScs:1 = 0
 SesReq:1 = 0
 VBValidOvEn:1 = 0
 VBValidOvVal:1 = 0
 AValidOvEn:1 = 0
 AValidOvVal:1 = 0
 BValidOvEn:1 = 0
 BValidOvVal:1 = 0
 HstNegScs:1 = 0
 HnpReq:1 = 0
 HstSetHnpEn:1 = 0
 DevHnpEn:1 = 0
 EhEn:1 = 0
 RSVD:2 = 0
 DbnceFltrBypass:1 = 0
 ConIdSts:1 = 0
 DbncTime:1 = 0
 ASesVld:1 = 1
 BSesVld:1 = 0
 OtgVer:1 = 0
 CurMod:1 = 1
 MultValidBc:5 = 0
 ChirpEn:1 = 0
 eUSB2_Phy_Disc_Supp:1 = 0
 Reserved_30_29:2 = 0
 TestMode_Corr_eUSB2:1 = 0
32 bits

GOTGCTL (nRF54): 0x03050070
 SesReqScs:1 = 0
 SesReq:1 = 0
 VBValidOvEn:1 = 0
 VBValidOvVal:1 = 0
 AValidOvEn:1 = 1
 AValidOvVal:1 = 1
 BValidOvEn:1 = 1
 BValidOvVal:1 = 0
 HstNegScs:1 = 0
 HnpReq:1 = 0
 HstSetHnpEn:1 = 0
 DevHnpEn:1 = 0
 EhEn:1 = 0
 RSVD:2 = 0
 DbnceFltrBypass:1 = 0
 ConIdSts:1 = 1
 DbncTime:1 = 0
 ASesVld:1 = 1
 BSesVld:1 = 0
 OtgVer:1 = 0
 CurMod:1 = 0
 MultValidBc:5 = 12
 ChirpEn:1 = 0
 eUSB2_Phy_Disc_Supp:1 = 0
 Reserved_30_29:2 = 0
 TestMode_Corr_eUSB2:1 = 0
32 bits

HCFG (nRF54): 0x00220000
 FSLSPclkSel:2 = 0
 FSLSSupp:1 = 0
 RESERVED2:4 = 0
 Ena32KHzS:1 = 0
 ResValid:8 = 0
 dis_tx_ipgap_dly_check:1 = 0
 RESERVED1:6 = 17
 DescDMA:1 = 0
 FrListEn:2 = 0
 PerSchedEna:1 = 0
 RESERVED:4 = 0
 ModeChTimEn:1 = 0
32 bits

HCFG (ESP32): 0x00100000
 FSLSPclkSel:2 = 0
 FSLSSupp:1 = 0
 RESERVED2:4 = 0
 Ena32KHzS:1 = 0
 ResValid:8 = 0
 dis_tx_ipgap_dly_check:1 = 0
 RESERVED1:6 = 8
 DescDMA:1 = 0
 FrListEn:2 = 0
 PerSchedEna:1 = 0
 RESERVED:4 = 0
 ModeChTimEn:1 = 0
32 bits

HFIR (nRF54): 0x000017d7
 FrInt:16 = 6103
 HFIRRldCtrl:1 = 0
 RESERVED:17 = 0
34 bits

HFIR (ESP32): 0x000017d7
 FrInt:16 = 6103
 HFIRRldCtrl:1 = 0
 RESERVED:17 = 0
34 bits

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Nov 6, 2025

The following west manifest projects have changed revision in this Pull Request:

Name Old Revision New Revision Diff

All manifest checks OK

Note: This message is automatically posted and updated by the Manifest GitHub Action.

@github-actions github-actions Bot added manifest manifest-hal_espressif DNM (manifest) This PR should not be merged (controlled by action-manifest) labels Nov 6, 2025
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch from 8e1b61a to 89c6af5 Compare November 7, 2025 13:06
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch 5 times, most recently from aa033fb to 85e6c06 Compare November 10, 2025 12:17
Comment thread drivers/usb/uhc/uhc_dwc2.c Outdated
struct uhc_dwc2_data *priv = uhc_get_private(dev);
enum uhc_port_event port_event = UHC_PORT_EVENT_NONE;

/* TODO: enter critial section */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better to keep the TODOs regarding the critical section, as it is important.

Copy link
Copy Markdown
Contributor Author

@josuah josuah Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to reduce everything to the minimal and might have trimmed important pieces accidentally.
The hope is that it's easier to add them back after the conversion rather than keep them while trying as hard to know what was historical baggage from the ESP32 export, or an optimization encountered in a different platform, or needed part of the operation etc. Thanks for helping seeing clear!

Regarding the critical section, I wonder:

  • If we are in IRQs, it is not possible to lock IRQs or have blocking calls anyway
  • If we are not in the IRQs, we are in the main thread or in an API call, and there is a global lock already.

Is there extra locking required in addition to this?

@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch 4 times, most recently from ee52eba to d8a9b2e Compare November 11, 2025 21:20
@josuah josuah linked an issue Jan 27, 2026 that may be closed by this pull request
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch from 92c7a85 to 123333d Compare January 28, 2026 01:53
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch 2 times, most recently from 5f5d57e to 89273ae Compare February 16, 2026 01:23
@sonarqubecloud
Copy link
Copy Markdown

@josuah josuah closed this Mar 5, 2026
@josuah josuah changed the title UHC: DWC2: host support for nRF54LM20 uhc: dwc2: vendor quirks for nRF54LM20 Apr 25, 2026
@josuah josuah reopened this Apr 25, 2026
@josuah josuah force-pushed the feature/usb_dwc2_host_support_nrf54lm20 branch from 89273ae to e8d3b99 Compare April 25, 2026 15:11
@josuah josuah marked this pull request as ready for review April 25, 2026 15:35
@josuah
Copy link
Copy Markdown
Contributor Author

josuah commented Apr 25, 2026

@zephyrbot zephyrbot added area: USB Universal Serial Bus area: Samples Samples area: Devicetree Binding PR modifies or adds a Device Tree binding platform: ESP32 Espressif ESP32 area: Boards/SoCs platform: nRF Nordic nRFx area: Xtensa Xtensa Architecture labels Apr 25, 2026
@zephyrbot zephyrbot requested a review from anangl April 25, 2026 15:37
int err;

/* TODO: not expected to be there */
LOG_MODULE_DECLARE(uhc_dwc2, CONFIG_UHC_DRIVER_LOG_LEVEL);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be removed now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.


if (!k_event_wait(&data->events, USBHS_VBUS_READY, false, K_NO_WAIT)) {
LOG_INF("VBUS is not ready, block udc_enable()");
if (!k_event_wait(&data->events, USBHS_VBUS_READY, false, timeout)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to wait USBHS_VBUS_READY two times: one with K_NO_WAIT and he second one with timeout?

Isn't the timeout only enough?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is from the UDC DWC2 quirk, the first one does not wait but allows to print a logging message. That does not seems to be right for the UHC.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, only one k_event_wait() now.

The message was printed every time in practice...

Josuah Demangeon and others added 2 commits April 30, 2026 14:14
Add 'gsnpsid' and 'ghwcfg3' to DWC2 USB peripheral in order to check
that they are as expected at runtimne, which the host driver can use.

Signed-off-by: Josuah Demangeon <josuah.demangeon@nordicsemi.no>
Note: Control transfers only

Add initial usb host driver for Synopsys DWC2 with vendor quirks.

Signed-off-by: Roman Leonov <jam_roma@yahoo.com>
@josuah
Copy link
Copy Markdown
Contributor Author

josuah commented May 1, 2026

Force-push:

  • Small bugfix for DWC2 to support nRF54LM20

Not sure why this is needed, but it helps to do this:

diff --git a/drivers/usb/uhc/uhc_dwc2.c b/drivers/usb/uhc/uhc_dwc2.c
index d4453c20cdd..c249674e5e9 100644
--- a/drivers/usb/uhc/uhc_dwc2.c
+++ b/drivers/usb/uhc/uhc_dwc2.c
@@ -847,7 +847,6 @@ static int uhc_dwc2_channel_configure(const struct device *const dev,
 	hcintmsk = sys_read32((mem_addr_t)&channel->regs->hcintmsk);
 
 	/* Enable transfer complete and channel halted interrupts */
-	hcintmsk |= USB_DWC2_HCINT_XFERCOMPL;
 	hcintmsk |= USB_DWC2_HCINT_CHHLTD;
 	/* Enable error interrupts */
 	hcintmsk |= USB_DWC2_HCINT_ERRORS;
@@ -1304,6 +1303,8 @@ static int uhc_dwc2_bus_reset(const struct device *const dev)
 	k_msleep(RESET_RECOVERY_MS);
 
 	/* Finish the port config for the appeared device */
+	dwc2_hal_set_fifo_sizes(dwc2, config->ghwcfg2, config->ghwcfg3);
+
 	/* TODO: set frame list for the ISOC/INTR xfer */
 	/* TODO: enable periodic transfer */
 

This also matches what is described by the datasheet.

Josuah Demangeon added 3 commits May 1, 2026 14:44
Add vendor quirks for nRF54LM20 PHY configuration for DWC2 in host mode.
Given the PHY is powered from USB, the PHY needs to be configured and
powered on before registers can be accessed or the SoC freezes on any
register access.

Signed-off-by: Josuah Demangeon <josuah.demangeon@nordicsemi.no>
Enable the DWC2 host controller, for now requiring external power to be
provided to the VBUS pin, however usable.

Signed-off-by: Josuah Demangeon <josuah.demangeon@nordicsemi.no>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 1, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Boards/SoCs area: Devicetree Binding PR modifies or adds a Device Tree binding area: Samples Samples area: USB Universal Serial Bus area: Xtensa Xtensa Architecture platform: ESP32 Espressif ESP32 platform: nRF Nordic nRFx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DWC2 USB Host controller (UHC)

5 participants