USB boot and recovery

Carambola2/Centipede/Lima/Rambutan boot loader (Caraboot/U-Boot) has USB boot/recovery functionality starting from version 2.0. Boot loader supports reading files from USB storage formatted with FAT32 file system and using them to boot Linux image or write to internal flash memory.

How USB boot/recovery works?

By default U-Boot will try to boot from USB storage only if 'USB boot button' is pressed for 3 seconds after system power up or reset.

Module USB boot GPIO USB boot button on devboard
Carambola2 GPIO11 S1
Centipede GPIO11 No button present
Lima GPIO16 S1
Rambutan GPIO18 S2

After boot loader detects that USB boot is requested, it will find all USB storage devices and start searching for files named: "8dev_uimage.bin" (boot image) and "8dev_recovery.bin"(recovery image). Recovery image has priority over boot image – if both images are present, boot loader will do recovery. Search for files is done via USB storage devices (as they enumerated) and over partitions in each device (up to 15 partitions). Full device file system with no partition table is also supported.

Example: You have USB hub with SD card reader connected to module. There is SD card in hub's socket and flash drive connected to hub. SD card contains single FAT32 file system (no partition table), and have file "8dev_recovery.bin" in root folder. USB drive have two partitions: first – ext4 partition, second FAT32 partition containing "8dev_uimage.bin" file in root folder. Let's say USB drive enumerated as device0 and SD card as device1. U-Boot will try search boot files as follows:

  1. Check if USB drive is full device partition – fails as is has partition table
  2. Check first partition – fails as ext4 is not supported
  3. Check second partition – succeeds, finds boot image and boots it.

SD card will not be checked, in this case. If USB flash stick is removed, then recovery from SD card would start after reboot.

If U-Boot does not find boot files in a USB storage or no storage is connected, it will proceed to boot from internal flash memory as usual.

When booting from USB, standard OpenWRT sysupgrade image may not work properly, since it uses internal flash memory for its root file system. It is recommended to use kernel image that has rootfs included in initramfs or mounts external partition as root file system.

When recovery image is found, it is written to flash memory at offset that depends on module's memory layout.

Module Recovery image offset on flash Maximum size of image
Carambola2 0x50000 16384000 bytes (0xFA0000)
Centipede 0x50000 16384000 bytes (0xFA0000)
Lima 0xc0000 Dynamically detected flash size - 0xc0000 (for 32MB flash - 32768000 bytes (0x1F40000))
Rambutan 0x600000 (start of ubi partition; configurable by mtdparts variable) 122 MB (0x07a00000)

After flashing boot loader waits 10 seconds (remove USB device with recovery image to avoid flashing again) and reboots.

How to boot from USB?

  1. Get (compile) Linux image (in U-Boot uImage format), suitable for USB booting.
  2. Get USB storage device formatted with FAT32 filesytem.
  3. Copy image to USB storage with filename "8dev_uimage.bin".
  4. Connect USB device to Carambola2.
  5. Power on (or reset) board and while holding USB boot button and hold it for 3 seconds.

How to do firmware recovery using USB flash?

  1. Get (compile) Linux image (in U-Boot uImage format) eg. sysupgrade image from repository.
  2. Get USB storage device formatted with FAT32 file sytem.
  3. Copy image to USB storage with filename "8dev_recovery.bin".
  4. Connect USB device to Carambola2.
  5. Power on (or reset) board and while holding USB boot button and hold it for 3 seconds.

How to configure boot loader's USB boot functionality?

USB boot functionality can be configured to suit specific needs, using U-Boot environment variables. More info on using U-Boot environment.

usbboot <mode> - boot mode
(if variable does not exist will use 'gpio' mode)
  usbboot=force - always boot from USB regardless from GPIO value
  usbboot=never - never boot from USB regardless from GPIO value
  usbboot=gpio  - boot from USB according to GPIO value (default)
bootfile="filename" - file name for booting. Can include directories eg. "boot/vmlinux.uimage"
(if variable does not exist “8dev_uimage.bin” default file name will be used.)

recoveryfile="filename" -  file name for recovery.
(if variable does not exist “8dev_recovery.bin” default file name will be used.)

