Fixing USB detection with uboot on RPI

As part of my experiments with RPi/FreeBSD i decided to move FreeBSD completely to the USB token. Some of the pros:

  • Easy to mount on normal laptop if i need to fix something, backup, etc.
  • I have tonn of them πŸ™‚
  • I think that performance of the recent usb3 flash is better compared to typical SD. However need to verify that.
  • Possibility to use SSD/HDD via USB-Sata bridge

Cons:

  • RPi 1 does not support real usb boot, you still need to have SD Card to initiate boot process

How RPi 1 boots with FreeBSD:

RPi expects FAT partition on SD Card which contains some files to boot. This includes bootcode.bin (removed on RPi4), start*.elf (primary firmware, different versions, reads config.txt file), u-boot (specified as kernel=u-boot.bin in the config.txt) which loads ubldr (arm port of the loader(8)). UBLDR scanning for the UFS partition to load kernel and pass control to it. Diagram of the process provided below:

boot.png

As ubldr does not have hardware specific code it is relying on u-boot API to access the disks. And here problems starts – 2 of my 3 USB drives were showing

starting USB...
USB0:   Core Release: 2.80a
scanning bus 0 for devices... usb_new_device: Cannot read configuration, skipping device XXXX:XXXX

on boot. I decided to debug why it happens.

Debugging u-boot

First thing i decided to do is to build a latest u-boot for the RPI platform. To do this i been using official u-boot git – git://git.denx.de/u-boot.git. I was using docker container with Ubuntu 18.04 to avoid any build issues. You will have to install cpp-arm-linux-gnueabi, gcc-arm-linux-gnueabi and binutils-arm-linux-gnueabi packages. Next is to set cross-compiler using export CROSS_COMPILE=arm-linux-gnueabi- command.

In the u-boot folder we will need to configure u-boot for our board and usecase:

  1. Run make rpi_defconfig. This will select our board.
  2. Using make menuconfig enable CONFIG_API configurable (or just add CONFIG_API=y to .config file)
  3. Run make command. This should create u-boot.bin file which you could copy to the SD Card. I am recommending to use different name, e.g. uboot-new.bin, this would allow to revert to the previous loader. Change kernel line in the config.txt to point to the new u-boot.

At this point i got 2 news: good one that my u-boot is working and bad that it has 100% same USB issue. So i decided to debug it. You can enable USB debugging by adding #define DEBUG in the beginning of the common/usb.c file and re-compile u-boot. This would print a lot of debug lines on initial boot and we have a typical heisenbug after this stage – USB detection is fixed πŸ™‚ Okay, at least we know that this is a timing issue and probably debug output prevents it to happens.

After number of experiments i was able to get it working without debug. Here is a diff:

diff --git a/common/usb.c b/common/usb.c
index b70f614d24..121df520bc 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -1086,10 +1086,11 @@ int usb_select_config(struct usb_device *dev)
         * requests in the first microframe, the stick crashes. Wait about
         * one microframe duration here (1mS for USB 1.x , 125uS for USB 2.0).
         */
-       mdelay(1);
+       mdelay(300);

        /* only support for one config for now */
        err = usb_get_configuration_len(dev, 0);
+       mdelay(100);
        if (err >= 0) {
                tmpbuf = (unsigned char *)malloc_cache_aligned(err);
                if (!tmpbuf)
@@ -1107,6 +1108,7 @@ int usb_select_config(struct usb_device *dev)
        usb_parse_config(dev, tmpbuf, 0);
        free(tmpbuf);
        usb_set_maxpacket(dev);
+       mdelay(100);
        /*
         * we set the default configuration here
         * This seems premature. If the driver wants a different configuration

After all it detects USB device and now it is visible (and bootable!) in ubldr.

Bus usb@7e980000: scanning bus usb@7e980000 for devices... 4 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found

Ubldr will scan all devices and will try to boot from the first bootable ufs parition found. This way i was able to move all the files to the USB flash with only few files left on the SD.

Tagged , , ,

2 thoughts on “Fixing USB detection with uboot on RPI

  1. kavin's avatar kavin says:

    Hi Author,
    I am also facing the same issue. I am not using Rasberry pi.
    The same “heisenbug” scenario happened for me also. i.e with debug prints enabled my USB 2.0 device enumerates properly.

    can you please explain why adding that 3 mdelay() functions helps in fixing this issue?

    even though USB enumerates with the above fix you posted, I am getting “WARN halted endpoints” printed multiple times. do you have any idea why does this happens?

    device# usb start
    starting USB…
    USB0: Register 2000140 NbrPorts 2
    Starting the controller
    USB XHCI 1.10
    scanning bus 0 for devices… WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    WARN halted endpoint
    2 USB Device(s) found
    device#

    Looking forward to your reply.

Leave a comment

Design a site like this with WordPress.com
Get started