USB Host/OTG Mode on Zynq7 with Xilinx Petalinux 2020.1

Getting USB host mode to work on an old Zynq is not straight forward. The documentation provided by Xilinx in their Wiki does not work with any recent Vivado/Petalinux version, and at best does nothing. At worst, you end up with a broken petalinux kernel build which send you down a rabbit hole of error messages unrelated to actually getting the Zynq’s USB interface to work.

So, here is how a zynq’s USB0 interface can be configured to support both/either host and OTG mode.

Adjust your kernel’s configuration:

petalinux-config -c kernel

Enable the following kernel features:

#Mandatory for Functionality
CONFIG_USB=y
CONFIG_USB_ULPI_BUS=y
CONFIG_USB_CONN_GPIO=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_DEFAULT_PERSIST=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_PCI=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_OF=y
CONFIG_USB_CHIPIDEA_PCI=y
CONFIG_USB_PHY=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_AM335X_CONTROL_USB=y
CONFIG_AM335X_PHY_USB=y
CONFIG_USB_GPIO_VBUS=y
CONFIG_USB_ULPI=y
CONFIG_USB_ULPI_VIEWPORT=y
#Choose either host mode:
CONFIG_USB_CHIPIDEA_HOST=y
#or device mode:
CONFIG_USB_CHIPIDEA_UDC=y

Remember to add USB device support functionality for the respective types of devices you want to attach:

#common USB device support
CONFIG_USB_HID=y
CONFIG_USB_ACM=y
CONFIG_USB_PRINTER=y
CONFIG_USB_WDM=y
CONFIG_USB_TMC=y
CONFIG_USB_STORAGE=y
#e.g. to enable support for a Zynq MPSoC's USB-2-UART Bridge
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_CP210X=y
#to enable usb camera/webcam support, add this
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
CONFIG_USB_GSPCA=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_ADV7604=y

These changes produce a kernel that can in theory support USB host/OTG mode, and communicate with attached devices and hubs. However, the kernel by default does not know where exactly the phy is in the system. Also Xilinx kindly disabled both of the zynq’s USB interfaces in their default device tree. Hence, next we need append our phy’s definition to the device tree, the petalinux way.

Add USB Phy to Kernel device tree:

Petalinux builds the actual kernel device tree from a set of custom device tree definition templates spread across your petalinux project root. Most of them are contributed by the petalinux BSP you are using, but others segments are provided by the kernel itself and you can hook in your own. Petalinux will eventually regenerate most of these files, and discard changes that you may make there.

Hence, we will place our custom device tree defintitions in

<petalinux-project-root>/project-spec/meta-user/recipes<br>-bsp/device-tree/files/system-user.dtsi

By default, the content of this file only has an include directive:

/include/ "system-conf.dtsi"
/ {

We will add our phy instantiation, and you can add more as necessary for any other devices you might have to include here. In my case, the file as a whole looks like this:

/include/ "system-conf.dtsi"
/{
 usb_phy0: usb_phy@0 {
  compatible = "ulpi-phy";
  #phy-cells = <0>;
  reg = <0xe0002000 0x1000>;
  view-port = <0x0170>;
  drv-vbus;
 };
};
&usb0 {
 dr_mode = "host";
 usb-phy = <&usb_phy0>;
};

Build and deploy. Have fun.