bootdev=<device:partition> - device for booting, used to boot from specific device and partition, skipping partition scan
(if variable does not exist will use automatic scan)
             "device" - is USB device number (starting from 0
             "partition" - partition number (0 - full device) 1-16 (normal partitions)

Examples:

  • You want always boot from specific USB device regardless of 'USB boot button' state and use custom filename.

Enter these commands to U-Boot console:

setenv usbboot force
setenv bootfile special_image.bin
setenv recoveryfile special_recovery.bin
setenv bootdev 1:2
saveenv

With this config U-Boot will only check second USB storage device's second partition (devices are counted from 0, so first is 0, second is 1, partitions are counted form 1). If file “special_recovery.bin” exists, recovery will start. If file “special_image.bin” exists, boot loader will boot it. If these files are not found in this partition, boot loader will boot from SPI flash.

  • You do not need USB boot functionality and use 'USB boot button' for other purpose that somehow interferes.

Enter these commands to U-Boot console:

setenv usbboot never
saveenv

Using U-Boot environment

U-Boot allows to save its configuration to a special partition called U-Boot environment. When using U-Boot console for the first time, note that it is not standard Bash shell, it lacks many functions but has power to brick your device – be very careful. For example U-Boot shell has no command history with UP key, HOME and END keys do not work (using them adds unwanted symbols to your command use CTRL+C to start over), pressing ENTER button on an empty line may repeat your last command.

To see all configuration variables type into U-Boot console:

printenv

To add new, or change existing variable type:

setenv variable_name variable_value

Note that when printing U-Boot uses equality sign: 'bootdelay=1', but when setting variable you must not use it. Use space to separate variable from its value instead. When you set variable it is only saved in memory. Save variables to flash memory using:

saveenv

You only need to saveenv once for all variables you changed.

Custom GPIO configuration

Carambola2/Centipede/Lima U-Boot since firmware version 2.0, has an option to configure custom GPIO settings. It allows to use module with different motherboards.

Three environment variables controls GPIO settings:

  • "gpio_config" allows direct manipulation of AR9331 GPIO registers,
  • “led_config” - allows assigning GPIOs as LEDs,
  • “button_config” - allows assigning GPIOs as buttons.

More information about using U-Boot environment.

“gpio_config” variable contains a list of register addresses that need to be changed, together with two bit masks showing which bits need to be set or cleared. Address range is restricted to [0x18040000–0x18040044] on Carambola2/Centipede and to [0x18040000–0x18040008] [0x18040014–0x18040070] on Lima. For more information on GPIO registers refer to AR9331 data sheet.

gpio_config=ADDR:SET_MASK:CLEAR_MASK/ADDR2:SET_MASK2:CLEAR_MASK2/......(and so on)

  ADDR - register address (in hex)
  SET_MASK, CLEAR_MASK - bits to set/clear in register (in hex)

LED and button configuration are stored in C structure:

typedef struct gpio_led_desc {
  int id;
  int bit;    //GPIO bit
  int polarity; //1 - high active; 0 - low active
  int disable; //1 - disable led, 0 - enable
};

To use LEDs and buttons values different from default, override them with environment variables:

led_config=ID:GPIO:POLARITY:DISABLE/..(and so on) button_config=ID:GPIO:POLARITY:DISABLE/..(and so on)

ID - LED/Button ID, it may have predetermined meaning (eg. button ID1= USB boot mode jumper) (number in decimal)
GPIO - which GPIO is used (number in decimal)
POLARITY - active state (eg. 1= LED on/BUTTON pressed when GPIO is high) (0 or 1)
DISABLE - do not use LED/BUTTON when enabled by default (0 or 1)

Default gpio/button config:

struct gpio_led_desc leds[]={
  {// WLAN LED
    .id=0, .bit=0, .polarity=0, .disable=0},
  {// ETH0_LED
   .id=1, .bit=13,  .polarity=1, .disable=0},
  {// ETH1_LED
    .id=2, .bit=14, .polarity=1, .disable=0},
  {// Nothing
    .id=3, .bit=0, .polarity=0, .disable=1},
    {// Nothing
    .id=4, .bit=0, .polarity=0, .disable=1}
};

struct gpio_led_desc buttons[]={
  {// USB Boot
    .id=0, .bit=11,  .polarity=0, .disable=0},
  {// Nothing
    .id=1,.bit=0, polarity=0, .disable=1},
  {// Nothing
    .id=2,.bit=0, polarity=0, .disable=1},
  {// Nothing
    .id=3,.bit=0, polarity=0, .disable=1},
  {// Nothing
    .id=4,.bit=0, polarity=0, .disable=1},
};

Button ID=0 is reserved for USB boot selection, other button IDs do not have purpose yet. All enabled LED's are used in these boot indications:

  1. Blink LEDs for 100ms early in boot (to show that U-Boot is functional)
  2. Blink LEDs constantly if booting image from SPI flash failed.

Examples:

  • You want to change USB boot button to GPIO 21

Since GPIO21 is configured as an input by default there is no need to change gpio_config variable, only button_config needs to be adjusted.

setenv button_config 0:21:0:0
saveenv

Explanation of parameter “0:21:0:0”: id=0 – USB boot button always has ID=0 gpio=21 – desired GPIO line polarity =0 – button will be active when GPIO input is low (depends on how button is connected) disable=0 – enables button

  • You want to turn on custom LEDs (GPIO20,GPIO22) during U-Boot stage

To turn on LEDs with GPIOs we need to configure them as outputs and set value to 1 (assuming LED's positive terminal is connected to GPIO). Output enable register is 0x18040000, where we want to set bit 20 and bit 22 = 0x500000. Then we want to set same bits in output value register (0x18040008).

setenv gpio_config 0x18040000:0x500000:0/0x18040008:0x500000:0
saveenv

There is no need to set led_config variable since we wanted only to light them up, not use them in any indications.