secubox-deb/docs/eye-remote/uboot-bootcmd.md

13 KiB

ESPRESSObin U-Boot Boot Commands — Eye Remote

Overview

This guide covers configuring ESPRESSObin U-Boot to boot from Eye Remote mass storage (active slot) or TFTP (shadow slot). The Eye Remote Pi Zero W provides USB OTG connectivity and network access for dual-boot management.

Key network setup:

  • Eye Remote IP: 10.55.0.2
  • ESPRESSObin IP: 10.55.0.1
  • Network: 10.55.0.0/30 (routable via USB OTG ECM)

Prerequisites

  1. Eye Remote Pi Zero W

    • Running v2.1.0 or later
    • USB OTG ECM mode enabled
    • DHCP server active on 10.55.0.2
  2. ESPRESSObin

    • U-Boot installed in SPI NOR flash or eMMC
    • Serial console access (TTL UART 115200 baud)
    • USB OTG micro-AB port (supports OTG mode)
  3. Connectivity

    • USB OTG cable (Pi Zero ↔ ESPRESSObin USB OTG port)
    • Serial console cable (UART3, pins TXD/RXD/GND)
    • Optional: Ethernet for TFTP boot (fallback)
  4. Host Files

    • Kernel: Image (Linux ARM64 binary)
    • DTB: armada-3720-espressobin.dtb (device tree)
    • Present on Eye Remote mass storage or TFTP server

Power Ordering — Two Approaches

Safest method — power devices independently:

  1. Connect USB OTG cable (Pi Zero ↔ ESPRESSObin OTG port)

    • Pi Zero: micro-AB port
    • ESPRESSObin: OTG micro-B port
    • Cable acts as data link only
  2. Power Pi Zero separately (5V via micro-USB)

    • Pi Zero boots → enables USB host (via g_ether overlay)
    • Exports mass storage LUN
  3. Power ESPRESSObin independently (external 5V)

    • Detects USB device (mass storage LUN) after U-Boot starts
    • No risk of back-power or brown-out

Option B: Retry Loop in U-Boot

For scenarios where ESPRESSObin must power from USB OTG:

# In U-Boot console (press Enter during boot)
setenv bootcmd 'usb start; if usb storage; then fatload usb 0 ${kernel_addr_r} Image && fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}; fi; false'
saveenv
reset

U-Boot will:

  1. Power on via USB OTG
  2. Wait ~2s for Pi Zero to stabilize
  3. Attempt usb startusb storage
  4. If USB device appears → load kernel/DTB → boot
  5. If timeout → retry or fall back to TFTP

Mass Storage Boot (Active Slot)

Quick Check: USB Enumeration

Enter U-Boot console and verify USB device is detected:

ESPRESSObin=> usb start
Starting USB Controller
USB XHCI 1.00

ESPRESSObin=> usb storage
  Device 0: Vendor: QEMU     Rev: 2.5+ Type: Removable Hard Disk
            Capacity: 1024 MB = 1 GB (2097152 x 512)

ESPRESSObin=> usb tree
USB device tree:
  1  XHCI 1.00
     | 1 Hub: QEMU QEMU USB Storage Controller (product id 0x0070)
     | | 1 Mass Storage: QEMU USB Storage (000010000000000000000000)

Boot Command: Active Slot

Set boot command to load kernel and DTB from mass storage:

ESPRESSObin=> setenv bootcmd 'usb start; usb storage; fatload usb 0 ${kernel_addr_r} Image; fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb; booti ${kernel_addr_r} - ${fdt_addr_r}'

ESPRESSObin=> setenv bootargs 'root=/dev/mmcblk0p2 rw rootwait console=ttyMV0,115200'

ESPRESSObin=> saveenv
Saving Environment to SPI Flash... OK

Explanation:

  • usb start — Initialize USB controller
  • usb storage — Detect USB storage device
  • fatload usb 0 ${kernel_addr_r} Image — Load kernel from USB LUN 0
  • fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb — Load DTB
  • booti ${kernel_addr_r} - ${fdt_addr_r} — Boot with kernel at kernel_addr_r, no ramdisk, DTB at fdt_addr_r
  • saveenv — Persist to SPI NOR flash

Verify Boot Environment

List current environment variables:

ESPRESSObin=> printenv bootcmd
bootcmd=usb start; usb storage; fatload usb 0 ${kernel_addr_r} Image; fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb; booti ${kernel_addr_r} - ${fdt_addr_r}

ESPRESSObin=> printenv kernel_addr_r
kernel_addr_r=0x2000000

ESPRESSObin=> printenv fdt_addr_r
fdt_addr_r=0x1f00000

ESPRESSObin=> printenv bootargs
bootargs=root=/dev/mmcblk0p2 rw rootwait console=ttyMV0,115200

TFTP Boot (Shadow Slot)

Prerequisite: TFTP Server

Set up TFTP on Eye Remote or a separate machine:

