WinLink E850-96 board
Overview
WinLink’s E850-96 board [1] is based on the Samsung Exynos850 SoC and follows the 96Boards Consumer Edition specification [2]. This makes it possible to use 96Boards mezzanine boards [3] with it. It’s an open-hardware board, and the hardware design files were published [4] along with supported software and related documentation [5].
U-Boot can be used on E850-96 instead of the original (factory pre-flashed) Samsung’s LittleKernel based bootloader [6]. Because the E850-96’s version of FWBL1 [7] doesn’t verify bootloader’s signature, there is no need to sign the U-Boot binary. This means the U-Boot binary can be flashed to eMMC instead of the LittleKernel bootloader, and it will just work.
The BL2 bootloader sets up DRAM and runs the final bootloader (U-Boot) from
DRAM, so there is no need for U-Boot SPL. It’s enough to have only U-Boot proper
(u-boot.bin).
Boot Flow
The boot path for Exynos850 is shown in Figure 1.
Figure 1: Exynos850 SoC boot architecture
Legend:
BL0: Boot ROM codeBL1: Software part of Boot ROMEPBL: Exynos Primary Boot LoaderBL2: Initializes CMU and DRAM and runs the final bootloaderBootloader: The final bootloader (e.g. U-Boot); it’s also called BL33 in terms of ARM boot flowEL3_MON: EL3 monitor (trusted firmware, handles SMC calls); it’s also called BL31 in terms of ARM boot flowLDFW: Loadable Firmware (loaded by U-Boot)
On a “power-on” event, the processor starts executing code at address 0x00000000 where the internal ROM (iROM) is mapped. iROM contains the Boot ROM code (BL0). All other bootloaders are stored in external storage (usually eMMC), so the user can update those later.
By default the board is configured to boot from eMMC. On power-on, the Boot ROM
code (BL0) jumps to the beginning of eMMC boot partition 0 (mmc0boot0)
where BL1 must reside. The boot flow then progresses through multiple various
bootloaders (as shown in Figure 1), eventually ending up
executing U-Boot (designated as “Bootloader” in the figure).
Boot Device Configuration
The boot device can be chosen using the SW1 DIP switch. It controls the eXternal Operating Mode (XOM) SoC pins. Table 1 shows how the boot source can be configured using the SW1.
SW1 pin positions (1234) |
Boot order |
|---|---|
0000 |
1st: eMMC, 2nd: USB |
1000 |
1st: USB, 2nd: - |
0100 |
1st: SD card, 2nd: USB |
1100 |
1st: eMMC, 2nd: SD card |
The default boot source is eMMC (all SW1 pins are “OFF”, i.e. in “down”
position). USB boot method can be useful for unbricking the board (in case
some incorrect or broken bootloader was flashed to eMMC by mistake), which
allows one to upload and execute all bootloaders over USB. See the
dltool [8] README file for details. SD card boot was never tested on
E850-96, so it leaves two options: eMMC boot (regular boot) or USB boot (mainly
used for unbricking the board and during the bootloader development process).
Building U-Boot
Build U-Boot binary from source code (using AArch64 baremetal GCC toolchain):
export PATH=<toolchain path>/bin:$PATH
export CROSS_COMPILE=<toolchain prefix>
make e850-96_defconfig
make
The output file is u-boot.bin.
Flashing Overview
Note
In case the board is bricked for some reason, the dltool [8] can be used
to unbrick and revive it. This tool performs USB boot and uploads all E850-96
bootloaders over USB, which are then executed on the board. The loaded
bootloader (e.g. LittleKernel or U-Boot) further enters fastboot mode, so that
the user can flash the functional bootloader binary (U-Boot or
LittleKernel [7]) to eMMC using fastboot tool. See the dltool README
file for more details about the procedure.
eMMC layout on E850-96 looks like this:
User area of eMMC: contains GPT partition table with OS partitions (either Linux or Android)
Boot Partition 0 (
mmc0boot0): contains all bootloaders (firmware)Boot Partition 1 (
mmc0boot1): contains U-Boot environment
There are several methods enabled in U-Boot for flashing software to eMMC on E850-96:
fastboot (USB): most useful for flashing OS partitions (Linux or Android)
DFU (USB): convenient for flashing bootloaders (firmware) to boot partition 0
Capsule Update: EFI mechanism, can update bootloaders without the need to use USB
Flashing U-Boot from LK (Initial)
The original E850-96 board is shipped with the LittleKernel-based bootloader
flashed in eMMC. This LK bootloader allows flashing images in the bootloader
area of eMMC boot partition 0 using fastboot just like flashing a regular
partition in the user area of eMMC.
So to replace the original bootloader with U-Boot, first boot into fastboot mode (as described in the board software documentation [9], in section 6 “Flashing the Software”):
Connect the power cable to your E850-96 board
Press the “POWER” button (SW2) for 1 sec to start booting the bootloader
Press and hold the “VOL_UP” button (SW4) for 7 seconds
Flash the U-Boot binary:
fastboot flash bootloader u-boot.bin
fastboot reboot
U-Boot will boot up to the shell. Configure the default U-Boot environment before starting to work with U-Boot:
env default -f -a
env save
Flashing Linux Images
The Linux partition table contains only two partitions:
esp(EFI System Partition)rootfs
Format eMMC to have Linux partition table (using the default $partitions
definitions):
gpt write mmc 0 $partitions
…or do the same using fastboot:
fastboot oem format
Enter fastboot mode on your device:
fastboot usb 0
And then flash the images:
fastboot flash esp esp.img
fastboot flash rootfs rootfs.img
Flashing Android Images
Use $partitions_android as current partition definitions:
setenv partitions_linux $partitions
setenv partitions $partitions_android
env save
Format eMMC to have Android partition table:
gpt write mmc 0 $partitions
…or do the same using fastboot:
fastboot oem format
Currently, flashing Android images using U-Boot’s fastboot implementation doesn’t work on E850-96. Instead it’s recommended to boot the GBL EFI app (Android Generic Bootloader) [10] and use its fastboot implementation. See Booting Android with GBL section for details. But first the ESP image containing the GBL app has to be flashed.
Enter fastboot mode on your device:
fastboot usb 0
And flash the ESP image:
fastboot flash esp esp.img
fastboot reboot
Now configure EFI boot variables (from U-Boot shell) to boot GBL app by default, as described in the Booting Overview section. Boot GBL and enter fastboot mode.
The Android flashing procedure is complex and may vary across different Android versions. So there is usually a flashing script (or flashing instructions) provided with AOSP images for the E850-96 board to flash all Android images to eMMC. Run it:
./flash-all.sh
Flashing Bootloaders using DFU
All bootloaders are stored in eMMC boot partition 0 (mmc0boot0), which
doesn’t have any partition table (it’s a raw storage area). Hence the most
convenient way to update bootloaders over USB on E850-96 board is using DFU
(Device Firmware Upgrade) protocol, because it allows one to flash images to a
particular area of boot0.
DFU uses only USB endpoint 0 (EP0), which means this flashing method is quite slow. That’s why it’s better to limit its usage for flashing only bootloaders (which are relatively small binaries), and not use it for flashing rootfs and other big images.
eMMC boot partition 0 (mmc0boot0) on E850-96 board has the next layout (all
offsets on the left are specified in 512B blocks):
boot0 partition (4 MiB)
0x0 +----------------------------------+
| fwbl1 (12 KiB) | // BL1 bootloader
0x18 +----------------------------------+
| epbl (76 KiB) | // EPBL bootloader
0xb0 +----------------------------------+
| bl2 (256 KiB) | // BL2 bootloader
0x2b0 +----------------------------------+
| dram_train (16 KiB) | // (not a bootloader)
0x2d0 +----------------------------------+
| ect_test (50 KiB) | // (not a bootloader)
0x334 +----------------------------------+
| acpm_test (130 KiB) | // (not a bootloader)
0x438 +----------------------------------+
| bootloader (2 MiB) | // U-Boot
0x1438 +----------------------------------+
| el3_mon (256 KiB) | // EL3 monitor firmware
0x1638 +----------------------------------+
This layout information is stored in the $dfu_alt_info U-Boot environment
variable, so one can provide a particular bootloader name to dfu-util tool
to update it.
Enter DFU mode on the board:
dfu 0 mmc 0
To update U-Boot via DFU:
dfu-util -D u-boot.bin -a bootloader
To update another bootloader just use the names from the boot0 partition layout
above in -a option.
Flashing Bootloaders using Fastboot
It’s also possible to use fastboot to flash the whole mmc0boot0 HW
partition. It might not be as convenient as using the DFU method though, as an
image containing all binaries has to be prepared first.
One way to generate such an image is to use dd tool, e.g.:
# $1: output image file
# $2: input image file to append
# $3: offset to append after, in LBA (512 bytes)
# $4: size to append, in LBA (512 bytes)
append() {
dd if="$2" of="$1" bs=512 conv=notrunc seek=$(($3)) count=$(($4))
}
# Create boot0 image
dd if=/dev/zero of=$img bs=4M count=1
append boot0.img fwbl1.img 0x0 0x18
append boot0.img epbl.img 0x18 0x98
append boot0.img bl2.img 0xb0 0x200
append boot0.img u-boot.bin 0x438 0x1000
append boot0.img el3_mon.img 0x1438 0x200
Once the image is generated, it can be flashed like this:
fastboot flash mmc0boot0 boot0.img
Updating BLs using Capsule Update
The bootloaders (in eMMC boot partition 0) can be updated using the EFI Capsule Update mechanism. It doesn’t require using USB, so it can be useful in some scenarios.
It works like this:
Generate the “capsule” file for the desired bootloader binary
Copy this capsule file to a particular location in ESP partition
Reboot the board
U-Boot will handle it automatically, using the next procedure:
Locate the capsule file and update the corresponding bootloader
Remove the capsule file from ESP after updating
Reboot again to make use of the updated bootloader
To generate capsule files, some extra information is needed for each bootloader, which is provided in Table 2 below.
Image index |
Image name |
GUID |
|---|---|---|
1 |
fwbl1 |
|
2 |
epbl |
|
3 |
bl2 |
|
4 |
bootloader |
|
5 |
el3_mon |
|
The kernel also exposes this information via the EFI ESRT table in SysFS, in
/sys/firmware/efi/esrt/entries.
For example, to update the U-Boot binary, the capsule file can be generated like this:
./tools/mkeficapsule --index 4 \
--guid 629578c3-ffb3-4a89-ac0c-611840727779 \
u-boot.bin capsule4.bin
The resulting capsule4.bin should be copied to ESP partition, in this
directory:
/EFI/UpdateCapsule/
Then after reboot U-Boot will update the bootloader area in eMMC boot
partition 0 (boot0) and remove the capsule file. It’s done by the EFI boot
manager executed as a part of Standard Boot. To confirm the bootloader was
updated U-Boot will print the next message in the serial console:
Applying capsule capsule4.bin succeeded.
Reboot after firmware update.
Booting Overview
OS booting is performed using a U-Boot mechanism called Standard Boot. The Standard Boot resembles the BIOS boot menu on a PC: it allows one to choose which boot source to use, specify the desired boot order, etc. All OS booting related information (like the next bootloader file, kernel image location, device tree blob location, kernel parameters, etc.) is provided in corresponding files in EFI System Partition (see EFI System Partition section for details), or in rootfs partition. This way there is no need to modify U-Boot (or U-Boot environment) each time the OS is modified or replaced.
With EFI enabled in U-Boot, that covers the requirements of ARM SystemReady compliance program [11], making it easy for end users to install and run different OSes on the same device, and be able to do that in a similar manner across different devices. For example, using Standard Boot and EFI capabilities enabled in U-Boot it should be possible for the user to insert a USB media drive with a Debian installer into the E850-96 board and install Debian OS to eMMC, the same way it’s done on a PC (or do the network installation).
When the autoboot happens on U-Boot countdown timeout, this command (bootcmd) is automatically executed:
bootflow scan -lb
It goes through all present storage devices, and searches for all available boot methods on all partitions that have the bootable flag, and boots the first found method. Next partitions will be searched:
Linux: both
espandrootfspartitions are bootableAndroid: only
espis bootable
Next boot methods are currently enabled in E850-86 U-Boot:
Method |
Description |
|---|---|
efi_mgr |
EFI boot manager flow (booting using |
efi |
EFI boot from |
extlinux |
Booting using |
script |
Booting using |
pxe |
Network boot using PXE protocol |
The most flexible, convenient and modern boot method is efi_mgr. It will be
used by default (if EFI Boot* variables are configured properly). If another
boot method or boot device should be used by default, the desired boot ordering
can be controlled with $boot_targets and $bootmeths environment
variables, as described in Standard Boot Overview documentation.
Booting with efi_mgr Method
The 'efi_mgr' boot method can run EFI apps by using the configuration from
Boot* EFI variables. It’s a recommended boot method and should be
preferred if there are no other requirements.
For example it can run:
GRUB EFI app (booting Debian OS further)
Android GBL EFI app (booting Android OS)
Linux kernel image (EFI stub), mounting further Debian rootfs from eMMC
The most convenient way to configure Boot* EFI variables is by using the
eficonfig U-Boot command. It’s an interactive pseudo-graphic menu-like boot
configurator.
For example, let’s configure EFI boot variables for booting GRUB EFI app from
ESP partition. First, run eficonfig command:
eficonfig
Add GRUB EFI app to the boot list, and make it the highest priority boot source:
Select “Add Boot Option” menu item
Set “Description:” to “GRUB”
Press “File:” -> “Select File” -> “mmc 0:1”, and select the GRUB EFI app (e.g.
/EFI\debian\grubaa64.efi)The created entry should look like this:
Description: GRUB File: mmc 0:1/EFI\debian\grubaa64.efi
Press “Save”
Press “Change Boot Order” and move the “GRUB” item on the top (using “+” key)
Press “Save”
Press “Quit”
Now reboot the board (with reset command); U-Boot will run GRUB, which
should boot Debian OS. So the whole execution chain will look like this:
U-Boot ->
'bootflow scan -lb'(bootcmd) -> efi_mgr -> GRUB -> Debian
The same way Android GBL can be booted:
Description: Android GBL
File: mmc 0:1/EFI\android\gbl_aarch64.efi
Linux kernel can be booted directly, as modern kernel images usually have EFI
stub format (when CONFIG_EFI_STUB=y kernel option is enabled). An example of
such boot configuration:
Description: Debian
File: mmc 0:1/EFI\Linux\Image
Fdt File: mmc 0:1/EFI\Linux\exynos850-e850-96.dtb
Optional Data: root=/dev/mmcblk0p2 rootwait rw console=ttySAC0,115200n8
Booting with efi Method
The 'efi' boot method just executes the /EFI/BOOT/BOOTAA64.EFI file from
the ESP partition, which should be some kind of an OS loader. For example it can
be systemd-boot UEFI boot manager, which is provided by systemd-boot Debian
package. This method is probably only useful if the system has an EFI
bootloader which resides at the fixed path mentioned above. It’s not very
flexible and usually the 'efi_mgr' method should be preferred for running
EFI apps.
To run the 'efi' boot method (assuming it has Seq=1 order in
'bootflow scan -l' output):
bootflow scan -l
bootflow select 1
bootflow boot
Booting with extlinux Method
The 'extlinux' boot method looks for the extlinux.conf configuration
file, reads it and uses the obtained information to find Linux kernel and dtb,
and run it with kernel parameters also supplied by extlinux.conf. This
method is useful if it’s not possible to do EFI boot.
The extlinux.conf file can be generated automatically with u-boot-update
command (from Linux). An example of /boot/extlinux/extlinux.conf (stored in
rootfs):
default l0
menu title U-Boot menu
prompt 0
timeout 50
label l0
menu label Debian GNU/Linux 6.16.0-09930-gecbe0323440c
linux /boot/vmlinuz-6.16.0-09930-gecbe0323440c
fdt /usr/lib/linux-image-6.16.0-09930-gecbe0323440c/exynos/exynos850-e850-96.dtb
append root=/dev/mmcblk0p2 rootwait rw console=ttySAC0,115200n8
To run the extlinux boot method (assuming it has Seq=2 order in
'bootflow scan -l' output):
bootflow scan -l
bootflow select 2
bootflow boot
Booting with script Method
The 'script' boot method looks for the boot.scr file, reads it and
executes U-Boot commands specified there. It can be useful for debugging and
development purposes, but it’s outdated and not very secure, and should be
avoided in production.
First, prepare the boot.txt file with OS boot instructions, for example:
setenv mmcroot 2
setenv console ttySAC0,115200n8
setenv kernel_file Image
setenv fdtfile exynos/exynos850-e850-96.dtb
setenv loadaddr 0x80000000
setenv fdt_addr_r 0x8c000000
echo Booting Linux from eMMC...
mmc dev $mmcdev
mmc rescan
setenv bootargs console=$console root=/dev/mmcblk${mmcdev}p${mmcroot} rootwait rw
load mmc $mmcdev:$mmcroot $fdt_addr_r /boot/$fdtfile
load mmc $mmcdev:$mmcroot $loadaddr /boot/$kernel_file
booti $loadaddr - $fdt_addr_r
Generate boot.scr file (in legacy U-Boot image format) like this:
mkimage -A arm64 -O linux -T script -n "E850-96 Debian bootscript" -C none \
-d boot.txt boot.scr
Then copy it to rootfs, e.g. at /boot/boot.scr path. The Standard Boot will
be able to find it by its name, and execute it to boot the OS.
Booting with pxe Method
The 'pxe' boot method implements PXE protocol, and performs network boot
over Ethernet. When used together with NFS for mounting the rootfs over the
network, it may be one of the most convenient boot methods for development.
That’s because it makes it possible to modify rootfs files (like kernel modules
or programs that are being developed) on the host machine, which is instantly
reflected on the board side due to the network-transparent nature of NFS.
PXE protocol requires TFTP and DHCP servers to be configured on the host machine:
DHCP server should be configured to provide an IP address to your board
TFTP server should be configured to hand out the configuration file (in extlinux format) specifying loadable binaries.
An example of a server-side TFTP directory:
/srv/tftp/ |-- exynos | `-- exynos850-e850-96.dtb |-- Image `-- pxelinux.cfg `-- 01-02-36-f5-1c-81-13where
'01-02-36-f5-1c-81-13'file contains extlinux configuration for TFTP to load and boot. The name of this file has to be in the format of'01-MAC-address'. The Ethernet MAC address in this case is02-36-f5-1c-81-13, and it can be looked up in the$ethaddrenvironment variable in U-Boot:=> env print ethaddr ethaddr=02:36:f5:1c:81:13
An example of such configuration file is:
prompt 0 timeout 5 default local menu title PXE Boot Menu serving from joe-pc label local menu label Debian GNU/Linux linux Image fdt exynos/exynos850-e850-96.dtb append console=ttySAC0,115200n8 root=/dev/nfs nfsroot=${serverip}:/srv/nfs/debian,nolock,nfsvers=4 rw ip=dhcpIf it’s desired to mount the rootfs over NFS (instead of mounting it from eMMC or using an
initrdramdisk) – NFS server should be configured accordingly. E.g. it can share Debian rootfs in/srv/nfs/debian/directory.NFS support should also be enabled in the kernel. Although NFS options are already enabled in ARM64 defconfig, the USB PHY and LAN9514 (Ethernet) drivers must be made built-in, so the next change is needed:
arch/arm64/configs/defconfig ---------------------------- # Keep USB PHY driver built-in, as the Ethernet controller sits on USB bus CONFIG_PHY_EXYNOS5_USBDRD=y CONFIG_TYPEC=y # Keep Ethernet driver built-in CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_USBNET=y
To enable PXE boot:
First, make sure to enable USB host mode in U-Boot, as discussed in Ethernet and USB Host Support section
Check if
'pxe'boot method is present in'bootflow scan -l'output. It should look like this:Seq Method State Uclass Part Name Filename --- ----------- ------ -------- ---- ------------------------ ---------------- 5 pxe ready ethernet 0 smsc95xx_eth.bootdev.0 extlinux/extlinux.conf
Select and boot it:
bootflow select 5 bootflow boot
It’ll run the network boot process which works like this:
U-Boot will obtain an IP address over DHCP from the host
U-Boot will obtain the extlinux configuration file over TFTP from the host
U-Boot will use the information from extlinux file to consequently obtain the Linux kernel image and device tree blob from the host
U-Boot will boot the Linux kernel, providing kernel parameters from the extlinux file
Linux kernel will use the kernel parameters to mount the rootfs over NFS
The Ethernet MAC address ($ethaddr) will be passed from U-Boot to Linux
kernel via device tree.
Booting from USB Flash Drive
It’s possible to boot an OS from a USB flash drive. That might be useful to prevent eMMC part wearing off, or for development reasons.
eMMC will still be used for its boot0 and boot1 partitions (where all
bootloaders and a U-Boot environment are stored, respectively). But it’s
possible to make U-Boot load the LDFW firmware from USB media by setting
$bootdev* environment variables accordingly. There are three environment
variables that can be used to specify the storage where the loadable firmware
should be loaded from:
bootdev: block device interface name ("mmc"or"usb")bootdevnum: block device numberbootdevpart: partition number
Assuming that the USB drive layout follows the same partitioning scheme as
defined in $partitions, it’s enough to only set $bootdev like this:
setenv bootdev usb
env save
Another thing to be aware of: in order to perform USB boot the USB PHY kernel driver has to be built-in. For example, in ARM64 defconfig it’s specified as a loadable module, not a built-in one. So the next change to the kernel config might be needed:
arch/arm64/configs/defconfig
----------------------------
# Needed for boot from USB storage (mounting rootfs from USB drive)
CONFIG_PHY_EXYNOS5_USBDRD=y
CONFIG_TYPEC=y
Follow the instructions below to boot from a USB storage device:
First, make sure to enable USB host mode in U-Boot, as discussed in Ethernet and USB Host Support section
Format your USB stick to follow the
$partitionslayout:Zero /dev/sdX: # dd if=/dev/zero of=/dev/sdX bs=1M count=100 Create GPT table matching eMMC: # cfdisk - 1st partition: EFI System (128 MiB) - 2nd partition: Linux filesystem (all remaining space) Set ESP partition (#1) type to EFI System (0xEF00): # sgdisk --typecode=1:ef00 /dev/sdX # partprobe /dev/sdX Format both partitions: # mkfs.fat -F 32 /dev/sdX1 # mkfs.ext4 /dev/sdX2 Set FS labels for partitions: # fatlabel /dev/sdX1 ESP # e2label /dev/sdX2 rootfs Set GPT names for partitions: # gdisk /dev/sdX c - change a partition's name 1 - partition number esp - new name c - change a partition's name 2 - partition number rootfs - new name w - write table to disk and exit Set bootable flag for rootfs partition: # gdisk /dev/sdX x - extra functionality (experts only) a - set attributes 2 - partition number 2 - legacy BIOS bootable Enter - exit w - write table to the disk and exit y - yes, want to proceedCopy Debian rootfs and ESP to your USB flash drive:
dd if=esp.img of=/dev/sdX1 bs=64M dd if=rootfs.img of=/dev/sdX2 bs=64M status=progress
Insert the prepared USB media into the E850-96 USB port
Tell U-Boot to search for LDFW firmware on USB stick:
setenv bootdev usb env save
Erase eMMC partition table to make U-Boot use ESP from USB drive:
mmc dev 0 mmc erase 0 0x2400 reset
Make sure
'bootflow scan -l'is able to detect boot methods on your USB stickSetup EFI variables (using
eficonfigcommand) for booting from USB stick withefi_mgrboot method, as described in Booting Overview section
Now U-Boot will be able to boot the OS from the USB drive using Standard Boot.
Booting Android with GBL
Warning
Android GBL support for E850-96 in U-Boot is experimental at the moment, and it requires additional actions from the user to make GBL work with U-Boot.
Android GBL (Generic Bootloader) [10] is an EFI app that acts as an Android OS bootloader. It’s able to recognize and boot different versions of Android OS, and provides its own fastboot protocol implementation. Nowadays GBL is a preferred method of running Android, and it’s recommended to use it instead of U-Boot Android booting capabilities.
Unfortunately, GBL support in U-Boot hasn’t been upstreamed yet. The reference U-Boot tree for GBL is Vim3 U-Boot [12]. There was also some independent GBL work done in “Devboards for Android” U-Boot tree [13]. In order to be able to run GBL with upstream U-Boot, next two patches have to be cherry-picked:
ANDROID: [efi] Implement EFI_ANDROID_BOOT_PROTOCOLANDROID: [efi] EFI_ANDROID_BOOT_PROTOCOL: Fixup usb_gadget_handle_interrupts()
They can be found in “Devboards for Android” U-Boot tree [13], in
wip/sm8x50-gbl-fastboot branch. Cherry-pick those patches:
git remote add db4a https://gerrit.devboardsforandroid.linaro.org/platform/external/u-boot
git fetch db4a
git cherry-pick cdc73ef81fdc
git cherry-pick 7d60b5bbe434
As GBL’s EFI_FASTBOOT_USB_PROTOCOL was recently changed (and it’s not
supported in the cherry-picked patches above), GBL source code should be
modified by reverting the latest changes and built manually. Follow GBL
deployment instructions [14] to obtain GBL source code, and then introduce next
changes before building it:
cd bootable/libbootloader
git checkout -b e850-96-functional-fb
git reset --hard f1bc0ca523e1
git cherry-pick 5cd4ad9999ab
Now build GBL and copy the built GBL binary (gbl_aarch64.efi) to your ESP
partition, at this path:
/EFI/android/gbl_aarch64.efi
Configure EFI manager to boot GBL EFI app by default, as described in
Booting with efi_mgr Method section, and run efi_mgr boot method:
bootflow scan -lb
U-Boot will execute the GBL app. GBL also prints messages to the serial console, starting with:
****Generic Bootloader Application****
Let’s use GBL capabilities to flash and boot Android images (assuming eMMC already has an Android partition table created as described in Flashing Android Images section).
Press Backspace to enter GBL’s fastboot mode. Flash E850-96 Android images as described in corresponding documentation.
Reboot the board and run GBL again. It will boot Android automatically.
GBL was successfully used to run AOSP/main on the E850-96 board using AOSP projects from “Devboards for Android” [15].
EFI System Partition
EFI System Partition (ESP) is required by UEFI specification and needed for EFI boot methods in U-Boot to be functional. Because EFI boot is now the recommended way of booting operating systems (see SystemReady [11]), it has to be properly prepared and flashed to eMMC on the E850-96. It’s needed for both Linux and Android boot (at least when using GBL).
ESP is the first partition in the E850-96 partition table, 128 MiB in size. It
must be formatted as FAT, and the bootable flag (“Legacy BIOS bootable” GPT
partition attribute, which is 0x4) has to be set for it, to make Standard Boot
look for boot methods on it.
The initial ESP image can be prepared like this:
dd if=/dev/zero of=esp.img bs=1M count=128
/sbin/mkfs.fat -F 32 -n ESP esp.img
mmd -i esp.img EFI EFI/BOOT EFI/firmware
mcopy -i esp.img ldfw.bin ::EFI/firmware
mdir -i esp.img ::EFI/firmware
The created ESP image will contain only LDFW firmware (see Loadable Firmware section for details). The same way other files can be added to it.
Here is an example of an ESP partition for E850-96:
/
|-- EFI
| |-- BOOT
| | `-- BOOTAA64.EFI // systemd-boot
| |-- Linux
| | |-- Image // Linux kernel image
| | `-- exynos850-e850-96.dtb // Linux device tree
| |-- UpdateCapsule
| |-- android
| | `-- gbl_aarch64.efi // Android GBL
| |-- debian
| | |-- BOOTAA64.CSV // GRUB
| | |-- fbaa64.efi // GRUB
| | |-- grub.cfg // GRUB
| | |-- grubaa64.efi // GRUB: EFI app
| | |-- mmaa64.efi // GRUB
| | `-- shimaa64.efi // GRUB
| |-- firmware
| | `-- ldfw.bin // Exynos loadable firmware
| |-- systemd
| `-- systemd-bootaa64.efi // systemd-boot
|-- loader
| |-- entries
| | |-- debian.conf // systemd-boot (created manually)
| | `-- grub.conf // systemd-boot (created manually)
| |-- entries.srel // systemd-boot
| |-- loader.conf // systemd-boot (modified manually)
| `-- random-seed // systemd-boot
`-- ubootefi.var // EFI variables (created by U-Boot)
A simple way to start is to copy only 3 files to the ESP:
/EFI/firmware/ldfw.bin/EFI/Linux/Image/EFI/Linux/exynos850-e850-96.dtb
and then run the Linux kernel image (/EFI/Linux/Image) using U-Boot’s
efi_mgr boot method, supplying "root=/dev/mmcblk0p2" kernel param to
mount Debian rootfs from eMMC. Once in Debian shell, it should be easy to
install and configure other bootloaders (like GRUB, systemd-boot, etc.) in ESP.
Once the image with desired files is prepared, it can be flashed to eMMC as described in Flashing Linux Images.
Loadable Firmware
For the E850-96 system to function properly, loadable firmware (LDFW) has to be loaded using an SMC call to the EL3 monitor. It’s needed for both bootloader and kernel, as it makes features like TRNG (true random number generator) functional. U-Boot looks for this firmware on ESP partition, where it should be present at this path:
/EFI/firmware/ldfw.bin
If LDFW binary is present at that location, U-Boot will read and load it during its initialization stage. LDFW binary can be obtained from E850-96 images repository [7].
In case of booting from a media different than eMMC, the location of LDFW can
be specified using $bootdev* environment variables. The details are
discussed in Booting from USB Flash Drive.
Ethernet and USB Host Support
Warning
With changes suggested in this section, all USB gadget functionality (like fastboot and DFU) will be disabled in U-Boot. This won’t affect the dynamic role switching later in the Linux kernel, as a separate (different) device tree blob is provided to the kernel.
E850-96 has only one USB controller, so it can only work in one role at a time: either USB peripheral, or USB host role. It makes it impossible to use both host ports and the device (micro-USB) port simultaneously. Also, the Ethernet bridge chip (LAN9514) is controlled by the USB host bus, so USB host mode has to be enabled to make Ethernet functional. U-Boot doesn’t support dynamic USB role switching, so in order to enable USB host and Ethernet support, U-Boot’s device tree has to be modified accordingly. And then the micro-USB cable has to be disconnected to make the board circuitry switch the USB lines to a correct USB connector.
By default U-Boot configures the USB controller in peripheral mode. To enable USB host mode, do the following two things:
Modify
dts/upstream/src/arm64/exynos/exynos850-e850-96.dtsfile like this:&usbdrd_dwc3 { - dr_mode = "otg"; + dr_mode = "host"; usb-role-switch; role-switch-default-mode = "host";
Rebuild and flash the updated U-Boot binary.
Disconnect the micro-USB cable from the board.
To re-enable USB peripheral mode, just revert the above changes.