DWC3 Xilinx Linux USB driver
Introduction
DWC3 Xilinx Linux USB driver supports Zynq Ultrascale USB 3.0 IP and Versal Adaptive SoCs USB IPs.
ZynqMP USB 3.0 Controller implements a 5.0 Gbit/s raw transfer rate using 8b/10b encoding. USB 2.0 implements the Hi-Speed mode (HS – 480 Mbit/s), while USB 1.1 implements Low Speed (LS) – 1.5 Mbit/s and Full Speed (FS) – 12 Mbit/s). The USB 3.0 Controller provides one 5.0Gbit/s USB channel using the PS internal GT as PHY.
The Versal adaptive SoC USB controller is based on newer Synopsys IP and is implemented as a USB 2.0 controller.
The Versal Gen 2 SOC has two USB 2.0 controllers and one MMI USB3 DRD IP. MMI USB DRD IP is usb3.1 Gen2 controller which supports SSP (10-Gbps), SuperSpeed(5-Gbps), high-speed(480-Mbps), full-speed(12-Mbps), and low-speed(1.5-Mbps) operation modes.
Table of Contents
- 1 Introduction
- 2 HW/IP Features
- 3 Missing Features, Known Issues and Limitations
- 4 Host Mode
- 4.1 Kernel Configuration
- 4.2 Devicetree
- 4.3 Test Procedure
- 4.3.1 Expected Output
- 4.4 Performance
- 5 Peripheral Mode
- 5.1 Mass Storage
- 5.1.1 Kernel Configuration
- 5.1.2 Devicetree :
- 5.1.3 Performance
- 5.1.4 Testing Procedure
- 5.2 Ethernet Gadget
- 5.2.1 Kernel Configuration
- 5.2.2 Devicetree
- 5.2.3 Performance
- 5.2.4 Testing Procedure
- 5.2.4.1 Expected Output:
- 5.3 USB Attached SCSI Protocol(UASP)
- 5.3.1 Kernel Configuration
- 5.3.2 Devicetree
- 5.3.3 Performance
- 5.3.4 Test procedure
- 5.1 Mass Storage
- 6 OTG Mode
- 7 Mainline Status
- 8 Phy Settings
- 9 Change log
HW/IP Features
The ZynqMP USB 3.0 Controller shall provide one 5.0 Gbit/s USB channel using the PS internal GT as the PHY. Refer to the Zynq UltraScale+ Device Technical Reference Manual (UG1085) for USB IP details.
The Versal USB 2.0 controller is compliant with the USB 2.0 specification to support high, full, and low-speed modes in all configurations. It can be configured as a host, a device, or in on-the-go (OTG). Refer to the Versal Adaptive SoC Technical Reference Manual (AM011) for USB IP details.
Features supported in the driver
The Linux DWC3 driver supports all standard USB controller features.
For the MMI USB Controller, host mode is validated using a Kingston DataTraveler Max SSP pendrive, and device mode is validated with the mass storage driver. DRD role switching and Type-C flip are not supported.
Missing Features, Known Issues and Limitations
ZynqMP USB 3.0 controller doesn't support USB 3.0 OTG (On The Go) host/device selection
Important AR links
USB core reset in Linux can cause issues with USB device connected if it was previously powered in U-boot - AR-72376
USB3.0 device mode does not work when booting through USB boot mode - AR-72409
USB 3.0 standalone device driver does not send STALL response for every unsupported command - AR-71925
USB 3.0 port hangs after plug-in and plug-out cable in gadget mode - AR-76696
USB DWC3-core getting the clock error message "Failed to get clk 'ref': -2“ - AR-72764
USB Remote wake-up feature support (2020 release) - AR-76750
USB Remote wake-up feature support (2021.1 and later release) - AR-76949
Host Mode
ZCU102 board jumper settings for Host mode
J7 - ON
J113 - 1-2
J110 - 2-3
Please refer the below image for jumper settings on ZCU102 board
USB 3.0 Host mode setup snapshot
Kernel Configuration
Device Drivers------>
USB support
<*> xHCI HCD (USB 3.0) support
<*> USB Mass Storage support
<*> DesignWare USB3 DRD Core Support
DWC3 Mode Selection (Dual Role mode) --->
(X) Dual Role mode
By enabling the above we need to see the below mentioned Kconfig parameter enabled
CONFIG_USB_DWC3 = y
CONFIG_USB_DWC3_DUAL_ROLE = y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PLATFORM=y
Devicetree
usb@ff9d0000 {
#address-cells = <0x02>;
#size-cells = <0x02>;
status = "okay";
compatible = "xlnx,zynqmp-dwc3";
reg = <0x00 0xff9d0000 0x00 0x100>;
clock-names = "bus_clk\\0ref_clk";
power-domains = <0x84 0x16>;
resets = <0x03 0x3b 0x03 0x3d 0x03 0x3f>;
reset-names = "usb_crst\\0usb_hibrst\\0usb_apbrst";
reset-gpios = <0xaf 0x01 0x01>;
ranges;
clocks = <0x7b 0x20 0x7b 0x22>;
assigned-clocks = <0x7b 0x20 0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,usb-polarity = <0x00>;
xlnx,ip-name = "psu_usb";
xlnx,usb-reset-mode = <0x00>;
xlnx,usb-board-interface = "custom";
xlnx,tz-nonsecure = <0x01>;
pinctrl-names = "default";
pinctrl-0 = <0xb0>;
phy-names = "usb3-phy";
phys = <0x6a 0x02 0x04 0x00 0x02>;
phandle = <0x74>;
usb@fe200000 {
compatible = "snps,dwc3";
status = "okay";
reg = <0x00 0xfe200000 0x00 0x40000>;
interrupt-parent = <0x0e>;
interrupt-names = "host\\0peripheral\\0otg\\0wakeup";
interrupts = <0x00 0x41 0x04 0x00 0x41 0x04 0x00 0x45 0x04 0x00 0x4b 0x04>;
clock-names = "ref";
snps,quirk-frame-length-adjustment = <0x20>;
snps,resume-hs-terminations;
clocks = <0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,ip-name = "psu_usb_xhci";
xlnx,enable-superspeed = <0x01>;
xlnx,usb-board-interface = "custom";
dr_mode = "host";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
phandle = <0x75>;
};
};
Test Procedure
Connect the USB 3.0/2.0 pendrive to USB 3.0 capable board and see it getting detected in /dev/sd<x>.
Expected Output
Once Linux boots the below highlighted prints should be visible when we connect the mass storage device
84943.023896] usb 2-1: new SuperSpeed USB device number 4 using xhci-hcd
[84943.044949] usb 2-1: New USB device found, idVendor=0781, idProduct=5581
[84943.051579] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[84943.058695] usb 2-1: Product: SanDisk Ultra
[84943.062858] usb 2-1: Manufacturer: SanDisk
[84943.066939] usb 2-1: SerialNumber: A20037A3AD063355
[84943.072653] usb-storage 2-1:1.0: USB Mass Storage device detected
[84943.078836] scsi host1: usb-storage 2-1:1.0
[84944.080804] scsi 1:0:0:0: Direct-Access SanDisk SanDisk Ultra PMAP PQ: 0 ANSI: 6
[84944.089531] sd 1:0:0:0: [sda] 30283008 512-byte logical blocks: (15.5 GB/14.4 GiB)
[84944.097708] sd 1:0:0:0: [sda] Write Protect is off
[84944.103904] sd 1:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[84944.309725] sda:
[84944.312888] sd 1:0:0:0: [sda] Attached SCSI removable disk
Performance
When Mass Storage device is connected
Device used :
USB 3.0 : HP USB 3.0 16 GB pendrive (idVendor=03f0, idProduct=4840)
USB 3.0 - UASP capable drive - Transcend Storjet 128GB
USB 2.0 : Sandisk Cruzer Blade USB 2.0 8 GB Pendrive (idVendor=0781, idProduct=5567)
Using HDPARM tool
Mode | Speed |
USB 3.0 (Super Speed) | 128 MB/sec |
USB 3.0 (UASP capable) | 327.10 MB/sec |
USB 2.0 (High Speed) | 25.48 MB/sec |
Note : Above results may vary from device to device
When Ethernet device is connected
Device used :
USB 3.0/2.0 : Xilinx ZynqMP RNDIS/Ethernet Gadget
Using Iperf tool (TCP)
Mode | Speed |
USB 3.0 (Super Speed) | 761.6 Mbits/sec |
USB 2.0 (High Speed) | 467.2 Mbits/sec |
Using Iperf tool (UDP)
Mode | Speed |
USB 3.0 (Super Speed) | 761.6 Mbits/sec |
USB 2.0 (High Speed) | 467.2 Mbits/sec |
Note : The above results are taken with LPM mode disabled
Peripheral Mode
ZCU102 jumper settings for Peripheral mode
J7 - OFF
J113 - 1-2
J110 - 1-2
J109- No jumper
Please refer the image below for jumper settings required for peripheral mode on ZCU102 board
USB 3.0 peripheral mode setup snapshot
This document only explains the USB 3.0 peripheral mode configurations for MASS STORAGE gadget or ETHERNET Gadget profiles.
Mass Storage
Kernel Configuration
Device Drivers-------->
USB support
<*> USB Gadget Support
<M> USB Gadget Drivers
<M> Gadget Filesystem
<M> Mass Storage Gadget
File systems --->
Pseudo filesystems --->
{M} Userspace-driven configuration filesystem
By enabling the above we need to see the below mentioned Kconfig parameter enabled
CONFIG_CONFIGFS_FS=y
CONFIG_USB_MASS_STORAGE=m
Please find the required .ko files in the paths mentioned below:
linux-xlnx/drivers/usb/gadget/legacy/g_mass_storage.ko
Devicetree :
Example Device tree node:
usb@ff9d0000 {
#address-cells = <0x02>;
#size-cells = <0x02>;
status = "okay";
compatible = "xlnx,zynqmp-dwc3";
reg = <0x00 0xff9d0000 0x00 0x100>;
clock-names = "bus_clk\\0ref_clk";
power-domains = <0x84 0x16>;
resets = <0x03 0x3b 0x03 0x3d 0x03 0x3f>;
reset-names = "usb_crst\\0usb_hibrst\\0usb_apbrst";
reset-gpios = <0xaf 0x01 0x01>;
ranges;
clocks = <0x7b 0x20 0x7b 0x22>;
assigned-clocks = <0x7b 0x20 0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,usb-polarity = <0x00>;
xlnx,ip-name = "psu_usb";
xlnx,usb-reset-mode = <0x00>;
xlnx,usb-board-interface = "custom";
xlnx,tz-nonsecure = <0x01>;
pinctrl-names = "default";
pinctrl-0 = <0xb0>;
phy-names = "usb3-phy";
phys = <0x6a 0x02 0x04 0x00 0x02>;
phandle = <0x74>;
usb@fe200000 {
compatible = "snps,dwc3";
status = "okay";
reg = <0x00 0xfe200000 0x00 0x40000>;
interrupt-parent = <0x0e>;
interrupt-names = "host\\0peripheral\\0otg\\0wakeup";
interrupts = <0x00 0x41 0x04 0x00 0x41 0x04 0x00 0x45 0x04 0x00 0x4b 0x04>;
clock-names = "ref";
snps,quirk-frame-length-adjustment = <0x20>;
snps,resume-hs-terminations;
clocks = <0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,ip-name = "psu_usb_xhci";
xlnx,enable-superspeed = <0x01>;
xlnx,usb-board-interface = "custom";
dr_mode = "peripheral";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
phandle = <0x75>;
};
};
Performance
Using HDPARM tool (Linux Host)
Link Power Management (LPM) mode Enable
Mode | Speed |
USB 3.0 (Super Speed) | 127.18 MB/sec |
USB 2.0 (High Speed) | 38.82 MB/sec |
Link Power Management (LPM) mode Disable
Mode | Speed |
USB 3.0 (Super Speed) | 237 MB/sec |
USB 2.0 (High Speed) | 38.47 MB/sec |
Testing Procedure
Please use the below settings for configuring USB as MASS STORAGE profile in device mode:
dd if=/dev/zero of=/tmp/mydev count=256 bs=1M
insmod g_mass_storage.ko file=/tmp/mydev removable=1 stall=1 iSerialNumber=7ABC7ABC7ABC7ABC7ABC7ABC
Testing the mass storage functionality by connecting the board to host using the below steps:
Connect the cable from board to windows host machine
Format the mass storage device that got detected in windows
The windows screen shot when we the device gets detected should be as below
The board will be detected as mass storage drive with size 256 MB.
Copy some files into the mass storage drive, remove the cable, and then reconnect it. We should be able to see the files that we copied into the drive.
Ethernet Gadget
Kernel Configuration
For the xilinx-v2016.2 and prior tags, apply the following patch.
USB support----->
<*> USB Gadget Support
<M> USB Gadget Drivers
<M> Gadget Filesystem
<M> Ethernet Gadget (with CDC Ethernet support)
[*] RNDIS support
File systems --->
Pseudo filesystems --->
{M} Userspace-driven configuration filesystemBy enabling the above we need to see the below mentioned Kconfig parameter enabled
CONFIG_CONFIGFS_FS=y
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
Please find the required .ko files in the paths mentioned below:
linux-xlnx/drivers/usb/gadget/function/g_ether.ko
linux-xlnx/drivers/usb/gadget/function/usb_f_rndis.ko
Devicetree
usb@ff9d0000 {
#address-cells = <0x02>;
#size-cells = <0x02>;
status = "okay";
compatible = "xlnx,zynqmp-dwc3";
reg = <0x00 0xff9d0000 0x00 0x100>;
clock-names = "bus_clk\\0ref_clk";
power-domains = <0x84 0x16>;
resets = <0x03 0x3b 0x03 0x3d 0x03 0x3f>;
reset-names = "usb_crst\\0usb_hibrst\\0usb_apbrst";
reset-gpios = <0xaf 0x01 0x01>;
ranges;
clocks = <0x7b 0x20 0x7b 0x22>;
assigned-clocks = <0x7b 0x20 0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,usb-polarity = <0x00>;
xlnx,ip-name = "psu_usb";
xlnx,usb-reset-mode = <0x00>;
xlnx,usb-board-interface = "custom";
xlnx,tz-nonsecure = <0x01>;
pinctrl-names = "default";
pinctrl-0 = <0xb0>;
phy-names = "usb3-phy";
phys = <0x6a 0x02 0x04 0x00 0x02>;
phandle = <0x74>;
usb@fe200000 {
compatible = "snps,dwc3";
status = "okay";
reg = <0x00 0xfe200000 0x00 0x40000>;
interrupt-parent = <0x0e>;
interrupt-names = "host\\0peripheral\\0otg\\0wakeup";
interrupts = <0x00 0x41 0x04 0x00 0x41 0x04 0x00 0x45 0x04 0x00 0x4b 0x04>;
clock-names = "ref";
snps,quirk-frame-length-adjustment = <0x20>;
snps,resume-hs-terminations;
clocks = <0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,ip-name = "psu_usb_xhci";
xlnx,enable-superspeed = <0x01>;
xlnx,usb-board-interface = "custom";
dr_mode = "peripheral";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
phandle = <0x75>;
};
};
Performance
Iperf tool (TCP)
Mode | Speed |
USB 3.0 (Super Speed) | 761.6 Mbits/sec |
USB 2.0 (High Speed) | 467.2 Mbits/sec |
Iperf tool (UDP)
Mode | Speed |
USB 3.0 (Super Speed) | 761.6 Mbits/sec |
USB 2.0 (High Speed) | 467.2 Mbits/sec |
Testing Procedure
Please use the below settings for configuring USB as an ETHERNET gadget profile in device mode:
insmod g_ether.ko
insmod usb_f_rndis.ko
mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g1
cd g1
echo "64" > bMaxPacketSize0
echo "0x200" > bcdUSB
echo "0x100" > bcdDevice
echo "0x03FD" > idVendor
echo "0x0502" > idProduct
mkdir configs/c1.1
mkdir functions/rndis.rn0
ln -s functions/rndis.rn0/ configs/c1.1/
echo "fe200000.dwc3" > UDC
ifconfig usb0 10.10.70.1
ifconfig usb0 up
Testing the ethernet gadget by connecting to linux/windows machine:
Connect the cable from board to windows/linux host machine
Set the ipaddress on device side
systest# ifconfig usb0 192.168.1.200Set the ipaddress on host side
ping host address from device side and the result should be as below mentioned
ping <host address>
Expected Output:
USB Attached SCSI Protocol(UASP)
Limitation
TCM MODULE USED FOR UASP does not support ATA_12 commands. so user needs to change VID and PID in file drivers/usb/gadget/legacy/tcm_usb_gadget.c as below
#define UAS_VENDOR_ID 0x0bc2
#define UAS_PRODUCT_ID 0xa013
Kernel Configuration
Device Drivers --->
<*> Generic Target Core Mod (TCM) and ConfigFS Infrastructure --->
--- Generic Target Core Mod (TCM) and ConfigFS Infrastructure
<*> TCM/FILEIO Subsystem Plugin for Linux/VFS
<*> TCM/pSCSI Subsystem Plugin for Linux/SCSI
<*> TCM/USER Subsystem Plugin for Linux
<*> TCM Virtual SAS target and Linux/SCSI LDD fabric loopback module
<*> Linux-iSCSI.org iSCSI Target Mode Stack
[*] USB support --->
<*> USB Gadget Support
<*> USB functions configurable through configfs
[*] USB Gadget Target Fabric
<M> USB Gadget Target Fabric Module
KCONFIG options for UASP profile
CONFIG_TARGET_CORE=y
CONFIG_TCM_FILEIO=y
CONFIG_USB_GADGET=y
CONFIG_USB_LIBCOMPOSITE=y
CONFIG_USB_F_TCM=y
CONFIG_USB_GADGET_TARGET=y
CONFIG_CONFIGFS_FS=y
Devicetree
usb@ff9d0000 {
#address-cells = <0x02>;
#size-cells = <0x02>;
status = "okay";
compatible = "xlnx,zynqmp-dwc3";
reg = <0x00 0xff9d0000 0x00 0x100>;
clock-names = "bus_clk\\0ref_clk";
power-domains = <0x84 0x16>;
resets = <0x03 0x3b 0x03 0x3d 0x03 0x3f>;
reset-names = "usb_crst\\0usb_hibrst\\0usb_apbrst";
reset-gpios = <0xaf 0x01 0x01>;
ranges;
clocks = <0x7b 0x20 0x7b 0x22>;
assigned-clocks = <0x7b 0x20 0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,usb-polarity = <0x00>;
xlnx,ip-name = "psu_usb";
xlnx,usb-reset-mode = <0x00>;
xlnx,usb-board-interface = "custom";
xlnx,tz-nonsecure = <0x01>;
pinctrl-names = "default";
pinctrl-0 = <0xb0>;
phy-names = "usb3-phy";
phys = <0x6a 0x02 0x04 0x00 0x02>;
phandle = <0x74>;
usb@fe200000 {
compatible = "snps,dwc3";
status = "okay";
reg = <0x00 0xfe200000 0x00 0x40000>;
interrupt-parent = <0x0e>;
interrupt-names = "host\\0peripheral\\0otg\\0wakeup";
interrupts = <0x00 0x41 0x04 0x00 0x41 0x04 0x00 0x45 0x04 0x00 0x4b 0x04>;
clock-names = "ref";
snps,quirk-frame-length-adjustment = <0x20>;
snps,resume-hs-terminations;
clocks = <0x7b 0x22>;
xlnx,is-cache-coherent = <0x00>;
xlnx,ip-name = "psu_usb_xhci";
xlnx,enable-superspeed = <0x01>;
xlnx,usb-board-interface = "custom";
dr_mode = "peripheral";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
phandle = <0x75>;
};
};
Example Device tree node:
&dwc3_0 {
status = "okay";
dr_mode = "peripheral";
}
Performance
HDPARM Tool (UBUNTU Host)
Link Power Management (LPM) mode | Result |
Enabled | 367.77 MB/sec |
Disabled | 381.42 MB/sec |
Test procedure
Connect the USB 3.0 cable to linux PC and perform the steps given below on the device side
Mount the configfs
mount a -t configfs /sys/kernel/config
Create a memory that will be assigned to gadget (here creating memory of 750MB)
mkdir /root
dd if=/dev/zero of=/root/file.bin bs=10M count=75
Format the memory that just has been created
mkdosfs -v /root/file.bin -n ramfs
Assign memory to gadget module
mkdir -p /sys/kernel/config/target/core/fileio_0/fileio
echo "fd_dev_name=/root/file.bin,fd_dev_size=734003200" > /sys/kernel/config/target/core/fileio_0/fileio/control
echo 1 > /sys/kernel/config/target/core/fileio_0/fileio/enable
mkdir -p /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1
mkdir /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1/lun/lun_0
echo naa.6001405c3214b06a > /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1/nexus
ln -s /sys/kernel/config/target/core/fileio_0/fileio /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1/lun/lun_0/virtual_scsi_port
Change max busrt to get maximum performance
echo 15 > /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1/maxburst
Connect device to Host
echo 1 > /sys/kernel/config/target/usb_gadget/naa.6001405c3214b06a/tpgt_1/enable
UbuntuOn performing the steps given above, below prints should be shown on host side on typing "dmesg"
© 2025 Advanced Micro Devices, Inc. Privacy Policy