# Eye Remote (10.55.0.2) or host on 10.55.0.0/30 network
mkdir -p /srv/tftp
cp Image /srv/tftp/
cp armada-3720-espressobin.dtb /srv/tftp/

# Start dnsmasq or in.tftpd listening on 10.55.0.2:69
systemctl restart dnsmasq
# or
systemctl restart tftpd-hpa

Boot Command: Shadow Slot

Configure TFTP boot for failover scenarios:

ESPRESSObin=> setenv serverip 10.55.0.2

ESPRESSObin=> setenv bootcmd 'usb start; if usb storage; then fatload usb 0 ${kernel_addr_r} Image && fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}; else tftp ${kernel_addr_r} Image && tftp ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}; fi'

ESPRESSObin=> saveenv

Logic:

  1. Try USB mass storage boot (active slot)
  2. If USB fails or times out → TFTP boot (shadow slot)
  3. Either way, boot the kernel + DTB combination

Direct TFTP Boot (No Fallback)

For testing the TFTP shadow channel in isolation:

ESPRESSObin=> setenv serverip 10.55.0.2

ESPRESSObin=> tftp ${kernel_addr_r} Image
Using usb_ether device
TFTP from server 10.55.0.2; our IP address is 10.55.0.1
Filename 'Image'.
Load address: 0x2000000
Loading: #################################################################
         1234 Bytes/s
done
Bytes transferred = 16384000 (fa80000 in hex)

ESPRESSObin=> tftp ${fdt_addr_r} armada-3720-espressobin.dtb
Using usb_ether device
TFTP from server 10.55.0.2; our IP address is 10.55.0.1
Filename 'armada-3720-espressobin.dtb'.
Load address: 0x1f00000
Loading: #
done
Bytes transferred = 32768 (8000 in hex)

ESPRESSObin=> booti ${kernel_addr_r} - ${fdt_addr_r}

Workflow: Test Then Promote

Phase 1: Upload to TFTP (Shadow)

  1. Build new kernel and DTB on development machine
  2. Copy to TFTP server at /srv/tftp/
    scp Image root@10.55.0.2:/srv/tftp/
    scp armada-3720-espressobin.dtb root@10.55.0.2:/srv/tftp/
    

Phase 2: Test via TFTP (Shadow Boot)

  1. Interrupt U-Boot at prompt
  2. Clear USB first (in case old device present):
    ESPRESSObin=> usb reset
    
  3. Boot via TFTP:
    ESPRESSObin=> setenv serverip 10.55.0.2
    ESPRESSObin=> tftp ${kernel_addr_r} Image
    ESPRESSObin=> tftp ${fdt_addr_r} armada-3720-espressobin.dtb
    ESPRESSObin=> booti ${kernel_addr_r} - ${fdt_addr_r}
    

Phase 3: Verify Boot Success

Once kernel boots, verify via SSH:

ssh root@10.55.0.1
# Verify kernel version, modules, etc.
uname -a

Phase 4: Promote to Active Slot (USB Mass Storage)

Once TFTP boot is verified:

  1. Copy files to Eye Remote mass storage

    scp Image root@10.55.0.2:/mnt/usb/boot/
    scp armada-3720-espressobin.dtb root@10.55.0.2:/mnt/usb/boot/
    
  2. Update U-Boot bootcmd to use USB:

    ESPRESSObin=> setenv bootcmd 'usb start; usb storage; fatload usb 0 ${kernel_addr_r} Image; fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb; booti ${kernel_addr_r} - ${fdt_addr_r}'
    ESPRESSObin=> saveenv
    
  3. Reset and verify USB boot:

    ESPRESSObin=> reset
    

Troubleshooting

Issue: "No USB storage device(s) found"

Cause: Pi Zero not detected or not in host mode.

Diagnosis:

ESPRESSObin=> usb start
Starting USB Controller
USB XHCI 1.00

ESPRESSObin=> usb tree
USB device tree:
  1  XHCI 1.00
     1 Hub: QEMU QEMU USB Storage Controller (product id 0x0070)
     (nothing under hub — no device)

Solutions:

  1. Check Pi Zero power: Verify 5V applied to Pi Zero micro-USB port

    # On Pi Zero:
    vcgencmd get_throttled  # Should be 0x0 (no throttle)
    
  2. Check USB cable: Swap cable, verify all connections

    # On Pi Zero:
    lsusb
    # Should show usb_ethernet module loaded
    lsmod | grep g_ether
    
  3. Restart U-Boot retry loop: Reset both devices

    ESPRESSObin=> reset
    
  4. Check Eye Remote ECM driver: On Pi Zero, verify interface is up

    ip link show usb0
    # Should be "UP"
    

Issue: "Unable to read file Image"

Cause: File not found on mass storage, or incorrect filename.

Diagnosis:

ESPRESSObin=> usb storage
ESPRESSObin=> fatls usb 0
(no files listed, or different names)

