-
Notifications
You must be signed in to change notification settings - Fork 8.3k
drivers: uhc_dwc2: Initial support [WIP] #94266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
drivers: uhc_dwc2: Initial support [WIP] #94266
Conversation
|
Hello @roma-jam, and thank you very much for your first pull request to the Zephyr project! |
9053da6 to
ecce802
Compare
|
For anyone trying this, here is what I did to get it built:
Then modify the build script to include one extra directory (espressif-specific): diff --git a/zephyr/esp32s3/CMakeLists.txt b/zephyr/esp32s3/CMakeLists.txt
index aedf412601..6a5546da9e 100644
--- a/zephyr/esp32s3/CMakeLists.txt
+++ b/zephyr/esp32s3/CMakeLists.txt
@@ -221,7 +221,7 @@ if(CONFIG_SOC_SERIES_ESP32S3)
)
endif()
- if (CONFIG_UDC_DWC2)
+ if (CONFIG_UDC_DWC2 OR CONFIG_UHC_DWC2)
zephyr_include_directories(
../../components/usb/include
)Then to build it, disable the device stack (or build error occurs insofar): |
|
@roma-jam thank you very much for this effort! Maybe you saw this incomplete branch from Espressif? raffarost@54dcf56 I could run the firmware but not yet test it I am still waiting an ESP32-S3 devkit (with 2 discrete USB interface to make sure there is no bug related to switching between the "jtag/serial and "usb-otg" interface on the same port) in the mail. In the other hand, I will also try to get it working on a Nordic devkit that also has DWC2, and it seems like some STM32 part also has it. Glad to see you preserved all the vendor-quirks system to keep all vendor-specific on separate files. I will post here as I am able to get more progress, and start doing early review as well. |
|
Hi @josuah, yes, I saw that and many thanks to @raffarost, I took couple of things from his work. Besides that, I decided to proceed with simple implementation for all controllers with dwc2 (I hope, at least I tried to predict as much as I could) with Buffer DMA config (as currently in TinyUSB host) and with similar logic of event handling (ports, pipes and channels) , as in esp-idf USB Host stack. Buffer DMA (not Scatter-Gahter) because it supports split-transactions, and I believe we want to have fully-working external hubs with HS root ports. Thanks for you support and just in case - this is still a draft and I pushed it because the first step positive scenario (like device enumeration is done) is copmleted. But there are still a lot of parts are missing. |
7f09880 to
e433713
Compare
|
@roma-jam I received my ESP32-S3 DevkitC-1 to test this. So far I used an OTG adapter on the "USB" interface and connected it to various devices but after No problem, I can investigate this, but just in case there was something obvious I missed, what is your physical setup? Build command used with your latest commits from 40 minutes ago: I suppose the warning message means it needs an USB HighSpeed device (USB MSC dongle) instead of FullSpeed? Or maybe a LowSpeed only (keyboard/mouse)? I will try to support for DWC2 OTG on an nRF54LM20 DK, so different hardware anyway, but I was interested in testing the same way as you, to check that things still work on the ESP32 after introducing more code for the nRF54LM20. I have the access to DWC2 docs and can join the effort with writing the driver as soon as I am done with the low levels (enable the core, PHY setup...). Thanks! |
|
Hi @josuah, Sorry for this. Yes, there is no 5V on the USB OTG port connector, so this dev kit is for the usb device, not the host. But! You can use the usb wire, attached to the pins or bypass the D7 to provide 5V to the port. Please, refer to the schematic: https://dl.espressif.com/dl/schematics/SCH_ESP32-S3-DevKitC-1_V1.1_20221130.pdf UPD:
No, the warning message just shows that the supported PHY is FS and there is no config for this so far. On esp this config is by default after the power on, so it will work without it. But I will add it soon. Thanks. |
|
That makes sense thank you for the hint I thought I missed something obvious. |
425c8d6 to
c4ff7f3
Compare
a73ab26 to
798801b
Compare
Add USB-OTG peripheral support to ESP32S3. Signed-off-by: Raffael Rostagno <[email protected]>
Signed-off-by: Roman Leonov <[email protected]>
Signed-off-by: Roman Leonov <[email protected]>
798801b to
bea0307
Compare
358b64c to
8292a0e
Compare
Added register bitmask description with low-level abstraction Signed-off-by: Roman Leonov <[email protected]>
cee68df to
f26fd50
Compare
Signed-off-by: Roman Leonov <[email protected]>
f26fd50 to
426ed18
Compare
|
|
Hello again @roma-jam, I could adapt this PR to be working on nRF54LM20 by only modifying the vendor quirks.= There seem to be a bit of coding style work needed, and maybe a few TODOs to cover. Should I keep going with the refactoring and coding style change to merge this then? I will start in Thanks! |
|
Hi @josuah, thanks for the feedback!
this seems like a good news, isn't it? I wasn't able to get back to this task in the last few months, but my plan is still the same:
Could you please specify, what do you want to cover in the priority order? So I can solve them one by one in the meantime. |
I think it is :)
This turned out convenient to have some PR stability during this time.
Maybe these could eventually be added over time, as new devices need to insert something at a new location
I was thinking static arrays could be used to avoid
What I needed to do:
What I wished to do is to:
I thought it'd be safer to do "big changes" with both hardware at hand to test it after every step (or what if I answer you "it does not work anymore", several days to find 1 typo >_<).
I think enabling, testing HighSpeed support, disabling HNP (should we rely on Type-C only for role swapping?)... What to do next? :) |
|
If rebasing on Which has this workaround: |
|
If asking to make one change, waiting the answer, then test things locally on the devkit, it will take ages. Let's try to make modifications, and announce them, so that it's possible to give feedback, and potentially I revert some changes if I am mistaken or better options exist etc. Once things are in shape, it becomes easier to pursue with actual feature development on top on both our side, this becomes normal PRs... |
josuah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First few modifications I am doing on my fork...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am removing every typedef as they are not allowed/recommended by Linux Kernel coding style:
https://www.kernel.org/doc/html/latest/process/coding-style.html#typedefs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am removing the section decorations for replacing them by a plain comment.
A bit less easy to notice but other Zephyr sources very rarely use decorations, so might as well do the same...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am converting source using clang-format to fix all of these. Zephyr provides a .clang-format file which is guaranteed to give code matching the coding style in almost every case,
USB area uses tabs for indenting \ though, also compatible AFAIU, so might as well do that once refactored...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doxygen comments are avoided from drivers as it would effectively generate docs for it (or at least in theory) and users are not expected to use the functions directly (declard static).
The @params are further self-explanatory (i.e. can lookup the struct definition to know what it is).
I also propose to not add a Thread context and only mark Interrupt context implying everything else is in non-IRQ context.
The challenge with saying "thread context" is that some day a function is refactored and the comment is out of sync easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to not make use of "lookup tables" for debug enums, which uses flash (though only if debug logs are enabled), and quickly become out of sync (i.e. here it lacks "Recovery"), which risks invalid accesses and confusing user more than needed.
They are also scarcely used in other drivers.
This reduces convenience though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No typedef means that pipe_hdl_t becomes struct dwc2_pipe * directly in the code and not a separate type anymore (by just expanding the typedefs...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is no typedef, tokens like pipe_obj no more need to have _s suffix for structs as there is only one type name: struct typename.
I am also adding a uhc_dwc2_ prefix to locally defined types, because this namespace is going to be "assaulted" by arbitrary HALs, some in the future might define their own names that clash with these in this driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The val of the unions does not seem used at all except for setting the whole thing to 0, which can easily be done with memset(), so am tempted to withdraw it for now.
Other drivers seems to not use this method for quickly resetting bitfields to 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While having separate structs helps with reducing the scope of functions to the minimum struct they act upon (good), it also mean a higher number of types, and refactoring (i.e. accessing an extra priv->field not on this "sub-struct") might require passing the struct device anyway.
Other drivers typically have all struct device * as first argument regardless of their use, with a boilerplate to access priv (USB-specific), config (all drivers) and data (all drivers, but not used directly in USB, priv is used instead).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To facilitate comparing the register access sequence with the programmer guide (i.e. to write a bug report to Synopsys), I am tempted to flatten the register accesses, in particular for functions used only once, and even annotate the steps of the programmer guide in the driver.
There are a lot of "HAL"s used in Zephyr drivers, but does not seem required to get this driver to work, and in a way, the HAL here is UHC API already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beware to not copy&paste from the Programmer Guide as it is not publicly available.
|
Hi @josuah, thanks a lot for looking through my code and for such a usefull feedback! I can‘t guarantee that I will fix everything in the next couple weeks, as I am in the middle of the other task. So, I will definetely return back to this PR and I hope to make it sooner. |
|
To avoid ambiguity: I am only announcing the asethetical code changes I'm doing now, and report what I've changed (to keep this a discussion and not impose anything). Then I will propose you a replacement PR that we can both use as a root. Hopefully this removes you the paperwork, while give an example to use to implement the actual features! :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to try to remove all k_malloc() to avoid sharing memory with the application and drivers, in both area used and resources.
This helps keeping everything more predictable under low-memory conditions (the application does not crash the drivers and other way around).
Alternative if really needed: k_heap_alloc() with a locally defined heap with size from Kconfig.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments for every DEVICE_DT_INST_DEFINE() field are rare... a shame as it helps with readability, but I will try to reduce review time and pick the same style as other drivers.
I will also try to make this multi-instance, even if it does not need to be, as this is now meant as a vendor-neutral implementation, and future SoCs could want multi-instance maybe? (i.e. some i.MXRT have USB1 and USB2).
Not sure if really needed though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am tempted to remove all bitfields that are not just 1~2-bit flags.
This might help avoid accidental bugs (I know I always miscalculate something and it integer overflows...). And uint8_t var has same footprint as uint32_t var: 8 (or maybe even fewer in case the uint32_t is not completely filled).
This also allow to use enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is nothing called "pipe" in DWC2 handbook or databook, so we may merge channel and pipe in a single struct, and this way there is no need to cross-reference them via "context" structs.
Furthermore, instead of passing struct uhc_dwc2_pipe (new name for pipe_t), it may be possible to pass const struct device and channel_num, and then use channel = priv->channels[channel_num];, which mean there is no more need to store the chan_idx, nor the the regs (which can be retreived given the channel number).
Next, the struct uhc_dwc2_pipe can be renamed into struct uhc_dwc2_channel to keep them matching with the DWC2 native hardware naming...
I will try this and hope this makes sense.





Description
Adding USB host driver initial support for DWC2 controller.
Features and Limitations
Commits by their order
host_prj.confoverlay forsample/subsys/usb/shellusb_dwc2_hw.huhc_dwc2.*files with vendor quirks and Kconfig forUHC_DWC2Testing
After running the shell sample and initial driver enabling with commands
usbh initandusbh enable: