[[PageOutline]]
= U-Boot Bootloader
Gateworks uses U-Boot (the Universal Boot Loader) as a primary bootloader for all current product families. In some cases U-Boot is used as the 'secondary program loader' as well as the 'primary program loader'.
The purpose of a bootloader is to load the Operating System (OS) and execute it. In terms of a Linux based OS this means loading the kernel image, device-tree blobs (optional), and initial ramdisk images (optional) into DRAM and executing the kernel with any necessary kernel arguments. Often this is done in an OS specific fashion via a U-Boot bootscript stored along-side the kernel Image.
== Features and Peripheral support
U-Boot has many features and peripheral support but it is not intended to be a full OS so some features do not work as well as they would on a Linux based OS for example. The intention of U-Boot is to provide enough support to load and execute the kernel therefore support for things like USB peripherals and high performance networking and I/O is not a priority and should not be expected.
Many features can be enabled by re-building and re-installing U-Boot. For more information on building U-Boot see the product specific BSP pages.
== Product Family specific notes
[=#malibu]
=== Malibu
The Marvell CN913x based Malibu product family boots via a BOOT ROM internal to the CN913x which loads ARM Trusted Firmware (ATF) which contains a U-Boot payload image. In this case initial SoC chip and DRAM configuration is done by components in the ARM Trusted firmware
see also [wiki:malibu/boot#u-boot]
[=#venice]
=== Venice
The NXP i.MX 8M !Mini/Nano/Plus based Venice product family boots via a BOOT ROM internal to the i.MX8M which loads U-Boot SPL (Secondary Program Loader) which then loads U-Boot proper. In this case initial SoC chip and DRAM configuration is done by U-Boot SPL.
see also [wiki:venice/boot]
[=#newport]
=== Newport
The Marvell CN803x based Newport product family boots via a BOOT ROM internal to the CN803 which loads Marvell's 'Board Disagnostics Kit' (BDK) (which we call the SPL) which in turn loads the ATF and U-Boot from a payload inside the ATF. In this case initial SoC chip and DRAM configuration is done by the Marvell BDK software.
see also [wiki:newport/boot#u-boot]
[=#ventana]
=== Ventana
The NXP i.MX 6Q/DL based Ventana product family boots via a BOOT ROM internal to the i.MX6 which loads U-Boot SPL (Secondary Program Loader) which then loads U-Boot proper. In this case initial SoC chip and DRAM configuration is done by U-Boot SPL.
Ventana U-Boot enables and supports PCI and the PCI based i210 NIC found on several of the Ventana boards.
see also [wiki:ventana/bootloader]
[=#env]
== Environment variables and scripts
U-Boot uses environment variables to configure much of its functionality. U-Boot environment variables can also be treated as scripts and therefore the environment dictates how U-Boot achieves its goal of loading and executing the OS.
You can use {{{env}}} commands to get or set env vars. For example:
* Get a var:
{{{#!bash
env print model
}}}
* Set a var:
{{{#!bash
env set quiet 1
}}}
* Load default values (does not save):
{{{#!bash
env default -f -a
}}}
* Save current env:
{{{#!bash
env save
}}}
If you want to erase the env:
{{{#!bash
env erase
}}}
Some notable env variables used in U-Boot:
||= Category =||= Name =||= Purpose =||
|| boot || preboot || script executed before 'Hit any key to abort' if CONFIG_USE_PREBOOT=y ||
|| boot || bootcmd || script executed at boot ||
|| boot || bootdelay || number of seconds to wait for a key to abort automatic boot (if 0 will not wait) ||
|| ||
|| console || baudrate || baudrate of serial console ||
|| console || device of serial console ||
|| ||
|| network || ethprime || primary ethernet device (used at boot) ||
|| network || ethaddr || mac addr of first eth interface ||
|| network || eth1addr || mac addr of second eth interface ||
|| network || ethact || active ethernet device (current) ||
|| network || ipaddr || local ip address ||
|| network || serverip || ip address of server for tftp commands ||
|| network || netmask || netmask address (optional) ||
|| network || gatewayip || ip address of gateway (optional) ||
|| network || ethrotate || if set to 'no' will not automatically rotate through network devices on network operations ||
|| network || dhcp || issue a DHCP request for network configuration (set 'autoload=no' to disable attempting to load an image)
|| ||
|| distro config || boot_targets || ordered list of boot targets (ie 'mmc1 mmc2 usb0 usb1') ||
|| distro config || boot_prefixes || ordered list of prefixes of boot scripts (ie '/ /boot') ||
|| distro config || boot_scripts || ordered list of boot script names (ie 'boot.scr') ||
|| ||
|| automatic || board || board model (automatically set during boot) ||
|| automatic || serial# || board serial number (automatically set during boot) ||
=== U-Boot env location, format, and accessing outside of U-Boot
There are several U-Boot config items (CONFIG_ENV_*) that specify where and how the U-Boot env is stored. Typically Gateworks configures 32KiB redundant env located at the end of the boot firmware. This means that U-Boot flips back and forth between the two env areas so that if a power-cut occurs during a 'saveenv' command it will default to the previous env saved.
There are several applications built by U-Boot that facilitate accessing U-Boot env outside of U-Boot:
* fw_printenv / fw_setenv - uses a config file to allow env get/set from Linux
* mkenvimage - creates a binary image from a source file in the format of name=value
The Ubuntu u-boot-tools package provides {{{fw_printenv}}} and {{{fw_setenv}}} but a config file must exist in {{{/etc/fw_env.config}}} (or specified via the -c parameter) which describe the env location and size:
* Venice: (U-Boot env is at the top of 4MB on emmc boot0)
{{{#!bash
# Device offset Env. size
/dev/mmcblk2boot0 0x3f0000 0x8000
/dev/mmcblk2boot0 0x3f8000 0x8000
}}}
- Note that at one point Venice stored its boot firmware on the emmc user hardware partition and its env at the top of 16M on emmc user). If you are using v2023.04 or above its at the device and offset above
* Malibu: (U-Boot env is at the top of 4MB on emmc boot0)
{{{#!bash
# Device offset Env. size
/dev/mmcblk0boot0 0x3f0000 0x8000
/dev/mmcblk0boot0 0x3f8000 0x8000
}}}
- Note that at one point in time Venice stored its boot firmware on the emmc user hardware partition and its env at the top of 16M on emmc user).
* Newport:
{{{#!bash
# Device offset Env. size
/dev/mmcblk0 0xff0000 0x8000
/dev/mmcblk0 0xff8000 0x8000
}}}
* Ventana (NAND boot device):
- cat /proc/mtd
{{{#!bash
dev: size erasesize name
mtd0: 01000000 00040000 "uboot"
mtd1: 00100000 00040000 "env"
mtd2: 7ef00000 00040000 "rootfs"
}}}
- cat /etc/fw_env.config
{{{#!bash
# device offset size erasesize
/dev/mtd1 0x0 0x20000 0x40000
/dev/mtd1 0x80000 0x20000 0x40000
}}}
* make sure /dev/mtd1 is your env partition
* Ventana (MMC boot device)
{{{#!bash
# device offset size erasesize
/dev/mmcblk0 0xb1400 0x20000 0x20000
/dev/mmcblk0 0xd1400 0x20000 0x20000
}}}
This will define the device being used, offset according to flash layout, size from flash map, and size of erase block (unless the device is a file). Ventana U-boot environment is redundant hence two entries, both locations need their variables updated.
Note that in certain circumstances the Linux representation of the boot device can change - please ensure that the devices specified do indeed point to your boot device.
It is important to understand the meaning of the '''Warning: Bad CRC, using default environment''' message. This means that the non-volatile env area specified by the config file is empty or corrupt and that the built-in env within U-Boot will be used which is not appropriate. Note that Gateworks Ventana boards ship with an empty env area and use built-in defaults so if you wish to use the u-boot-tools to access the env from Linux first do a 'saveenv' from U-Boot to provide a valid default env.
If you use {{{fw_setenv}}} on an environment in this state it will properly set the variable you specify and all other variables will continue to use their built-in default values within U-Boot. Essentially you are 'overriding' the defaults as you would expect.
Example usage:
{{{#!bash
# display environment
fw_printenv -c fw_env.config
# set environment variable
fw_setenv -c fw_env.config foo bar #foo being variable name bar being value variable will be set to
#second example
fw_setenv -c fw_env.config ipaddr 192.168.1.10
#print single environment variable
fw_printenv -c fw_env.config foo
#second example
fw_printenv ipaddr
}}}
[=#bootflow]
== Boot Flow
Boot flow in U-Boot refers to how specifically U-Boot loads and passed control to the OS.
After U-Boot initializes it does the following
* executes contents of 'preboot' env variable (if configured with CONFIG_USE_PREBOOT)
* based on the contents of 'bootdelay' env variable it prints 'Hit any key to stop autoboot:' and counts down the number of seconds specified (if set to 0 it will skip this and not allow you to stop execution manually)
* executes contents of 'bootcmd' env variable
[=#distroconfig]
=== Distro Config
A set of scripts referred to as 'distro config' can be used to scan bootable partitions on a set of specified devices for boot scripts and execute the first one it finds.
'''This configuration is used on Newport, Venice, and Malibu product families (not Ventana which pre-dated this concept)'''
This feature provides a well defined U-Boot env intended to make it easier for distro maintainers to develop compatible bootscripts. This primarily entails a set of 'boot scripts' and variables that control them.
Ultimately this U-Boot environment is looking for a U-Boot boot script on a 'bootable' partition (partitions with the 'boot' flag enabled). It searches in this order with these rules:
- **boot_targets** - list of target device type/nums to search: defaults to mmc1 mmc0 usb0 usb1 pxe dhcp
- **devplist** - ''dynamically created'' list of all partitions flagged as 'bootable'
- **boot_prefixes** - list of directories within a partition searched for bootscripts
- **boot_scripts** - list of boot script names searched for
The boot device order is specified by the {{{boot_targets}}} env variable which typically defaults to something like {{{mmc1 mmc0 usb0 usb1 pxe dhcp}}}. For example, to limit OS booting to only mmc device 2 you would 'setenv boot_targets mmc 2; saveenv'.
The Distro-Config environment supports legacy uImage scripts (it does not support FIT images with scripts).
[=#bootscript]
=== Boot script
A boot script is a U-Boot specific set of commands wrapped inside a U-Boot binary header which can be loaded from a device or filesystem and executed via the 'source
' command.
You can create these with the {{{mkimage}}} tool from U-Boot as such:
{{{#!bash
mkimage -A arm64 -T script -C none -d boot.txt boot.scr
}}}
The bootscript can be updated at runtime on the Linux target. For example:
{{{#!bash
mkimage -A arm64 -T script -C none -d boot.txt /boot/boot.scr
}}}
When writing bootscripts compatible with Generic Distro Config you can assume the following env variables:
- **devtype** - the device type the script was loaded from (mmc|usb|sata)
- **devnum** - the device number the script was loaded from (ie 0 for mmc0, 1 for mmc1, etc)
- **distro_bootpart** - the partition number the script was loaded from (ie 0, 1, etc)
- **fdtcontroladdr** - the address the device-tree is at (Note that the Malibu bootloader contains a static version of the board device-tree)
- **kernel_addr_r** - address where kernel can be loaded
- **bootargs** - default bootargs to pass to the kernel - you probably want to add to this and not overwrite it
- **console** - the serial console device to pass to the kernel
Additionally you should note the following:
- use load/ls/save commands which support FAT/ext filesystem types automatically instead of the fs specific commands
- if using a root filesystem that is not supported by the bootloader (ie F2FS or BTRFS) you can place your bootscript and kernel image in the FAT12 filesystem on partition 1 of the boot device. This filesystem is part of the 16MB 'Boot Firmware' image. If doing so you will need to compress the kernel and package it into a [#fit FIT image] in order to fit it in the available space.
[=#fit]
== Flattened Image Tree (FIT) images
The U-Boot bootloader supports Flattened Image Tree (FIT) images which expand greatly on the legacy U-Boot image (uImage) format by allowing multiple binary blobs within an image. These blobs can be kernel images, ramdisk images, device-tree blobs, and bootloader scripts. Each image can also be optionally compressed (meaning U-Boot will decompress it) and check-sumed with a variety of hash mechanisms (meaning U-Boot will verify the image before using it).
Quick summary of FIT Images:
* introduced to resolve limitations with original single-image formats and follow-on multi-image format supported by UBoot bootm (boot memory)
* uses power of the Device-Tree-Compiler (DTC)
* FIT .itb files can be created with mkimage by passing in a .its file which in device-tree notation describes the images
* U-Boot supports FIT with several commands:
- {{{source :}}} # source a script by name from FIT image in memory
- {{{iminfo }}} # print all the info contained in a FIT image in memory and verify (just not boot it)
- {{{imextract - }}} # extract item (ie kernel@1) to addr
- {{{bootm [#conf] - $fdtcontroladdr}}} # boot default or 'conf' configuration (ie #config@1)
- {{{bootm start [#conf] - $fdtcontroladdr}}} # boot from memory a specific configuration (or default configuration) from FIT image
Example:
* kernel.its with a single compressed kernel for ARM64
{{{#!bash
/dts-v1/;
/ {
description = "Simple image with single Linux kernel";
#address-cells = <1>;
images {
kernel@1 {
description = "Linux kernel";
data = /incbin/("./Image.gz");
type = "kernel";
arch = "arm64";
os = "linux";
compression = "gzip";
load = <0x40200000>;
entry = <0x40200000>;
hash@1 {
algo = "sha256";
};
};
};
configurations {
default = "conf@1";
conf@1 {
description = "Boot Linux kernel";
kernel = "kernel@1";
};
};
};
}}}
* create image:
{{{#!bash
cp arch/arm64/boot/Image .
gzip Image
mkimage -f kernel.its /tftpboot/kernel.itb
}}}
* boot the default configuration from U-Boot:
{{{#!bash
tftpboot $loadaddr kernel.itb && bootm $loadaddr - $fdtcontroladdr
}}}
References:
* [http://git.denx.de/?p=u-boot.git;a=tree;f=doc/uImage.FIT doc/uImage.FIT]
* http://www.denx.de/wiki/pub/U-Boot/Documentation/multi_image_booting_scenarios.pdf
* http://elinux.org/images/f/f4/Elc2013_Fernandes.pdf
[=#gpio]
== General Purpose I/O (GPIO)
The {{{gpio}}} command provides the ability to list and configure board-specific GPIO's.
Examples:
* List GPIO's:
{{{#!bash
u-boot=> gpio status
Bank GPIO1_:
GPIO1_0: output: 0 [x] rs485_term.gpio-hog
GPIO1_1: input: 0 [x] mipi_gpio4.gpio-hog
GPIO1_5: output: 0 [x] regulator-wifi-en.gpio
GPIO1_6: output: 0 [x] pci_usb_sel.gpio-hog
GPIO1_7: input: 1 [x] dio0.gpio-hog
GPIO1_8: output: 0 [x] regulator-usb-otg2.gpio
GPIO1_9: input: 1 [x] dio1.gpio-hog
GPIO1_12: output: 0 [x] regulator-usb-otg1.gpio
Bank GPIO2_:
GPIO2_12: input: 1 [x] mmc@30b50000.cd-gpios
Bank GPIO3_:
GPIO3_0: output: 0 [x] ethernet@30be0000.phy-reset-gpios
Bank GPIO4_:
GPIO4_0: output: 0 [x] rs485_en.gpio-hog
GPIO4_1: input: 0 [x] mipi_gpio3.gpio-hog
GPIO4_2: output: 0 [x] rs485_hd.gpio-hog
GPIO4_3: input: 0 [x] mipi_gpio2.gpio-hog
GPIO4_4: input: 0 [x] mipi_gpio1.gpio-hog
GPIO4_7: output: 1 [x] pci_wdis#.gpio-hog
Bank GPIO5_:
GPIO5_4: output: 0 [x] led-1.gpios
GPIO5_5: output: 0 [x] led-0.gpios
}}}
* set GPIO named DIO1 to logic 1:
{{{#!bash
u-boot=> gpio set dio1
gpio: pin dio1 (gpio 9) value is 1
}}}
* set GPIO named DIO1 to logic 0:
{{{#!bash
u-boot=> gpio clr dio1
gpio: pin dio1 (gpio 9) value is 0
}}}
* read GPIO DIO1 logic level:
{{{#!bash
u-boot=> gpio input dio1
gpio: pin dio1 (gpio 9) value is 0
}}}
[=#led]
== LED support
If LED support is enabled you can configure board LED's via U-Boot:
* List LED's:
{{{#!bash
u-boot=> led list
led-0 off
led-1 off
}}}
* turn an LED on:
{{{#!bash
u-boot=> led led-0 on
}}}
* turn an LED off:
{{{#!bash
u-boot=> led led-0 off
}}}
Note that many Gateworks boards have a front-panel bi-color LED which is supported by two distinct LED's for 'red' and 'green'. In this case you must enable one and disable the other (setting both 'on' is the same as setting both 'off').
[=#gsc]
== GSC support ==
The {{{gsc}}} command that will let you interact with the Gateworks System controller on Gateworks boards.
Examples:
* see basic info
{{{#!bash
u-boot=> gsc
GSCv3 : v61 0x1d6f RST:VIN Thermal protection:enabled at 96C
RTC : 1970-01-05 22:36:56 UTC
Model : GW7301-01-CF
Serial : 928012
MFGDate : 01-09-2023
SOM : GW7001-F 928012 01-09-2023
BASE : GW7301-C 878707 05-04-2022
}}}
* disable primary power supply for 5 seconds
{{{#!bash
u-boot=> gsc sleep 5
GSC Sleeping for 5 seconds
}}}
* Show hardware monitor values:
{{{#!bash
u-boot=> gsc hwmon
temp : 47.9C
vdd_bat : 3.216V
vdd_vin : 16.724V
vdd_adc1: 0.000V
vdd_adc2: 0.000V
vdd_dram: 1.119V
vdd_1p2 : 1.192V
vdd_1p0 : 0.000V
vdd_2p5 : 0.000V
vdd_3p3 : 3.272V
vdd_0p95: 0.938V
vdd_1p8 : 1.793V
vdd_gsc : 2.950V
}}}
- Note that the voltage rails connected to the GSC hardware monitor vary per board
[=#net]
== Network
U-Boot network support exists for the network controllers found within the SoC of the board. If PCI is supported by the product family there are a few PCI based network controller drivers as well.
Because U-Boot is not a full OS and does not support background drivers network operations occur based on various network commands such as 'tftpboot', 'dhcp'. The network interface used for these commands is specified by the 'ethact' env variable. The 'net list' command available in newer versions of U-Boot can help identify the names of the network interface that can be used.
To see a table showing the physical network interface mapping to U-Boot devices refer to:
* [wiki:malibu/ethernet Malibu Ethernet page]
* [wiki:venice/ethernet Venice Ethernet page]
* [wiki:newport/ethernet Newport Ethernet page]
* [wiki:ventana/ethernet Ventana Ethernet page]
The following U-Boot environment variables are used with networking:
* {{{ipaddr}}} - local IP address
* {{{serverip}}} - TFTP server IP
* {{{netmask}}} - Netmask
* {{{gatewayip}}} - Gateway IP if needed
* {{{ethact}}} - controls which interface is currently active
* {{{ethprime}}} - controls which interface is used first
* {{{ethrotate}}} - when set to 'no' uboot does not go through all available network interfaces and instead just stays at the currently selected interface (ethact)
* {{{filesize}}} - gets set to the size of data transferred
* {{{netretry}}} - when set to 'no' each network operation will either success or fail without retrying. When set to 'once' the operation will fail only when all available network interfaces have been tried once without success.
[=#dhcp]
=== DHCP
The {{{dhcp}}} command (if enabled) can use the DHCP protocol to configure networking.
Examples:
* use DHCP to configure networking:
{{{#!bash
u-boot=> dhcp
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
DHCP client bound to address 172.24.20.160 (1047 ms)
}}}
A successful bind will set the following:
* ipaddr
* netmask
* gatewayip
* serverip
The following variables affect dhcp:
* autoload - if set will attempt to transfer a file from the server
[=#dns]
=== DNS
The {{{dns}}} command (if enabled) can use the DNS protocol to perform a name to IP lookup. You must setn the 'dnsip' env variable to an accessible DNS server.
Examples:
* use DNS to lookup dev.gateworks.com
{{{#!bash
u-boot=> dhcp
BOOTP broadcast 1
DHCP client bound to address 172.24.20.160 (1046 ms)
u-boot=> setenv dnsip 8.8.8.8
u-boot=> dns dev.gateworks.com
108.161.129.64
}}}
[=#tftp]
=== TFTP
The {{{tftpboot}}} command has been the primary method for transferring files from a server for many years.
The following U-Boot environment variables (as well as the general network variables above) are used with tftp:
* {{{tftpsrcport}}} - UDP source port (if not set uses default)
* {{{tftpdstport}}} - UDP dest port (if not set uses well known port 69)
* {{{tftpblocksize}}} - if not set will use TFTP server's default block size
* {{{tftptimeout}}} - retransmission timeout for TFTP packets in ms (min value is 1000, default is 5000)
Examples:
* fetch a file via TFTP to a memory address specified by loadaddr:
{{{#!bash
u-boot=> tftpboot $loadaddr 192.168.1.146:file
}}}
The {{{filesize}}} variable will be set to the number of bytes transferred
[=#nfs]
=== NFS
The NFS command (if enabled) can transfer a file from an NFS server to a memory address.
Examples:
* fetch a file via NFS to a memory address specified by loadaddr:
{{{#!bash
u-boot=> nfs $loadaddr 172.24.21.238:/venice/firmware-venice-imx8mp.bin
}}}
The {{{filesize}}} variable will be set to the number of bytes transferred
[=#wget]
=== WGET
The TCP protocol and {{{wget}}} command (if enabled) were added to U-Boot v2023.01 to support fetching files via HTTP however until very recently it was plagued with a couple of issues. These issues have been resolved and support has been enabled for venice U-Boot
Examples:
* fetch a file via HTTP to a memory address specified by loadaddr:
{{{#!bash
u-boot=> wget $loadaddr 172.24.21.238:/venice/firmware-venice-imx8mp.bin
HTTP/1.0 200 OK| | | | | | | | | | | | | | | | | | | | | |
Packets received 2900, Transfer Successful
Bytes transferred = 4194336 (400020 hex)
}}}
The {{{filesize}}} variable will be set to the number of bytes transferred
Note that only HTTP is supported.
[=#filesystem]
== Generic File System and File Management support for Block storage devices
For modern versions of U-Boot there are several commands that work with files which support multiple file systems and device interfaces eliminating the need for you to know what filesystem is used and avoid using the deprecated filesystem specific commands. For these commands you specify the interface name (ie mmc,usb,sata) , a device number and optionally a partition.
* load [ [ [ [bytes [pos]]]]] - load a file to memory
* save [ bytes [pos] - save a file from memory
* ls [ [directory]] - list files on a device/directory
* ln target linkname - create a symlink
* size - determine size of a file (saved in 'filesize' env variable)
The 'part' command can be used to work with partition tables (both GPT and MBR if enabled):
* part uuid : - print partition UUID
* part uuid : - set varname to partition UUID
* part list - print partition table
* help part - see more options
Note that for the usb interface you must start the interface first with a 'usb start' operation. USB bus enumeration does not happen in the background.
[=#mmc]
== MMC (eMMC and microSD)
The 'mmc' command supports various low level operations on !MultiMediaCard bus devices such as eMMC and microSD when not working at the [#filesystem fileystem layer]. When working at this level you must set the current mmc device manually.
Examples:
* mmc list - list available device numbers
{{{#!bash
u-boot=> mmc list
FSL_SDHC: 0
FSL_SDHC: 1
FSL_SDHC: 2 (eMMC)
}}}
* mmc dev [dev] [part] [mode] - show or set the current mmc device
{{{#!bash
u-boot=> mmc dev 2
switch to partitions #0, OK
mmc2(part 0) is current device
u-boot=> mmc dev
switch to partitions #0, OK
mmc2(part 0) is current device
}}}
* mmc info - show info for currently selected device:
{{{#!bash
u-boot=> mmc info
Device: FSL_SDHC
Manufacturer ID: 70
OEM: 0
Name: IB2964
Bus Speed: 200000000
Mode: HS400 (200MHz)
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 58.4 GiB
Bus Width: 8-bit DDR
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 58.4 GiB
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
Boot area 0 is not write protected
Boot area 1 is not write protected
}}}
* mmc help - show more options
[=#usb]
== USB
The 'usb' command supports various low level operations on Universal Serial Bus hosts and devices when not working at the [#filesystem fileystem layer]. When working at this level you must set the current usb device manually. Additionally you must use the 'usb start' command to initialize the USB subsystem and enumerate the bus. USB bus enumeration does not happen in the background.
Examples:
* usb start - start and scan the USB controllers
* usb tree - show a tree view of USB enumerated devices
* help usb - more USB commands and options
Example Usage:
{{{#!bash
u-boot=> usb start && usb tree
starting USB...
Bus usb@32e40000: Bus usb@32e50000: USB EHCI 1.00
scanning bus usb@32e40000 for devices... 1 USB Device(s) found
scanning bus usb@32e50000 for devices... 4 USB Device(s) found
scanning usb for storage devices... 1 Storage Device(s) found
USB device tree:
1 Hub (480 Mb/s, 0mA)
u-boot EHCI Host Controller
1 Hub (480 Mb/s, 0mA)
| u-boot EHCI Host Controller
|
+-2 Hub (480 Mb/s, 0mA)
| Microchip Tech USB2744
|
+-3 Mass Storage (480 Mb/s, 100mA)
| CENTON USB 52D0CE92
|
+-4 Vendor specific (480 Mb/s, 0mA)
Microchip Tech Hub Controller
}}}
=== USB Device support (via USB Host mode)
A very small set of USB devices are supported in U-Boot depending on the version and configuration. Typically the following devices are used during development:
* USB Network Adapters
* USB Mass Storage
[=#usbnet]
==== USB Network Adapters
A very small set of USB network adapters are supported in U-Boot depending on the version and configuration:
* ASIX AX8817X - (ie [http://plugable.com/products/usb2-e100 Plugable USB2-E100 10/100mbps)
* network device: asx0
* SMSC LAN95xx
* network device: sms0
Depending on the version of U-Boot more devices may be available
To use these use the following U-Boot configuration:
1. scan USB bus for supported devices:
{{{#!bash
usb start
}}}
* If you have a supported USB device attached you will see a message to that effect
2. set active ethernet device (use 'net list' to see a list of device names)
{{{#!bash
setenv ethact asx0
}}}
3. Use networking as needed:
{{{#!bash
ping 192.168.1.254
tftp ${loadaddr} ${file}
}}}
[=#ums]
==== USB Mass Storage (UMS) Device
USB Mass Storage (UMS) device support is not as robust as it is on Linux. Specifically some older devices that have support for various quirks in Linux may not work in U-Boot.
Older UMS devices sometimes fail to enumerate on the bus. If you encounter this you can try the following:
- see if it enumerates on a different port (sometimes enumerating through an on-board USB HUB can be problematic). If your board has a USB OTG or Type-C connector those interfaces do not go through a USB HUB so try your UMS device there
- try setting the 'usb_pgood_delay' env variable to something like 2000 before you do your 'usb start'. This represents a millisecond delay between enabling the VBUS regulator and enumerating the bus
Example:
{{{#!bash
u-boot=> usb start && usb tree
starting USB...
Bus usb@32e40000: Bus usb@32e50000: USB EHCI 1.00
scanning bus usb@32e40000 for devices... 1 USB Device(s) found
scanning bus usb@32e50000 for devices... 4 USB Device(s) found
scanning usb for storage devices... 1 Storage Device(s) found
USB device tree:
1 Hub (480 Mb/s, 0mA)
u-boot EHCI Host Controller
1 Hub (480 Mb/s, 0mA)
| u-boot EHCI Host Controller
|
+-2 Hub (480 Mb/s, 0mA)
| Microchip Tech USB2744
|
+-3 Mass Storage (480 Mb/s, 100mA)
| CENTON USB 52D0CE92
|
+-4 Vendor specific (480 Mb/s, 0mA)
Microchip Tech Hub Controller
u-boot=> usb storage
Device 0: Vendor: CENTON Rev: 8.07 Prod:
Type: Removable Hard Disk
Capacity: 61500.0 MB = 60.0 GB (125952000 x 512)
u-boot=> ls usb 0:1 boot
4096 .
4096 ..
860 boot.scr
10407524 Image
}}}
[=#gadget]
=== USB Device Gadget support
Very limited support for USB device/gadget mode exists
[=#gadgetums]
==== USB Mass Storage (UMS) Gadget
The 'ums' command can be used to allow a host PC to access (slowly!) a block storage device on your target board.
On boards that support this with a USB OTG or Type-C connector cabled to a PC USB host you can use:
* ums [] - usb controller is the number of the usb controller (ie 0 or 1) to present the interface on while devtype, dev, and part specify the interface (devtype), device number (dev), and optional partition to expose via the USB Mass Storage device class
Examples:
* expose mmc device 0 on USB host controller 0 as a USB Mass Storage device:
{{{#!bash
usb start && ums 0 mmc 0
}}}
This requires CONFIG_USB_FUNCTION_MASS_STORAGE to be enabled and a USB host controller that can operate in gadget mode
[=#gadgetacm]
==== USB CDC ACM (Serial) Gadget
You can use USB in device mode for console input/output to a host PC which supports the standard CDC ACM USB driver:
* Examples:
- use only ACM for console
{{{#!bash
setenv stderr usbacm && setenv stdout usbacm && setenv stdin usbacm
}}}
- use both ACM as well as original env based UART serial console (requires CONFIG_CONSOLE_MUX=y):
{{{#!bash
setenv stderr ${stderr},usbacm && setenv stdout ${stdout},usbacm && setenv stdin ${stdin},usbacm
}}}
After doing this on your host PC the device is connected to with a USB-C to Host cable you should see a USB ACM device enumerate and can use it:
* example on a Linux PC you will see the following in syslog (dmesg):
{{{#!bash
usb 3-10.5.5: new high-speed USB device number 21 using xhci_hcd
usb 3-10.5.5: New USB device found, idVendor=0525, idProduct=a4a5, bcdDevice= 2.21
usb 3-10.5.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 3-10.5.5: Product: USB download gadget
usb 3-10.5.5: Manufacturer: Gateworks
usb 3-10.5.5: SerialNumber: 445096
usb-storage 3-10.5.5:1.0: USB Mass Storage device detected
usb-storage 3-10.5.5:1.0: Quirks match for vid 0525 pid a4a5: 10000
cdc_acm 3-10.5.5:1.0: ttyACM0: USB ACM device
# connect to ttyACM0 with a terminal program such as screen/minicom/picocom
screen /dev/ttyACM0
}}}
This requires CONFIG_USB_FUNCTION_ACM to be enabled and a USB host controller that can operate in gadget mode
[=#pci]
== PCI
PCI bus support is enabled on the Ventana family due to the fact that at least one Ventana board model has only PCI based network interfaces.
[=#netconsole]
== !NetConsole (access U-Boot console from network)
U-Boot does not contain any TCP implementation and as such there is no 'telnet server' or 'telnetd' support. There is however something similar called '!NetConsole' which will allow stdin/stdout/stderr to be directed to a UDP network port. If you set this up you can use the Linux 'nc' or 'netcat' tool or use the the 'netconsole' shell script provided in tools/netconsole (which uses these tools) to talk to U-Boot's interpreter from a Linux host.
Using !NetConsole, the paradigm is reversed from the telnet/ssh perspective a bit such that you need to configure U-Boot to listen to a specifc IP address of a server.
To enable !NetConsole you must do the following:
- U-Boot:
* configure networking: For example have a network interface supported by U-boot, set {{{ipaddr}}} env variable and {{{serverip}}} env variable (make sure you can {{{ping $serverip}}}):
{{{
setenv ipaddr 192.168.1.1 # local ip
setenv serverip 192.168.1.146 # host ip running netcat/netconsole
}}}
* set the {{{ncip}}} address to your server:
{{{
setenv ncip ${serverip}
}}}
* set stdin/stdout/stderr as desired to {{{nc}}}:
{{{
setenv stdin nc; setenv stdout nc; setenv stderr nc
}}}
* (optional) if you want these changed persistent, do a {{{saveenv}}}:
{{{
saveenv
}}}
- Linux host:
* make sure you have netcat (either {{{nc}}} or {{{netcat}}} applications)
* grab the {{{netconsole}}} shell script from U-Boot's tools directory:
{{{#!bash
wget https://raw.githubusercontent.com/Gateworks/u-boot-imx6/gateworks_v2015.04/tools/netconsole
chmod +x netconsole
}}}
* use {{{netconsole}}} to listen to your target IP address for input/output:
{{{#!bash
netconsole 192.168.1.1
}}}
- Note that netconsole remaps the interrupt from Cntl-C to Cntl-T so that you can use Cntl-C over the network console
For a bootloader configuration that sits waiting for network commands from a specific host but with a timeout you can use the preboot env variable to execute a script prior to bootcmd such as:
{{{
setenv serverip 192.168.1.146 # your server ip
setenv ipaddr 192.168.1.1 # your local ip
setenv netretry no
setenv preboot 'echo "Looking for server at $serverip..."; \
if ping $serverip; then setenv ncip ${serverip}; setenv bootdelay 10; \
echo "Starting NetConsole to ${ncip} and waiting for ${bootdelay} seconds..."; \
setenv stdin nc; setenv stdout nc; setenv stderr nc; \
fi'
saveenv
}}}
* Note that we set {{{netretry}}} to 'no' which causes network operations to not retry (otherwise the ping will go forever). This could also be set to 'once' if you wish to cycle through all available network interfaces (such as on-board NIC's as well as USB nics) instead of just 'ethprime'.
This only pertains to input/output of the U-Boot environment. Once the bootloader jumps to the kernel, the kernel is in charge of what to do about its input/output, which is controlled via the 'console' kernel cmdline. Note that there is a CONFIG_NETCONSOLE option in the kernel that uses a 'netconsole' kernel cmdline however that option is not enabled in the Gateworks kernels by default
References:
* https://github.com/Gateworks/u-boot-imx6/blob/gateworks_v2015.04/doc/README.NetConsole
[=#split]
== Installing Large Disk Images on Systems with Limited RAM
In certain scenarios, devices with limited RAM face challenges when updating firmware or system images stored on MMC flash storage. Attempting to install large disk images directly may fail due to memory constraints. To address this limitation, a practical approach involves splitting the disk image into smaller chunks and updating the device incrementally. This wiki section documents a solution for how to install these larger than RAM disk images inside of u-boot; on Gateworks SBCs.
=== Spliting the Disk Image Into Segments
Before proceeding with the update process, the disk image needs to be split into smaller parts. This can be achieved using the Linux {{{split}}} command, making sure to decompress the image if it's compressed. The key requirement for the process outlined here is that the file must be divided into segments that are evenly divisible by 512-byte blocks (so any multiple of KB or MB is fine). This ensures that the subsequent calculation of block count, as demonstrated in the script in the following section. Here are the steps to split our BSP disk image as an example:
{{{#!bash
# If the image is compressed, extract it first
gunzip jammy-venice.img.gz
# Split the image into parts of 500MB each named 'jammy-venice.img.part'
split -d -b 500M jammy-venice.img jammy-venice.img.part
}}}
=== Downloading and Installing the Segments
To handle the segmented installation of the disk image, we will utilize a U-Boot script specifically designed for devices with limited RAM. This script orchestrates the sequential installation of each segmented portion of the disk image. Here's how to create and use the U-Boot script:
{{{#!bash
cat <<\EOF> storage_split_update
setenv storage_split_update 'if itest.s x == "x${splitfile}"; then
# Check if the ${splitfile} environment variable is set
echo "The following environment variables need to be set in order for this script to run:"
echo " splitfile - full path file name prefix of the splitted files (eg file.img for file.img.part00)"
exit 1
fi
# Attempt to fetch the ${splitfile} to update storage
echo "Attempting to fetch ${splitfile} to update storage"
setenv 0 0
setexpr i 0
setexpr offset 0
# Iterate over segments to write to Storage
while itest $i -le 99; do
# Add leading zero to $i if necessary
itest $i -gt 9 && setenv 0
if tftpboot $loadaddr ${splitfile}.part${0}${i}; then
# Calculate block count
setexpr blkcnt $filesize + 0x1ff
setexpr blkcnt $blkcnt / 0x200
# Write segment to Storage
if ${iface} write ${loadaddr} ${offset} ${blkcnt}; then
echo "Successfully wrote segment ${i} of ${filesize} bytes"
setexpr offset ${offset} + ${blkcnt}
setexpr i ${i} + 1
# setexpr results in a hex number so convert to dec
setexpr rem ${i} % 0x10; itest ${rem} -eq 0x0a && setexpr i ${i} + 6
else
echo "Error writing segment ${i} of ${filesize} bytes"
exit 1
fi
elif itest ${i} -eq 0; then
echo "ERROR: image file ${splitfile}.part${0}${i} not found or it is too big to fit in memory"
exit 1
else
echo "SUCCESS: ${splitfile} was successfully written to ${iface} storage device"
exit 0
fi
done'
EOF
}}}
U-Boot requires scripts to be in a specific binary format for execution with the {{{source}}} command. To compile the script into this format, we use the mkimage tool, which is provided as part of the U-Boot distribution.
{{{#!bash
mkimage -A arm64 -T script -C none -d storage_split_update ustorage_split_update
}}}
Once you have the u-boot source-able script and your split image segments saved to your tftp server; you can now install your large disk Image onto your target board.
{{{#!bash
cp storage_split_update your_tftp_server
cp jammy-venice.img.part* your_tftp_server
}}}
=== Installing
Before running the update script, you need to download it from your tftp server to your target board, and you need to specify the name of the split image file that you want to use.
{{{#!bash
#Set your tftp server IP
u-boot=> dhcp
u-boot=> setenv serverip
#Load the script, being sure to use full path name
u-boot=> tftpboot /venice/ustorage_split_update
u-boot=> source $loadaddr
#Run the script & install the segments
u-boot=> setenv splitfile /venice/jammy-venice.img
}}}
Depending on which storage device you want to write your Image to, you need to set the device accordingly then you can run the script. Here is the general use as well as a specific use case:
**For MMC:
{{{#!bash
#mmc dev
# hardware partition: 0=user 1=boot0 2=boot1
u-boot=> mmc list # show mmc devs
u-boot=> mmc dev 2 0
u-boot=> setenv iface mmc
}}}
**For USB:
{{{#!bash
#usb dev
u-boot=> usb stop && usb start && usb storage # scan and show storage devs
u-boot=> usb dev 0 0
u-boot=> setenv iface usb
}}}
**For SATA:
{{{#!bash
#sata dev
u-boot=> sata init && sata device # scan and show storage devs
u-boot=> sata dev 0
u-boot=> setenv iface sata
}}}
**For NVMe:
{{{#!bash
#nvme dev
u-boot=> pci enum && nvme scan && nvme info # scan and show storage devs
u-boot=> nvme dev 0
u-boot=> setenv iface nvme
}}}
To initiate the instillation after you have properly selected the storage device your want:
{{{#!bash
run storage_split_update
}}}
Once the image download and installation process is complete, you can proceed to use the board as usual.
{{{#!bash
u-boot=> boot
}}}