LAN969x USB

1. SoC Resources

LAN969x SoC supports one instance of the Dual Role SuperSpeed DesignWare USB3 controller.

The current implementation supports only the host mode part of dual role

2. Kernel configurations

Following kernel config options should be enabled to use LAN969x USB in host mode:

3. Devicetree Configuration

To enable LAN969x USB, following configurations are required in device tree:

  • compatible string must be set to "microchip,lan966x-dwc3"

  • clocks property must be set to <&clks GCK_GATE_USB_DRD>

  • #address-cells must be set to 1.

  • #size-cells must be set to 1.

  • ranges property must be present (this is an empty address translation)

  • This node must have a child node that specifies the glue for the DWC3 controller:

    • compatible string must be set to = "snps,dwc3".

    • reg property must be set to <0x300000 0x80000>.

    • interrupts must be set to <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>

      Peripheral Shared Peripheral Interrupt CPU INTR

      USB Host

      112

      80

    • dr_mode property must be set to "host".

    • clocks property must be set to <&clks GCK_ID_USB_REFCLK>.

    • clock-names property must be set to "ref".

    • assigned-clocks property must be set to <&clks GCK_ID_USB_REFCLK>.

    • assigned-clock-rates property must be set to 60Mhz.

    • maximum-speed property must be set to "full-speed".

    • phy-names property must be set to "usb2-phy" and "usb3-phy"

3.2. Example

Following example shows how the LAN969x USB controller should be defined in DT:

dtsi file:

usb0: usb@300000 {
	compatible = "microchip,lan966x-dwc3";
	clocks = <&clks GCK_GATE_USB_DRD>;
	#address-cells = <1>; #size-cells = <1>;
	ranges;
	status = "disabled";

	usb0_dwc3: usb_dwc3@300000 {
		compatible = "snps,dwc3";
		reg = <0x300000 0x80000>;
		interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
		dr_mode = "host";
		clocks = <&clks GCK_ID_USB_REFCLK>;
		clock-names = "ref";
		assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
		assigned-clock-rates = <60000000>;
		maximum-speed = "full-speed";
		phy-names = "usb2-phy", "usb3-phy";
		status = "okay";
	};
};

dts file changes:

&gpio {
	usb_ulpi_pins: usb-ulpi-pins {
		pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
		"GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
		"GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
		function = "usb_ulpi";
	};

	usb_rst_pins: usb-rst-pins {
		pins = "GPIO_12";
		function = "usb2phy_rst";
	};

	usb_over_pins: usb-over-pins {
		pins = "GPIO_13";
		function = "usb_over_detect";
	};

	usb_power_pins: usb-power-pins {
		pins = "GPIO_1";
		function = "usb_power";
	};
};

&usb0 {
	status = "okay";
	pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
	pinctrl-names = "default";
};

4. UserSpace

You can verify that the driver is available by checking its mode setting is host, like this:

# cat /sys/kernel/debug/usb/300000.usb_dwc3/mode
host

4.1. Creating and mounting a USB Memory Stick using EXT4

Prepare a USB Memory Stick (/dev/sdx in the following example) with the following properties on a Linux Desktop:

  • Make a GTP partition table

    sudo parted -s /dev/sdx mktable gpt
  • Add one primary partition using the EXT4 filesystem that uses the total USB Memory Stick space.

    sudo parted -s /dev/sdx mkpart primary ext4 1024 100%
  • Format partition 1 (/dev/sdx1) with the ext4 formatter

    sudo mkfs.ext4 /dev/sdx1
  • Mount the partition on an empty folder

    mkdir mnt
    sudo mount /dev/sdx1 mnt
  • Copy a wellknown file to the mounted folder (a file we have built in this case):

    sudo cp /tftpboot/lan969x.itb mnt/
  • Sync and unmount the folder

    sync
    sudo umount mnt

Now insert the memory stick in the USB vertical USB port on the EVB-LAN9696-24port and check the logs:

# [  382.641801] usb 1-1: new high-speed USB device number 2 using xhci-hcd
[  382.790319] usb 1-1: New USB device found, idVendor=0781, idProduct=5406, bcdDevice= 2.00
[  382.795753] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  382.803050] usb 1-1: Product: U3 Cruzer Micro
[  382.807278] usb 1-1: Manufacturer: SanDisk
[  382.811348] usb 1-1: SerialNumber: 194253029D50FD3B
[  382.817444] usb-storage 1-1:1.0: USB Mass Storage device detected
[  382.822855] scsi host0: usb-storage 1-1:1.0
[  383.842201] scsi 0:0:0:0: Direct-Access     SanDisk  Cruzer           8.02 PQ: 0 ANSI: 0 CCS
[  383.848550] sd 0:0:0:0: [sda] Media removed, stopped polling
[  383.854874] sd 0:0:0:0: [sda] Attached SCSI removable disk

# ls /dev/sda*
/dev/sda

The log announces a new sda block device which is visible in the /dev folder, but what about the partition that we created?

Here you need to probe the new device for partition information:

# partprobe /dev/sda
[  405.656881] sd 0:0:0:0: [sda] 15704063 512-byte logical blocks: (8.04 gb/7.49 gib)
[  405.662434] sda: detected capacity change from 0 to 15704063
[  405.693476]  sda: sda1
[  405.720651]  sda: sda1

Partprobe informs the kernel about the partitions on device sda which in turn causes the kernel to create a new sda1 block device that represents the first (and only) partition on sda.

On Desktop Linux systems it is common to run the udev daemon that takes care of retrieving partition information and spawn process that will mount these partitions with specific user rights, but udev and its helpers are not always available on embedded systems.

Now you can mount the sda1 partition to access the file that was stored there:

# mount /dev/sda1 /mnt/
[  421.617746] EXT4-fs (sda1): mounted filesystem with ordered data mode. Quota mode: disabled.
# ls -l /mnt/
total 28K
drwxr-xr-x    3 root     root        4.0K Dec 12  2023 .
drwxr-xr-x   19 1001     1001        4.0K Sep 28  2023 ..
drwx------    2 root     root       16.0K Dec 12  2023 lost+found
-rw-r--r--    1 root     root        1.4K Dec 12  2023 main.rs
# cat /mnt/main.rs
use std::fs::File;
use std::io::Read;
... file listing continues...
#

You can now read and write to the folder as you please, and the changes will be stored in the first partition of the USB Memory Stick.

Remember to sync and unmount the device before unplugging it.

# sync
# umount /mnt/
[  897.689004] EXT4-fs (sda1): unmounting filesystem.
#

4.1.1. Using FAT32

You can also use the FAT32 filesystem instead of EXT4 as it is supported by default by the Windows Operating System.

Here is how to format a USB stick with a partition that provides FAT32 support.

  • Make a GTP partition table

    sudo parted -s /dev/sdx mktable gpt
  • Add one primary partition using the FAT32 filesystem that uses the total USB Memory Stick space.

    sudo parted -s /dev/sdx mkpart primary fat32 1024 100%
  • Format partition 1 (/dev/sdx1) with the fat formatter selecting the FAT32 variant:

    sudo mkfs.fat -F 32 /dev/sdx1

You can now use this USB stick to copy files to and from a Windows based PC.