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:

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:
- Run
make rpi_defconfig. This will select our board. - Using
make menuconfigenableCONFIG_APIconfigurable (or just addCONFIG_API=yto.configfile) - Run
makecommand. This should createu-boot.binfile 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.
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.
Issue was most likely with timing. Mdelay allow to mask some incorrect timing handling in the code.