Solutions:

  1. Verify file exists on Eye Remote:

    ls -lh /mnt/usb/boot/Image
    
  2. Check FAT filesystem:

    mount | grep usb0
    fsck.vfat -v /dev/sda1
    
  3. Verify filename case: U-Boot FAT driver is case-sensitive

    ESPRESSObin=> fatls usb 0
    # Should show "Image" (capital I)
    
  4. Recreate boot partition if corrupted:

    mkfs.vfat -F 32 /dev/sda1
    mkdir -p /mnt/usb/boot
    mount /dev/sda1 /mnt/usb/boot
    cp Image armada-3720-espressobin.dtb /mnt/usb/boot/
    umount /mnt/usb/boot
    

Issue: TFTP Timeout

Cause: Network unreachable, TFTP server down, or firewall blocking.

Diagnosis:

ESPRESSObin=> setenv serverip 10.55.0.2
ESPRESSObin=> tftp ${kernel_addr_r} Image
Using usb_ether device
TFTP from server 10.55.0.2; our IP address is 10.55.0.1
Filename 'Image'.
Load address: 0x2000000
Waiting for ethernet device... timeout!

Solutions:

  1. Verify network connectivity:

    # On Pi Zero or test host
    ping 10.55.0.1
    # Should succeed
    
  2. Check TFTP server is running:

    systemctl status dnsmasq  # or tftpd-hpa
    netstat -uln | grep :69   # TFTP port
    
  3. Verify firewall allows TFTP:

    ufw allow 69/udp
    # or nftables
    nft add rule inet filter input udp dport 69 accept
    
  4. Test TFTP connectivity manually:

    # On test host on 10.55.0.0/30 network
    echo "test" > /srv/tftp/test.txt
    tftp 10.55.0.2
    > get test.txt
    
  5. Set TFTP timeout in U-Boot:

    ESPRESSObin=> setenv netretry 5
    ESPRESSObin=> saveenv
    

Issue: Kernel Loads but Won't Boot

Symptoms: Files load successfully, but kernel crashes or hangs.

Diagnosis:

ESPRESSObin=> booti ${kernel_addr_r} - ${fdt_addr_r}
## Flattened Device Tree blob at 1f00000
## Kernel loaded from 0x02000000
## Loading Device Tree to 27f00000, end 27f08000 ... OK
## Booting using the fdt blob at 0x27f00000
(hangs here)

Solutions:

  1. Verify DTB matches kernel version:

    file armada-3720-espressobin.dtb
    # Should show "Device Tree Blob"
    
  2. Check kernel bootargs:

    ESPRESSObin=> printenv bootargs
    # Verify root= device exists
    
  3. Enable serial console on kernel side:

    ESPRESSObin=> setenv bootargs 'root=/dev/mmcblk0p2 rw rootwait console=ttyMV0,115200 earlyprintk'
    ESPRESSObin=> saveenv
    
  4. Rebuild kernel with proper config:

    # Ensure CONFIG_SERIAL_MVEBU_UART=y in kernel .config
    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
         mvebu_v7_defconfig
    

Environment Variable Reference

Variable Default Purpose
bootcmd varies Command executed at boot
bootargs varies Kernel boot arguments (root, console, etc.)
kernel_addr_r 0x2000000 DRAM address for kernel load
fdt_addr_r 0x1f00000 DRAM address for DTB load
ramdisk_addr_r varies DRAM address for ramdisk (if used)
serverip 10.55.0.2 TFTP server IP
ipaddr 10.55.0.1 ESPRESSObin IP (USB OTG)
netmask 255.255.255.252 Network mask for USB OTG link
netretry 1 TFTP retry count

To view all:

ESPRESSObin=> printenv

To save any change:

ESPRESSObin=> saveenv

See Also


Examples

Full Bootcmd with Fallback

Active slot (USB) with fallback to shadow slot (TFTP):

setenv bootcmd 'usb start; if usb storage; then echo "Booting from USB..."; fatload usb 0 ${kernel_addr_r} Image && fatload usb 0 ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}; else echo "USB boot failed, trying TFTP..."; tftp ${kernel_addr_r} Image && tftp ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}; fi'

setenv bootargs 'root=/dev/mmcblk0p2 rw rootwait console=ttyMV0,115200'

saveenv
reset

Development Iteration (TFTP Only)

For rapid kernel development, stay on TFTP:

setenv bootcmd 'usb reset; setenv serverip 10.55.0.2; tftp ${kernel_addr_r} Image && tftp ${fdt_addr_r} armada-3720-espressobin.dtb && booti ${kernel_addr_r} - ${fdt_addr_r}'

setenv bootargs 'root=/dev/mmcblk0p2 rw rootwait console=ttyMV0,115200 earlyprintk'

saveenv
reset

Author: CyberMind — Gérald Kerma License: Proprietary / ANSSI CSPN candidate Last Updated: 2024