DWC3 is the Synopsys USB3 dual-role controller embedded in RK3399. On
the PinePhone Pro, the FreeBSD port currently runs it locked in
peripheral mode and exposes a CDC Ethernet gadget on ue0. Plug
the phone into a host machine, configure 10.0.0.1 on the host and
10.0.0.2 on the phone, and ssh pinephone works. That gadget is the
only persistent network path on the bench until WiFi or the modem
take over — so this driver carries a lot of weight.
Identity
| Property | Value |
|---|---|
| Block | Synopsys DWC3 USB3 controller |
| MMIO base | 0xfe800000 |
| GCTL register | 0xfe80c110 (PRTCAP bits [13:12]: 1=host, 2=device, 3=OTG) |
| DTS compatible | snps,dwc3 + rockchip,rk3399-dwc3 glue |
dr_mode | peripheral — see DTS line 1353 of rk3399-pinephone-pro.dts |
| Linux driver | drivers/usb/dwc3/ |
| FreeBSD baseline | sys/dev/usb/controller/dwc3.c |
Driver
● working CDC Ethernet gadget on ue0 is stable. A
2026-05-05 local HTTP sanity test downloaded a 64 MiB file from the host
to the phone over ue0 three times:
23.30 MB/s
23.43 MB/s
23.49 MB/s
That is about 186-188 Mbit/s in the same direction as the WiFi HTTP
fetch test, so the current 42-43 KB/s native-WiFi ceiling is not a
generic TCP, userspace, or DWC3 gadget bottleneck.
Three files cooperate under our overlay:
src/sys/dev/usb/controller/dwc3/rk_dwc3.c— Rockchip glue: clocks, resets, PHY references.src/sys/dev/usb/controller/dwc3/dwc3.c— 727 lines, core controller.src/sys/dev/usb/controller/dwc3/dwc3_gadget.c— 2746 lines, the gadget side that implements CDC ECM end-to-end.
What got built
The gadget path is local to this tree — there was no functional CDC Ethernet gadget in mainline FreeBSD’s DWC3 driver. Highlights from the commit log:
- Bulk endpoint completion delivering packets to
ifnet(8e2fa81dwc3_gadget: handle bulk RX/TX completion — deliver packets to ifnet ). - CDC Ethernet data path with notification + alternate setting
handshake (
f580710dwc3_gadget: fix CDC Ethernet data path — different MAC, send notification ,3f9a6fbdwc3_gadget: move CDC notification to after SET_INTERFACE(alt=1) ,90800bddwc3_gadget: add CDC ECM alt settings for data interface ). - Port to FreeBSD 15’s opaque
if_tAPI (5ef0162dwc3_gadget: port network interface to FreeBSD 15 opaque if_t API ). - TX ring rework — 8-slot DMA ring, completion advances head, queue
up to 8 packets (
d4dfbbddwc3_gadget: allocate 8 TX ring DMA buffers in attach ,569ebb7dwc3_gadget: rewrite if_start with TX ring — queue up to 8 packets ,f0258c2dwc3_gadget: TX completion advances ring, submits next slot ,9255d7adwc3_gadget: fix TRB ring index mismatch — always use TRB[0] ). - TRB ring index fix that resolved a long stall under sustained TX
(
9255d7adwc3_gadget: fix TRB ring index mismatch — always use TRB[0] ). - Reset / OACTIVE state cleanup (
aba89f0dwc3_gadget: mark bulk endpoints stopped and link-down on USB reset ,1a7665edwc3_gadget: clear OACTIVE and TX ring state on USB reset ,175dd10dwc3_gadget: add ep_start_transfer error check and clear OACTIVE on reset ). - TX watchdog NULL deref under load fixed via
USB_BUS_LOCKserialization with the ISR (6b15dc5dwc3_gadget: serialize TX watchdog against ISR via USB_BUS_LOCK ).
The full narrative is in Essay 04: USB-Ethernet up and Essay 05: DWC3 gadget from scratch.
Open work
Static role switching is now solved at the controller level via
hw.dwc3.force_host=1 ( 16a9f5e dwc3: add host-mode boot override ), and the host attach
path emits forensic registers and a success/failure line
( 5a1cb12 dwc3: log host-attach state unconditionally ). On 2026-05-08 a forced-host kernel attached
xHCI cleanly, advertised SuperSpeed at the root, and — with the FUSB302
in source role — enumerated a real USB hub: a VIA Labs USB 2.0 hub IC,
an ASIX AX88179A Gigabit-Ethernet adapter, a Norelsys NS1081 mass-storage
bridge, a Chicony USB keyboard, and the Anker hub’s own management
interface. See appendix: USB-C source role and host-mode bring-up.
Two of the three pieces from the morning’s open list landed on the same day:
axge(4)(andaxe,ure,miibus) are now inPINEPHONE_PRO(5589d8aPINEPHONE_PRO: add axge / axe / ure for downstream USB Ethernet ). The AX88179A on the hub now attaches asue0instead of a generic USB device.rk_typec_phySS lane swap is now configurable via two boot tunables,hw.rk_typec_phy.usb3_enableandhw.rk_typec_phy.flip(1dbe486rk_typec_phy: add tunable USB-3 SuperSpeed bring-up ). Withusb3_enable=1and the matchingflipvalue, downstream USB-3 devices on the same Anker hub enumerate at SuperSpeed 5.0 Gbps. See appendix: USB-C source role and host-mode bring-up for the full receipt and decode.
What is still open:
- The DTS is still
dr_mode = "peripheral". Changing it tootgis only useful once a runtime role-switch bridge can re-role the controller from FUSB302 state changes; the boot tunable is the right shape for now. - The same boot-tunable shape applies to
rk_typec_phy.flip. A cable reseat that flips orientation silently breaks SS until the next reboot. The right answer is a notifier fromfusb302(4)that re- inits the phy with the live orientation.
Once the controller and PHY can stay in sync with the FUSB302 role,
DisplayPort alt-mode is the next layer up — PD VDM negotiation, TCPHY
DP lane reconfig, and a FreeBSD cdn_dp DRM bridge. See the
cross-references in USB-PD / fusb302
and essay 15 — what’s next.
Status
| Question | Answer |
|---|---|
| Probes? | Yes |
Gadget mode (ue0)? | Working — CDC ECM stable |
| Host mode? | Working — hw.dwc3.force_host=1 + xHCI attach + downstream USB-2 and USB-3 device enumeration on 2026-05-08 |
| OTG / role switch? | Boot-time only via hw.dwc3.force_host; no FUSB302-driven dynamic role switch yet |
| SuperSpeed lanes? | Working with hw.rk_typec_phy.usb3_enable=1 + matching flip; downstream hub came up at 5.0 Gbps. Boot-tunable orientation, no dynamic flip on cable reseat |
| USB-PD coupling? | Sink direction works; source role enables VBUS but does not yet drive PD VDM / alt-mode |
Related
- Essay 04: USB-Ethernet up — the first bring-up.
- Essay 05: DWC3 gadget from scratch — the gadget rewrite.
- Essay 16: FUSB302 USB-PD sink — the role-switch piece of the puzzle.
- USB-C / PD recipe — verification.
- Cross-driver audit (2026-04-30) — fusb302 / DWC3 coupling notes.