.. SPDX-License-Identifier: GPL-2.0+ .. sectionauthor:: Sam Protsenko 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 :ref:`Figure 1 `. .. _figure1: .. kernel-figure:: img/exynos850-boot-architecture.svg :align: center Figure 1: Exynos850 SoC boot architecture Legend: * ``BL0``: Boot ROM code * ``BL1``: Software part of Boot ROM * ``EPBL``: Exynos Primary Boot Loader * ``BL2``: Initializes CMU and DRAM and runs the final bootloader * ``Bootloader``: The final bootloader (e.g. U-Boot); it's also called BL33 in terms of ARM boot flow * ``EL3_MON``: EL3 monitor (trusted firmware, handles SMC calls); it's also called BL31 in terms of ARM boot flow * ``LDFW``: 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 :ref:`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. :ref:`Table 1 ` shows how the boot source can be configured using the SW1. .. _table1: .. table:: Table 1: Boot device configuration using the SW1 DIP switch ======================== ======================= 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): .. prompt:: bash $ export PATH=/bin:$PATH export CROSS_COMPILE= 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: .. prompt:: bash $ 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: .. prompt:: bash => env default -f -a env save .. _flashing-linux-label: Flashing Linux Images --------------------- The Linux partition table contains only two partitions: 1. ``esp`` (EFI System Partition) 2. ``rootfs`` Format eMMC to have Linux partition table (using the default ``$partitions`` definitions): .. prompt:: bash => gpt write mmc 0 $partitions ...or do the same using fastboot: .. prompt:: bash $ fastboot oem format Enter fastboot mode on your device: .. prompt:: bash => fastboot usb 0 And then flash the images: .. prompt:: bash $ fastboot flash esp esp.img fastboot flash rootfs rootfs.img .. _flashing-android-label: Flashing Android Images ----------------------- Use ``$partitions_android`` as current partition definitions: .. prompt:: bash => setenv partitions_linux $partitions setenv partitions $partitions_android env save Format eMMC to have Android partition table: .. prompt:: bash => gpt write mmc 0 $partitions ...or do the same using fastboot: .. prompt:: bash $ 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 :ref:`booting-android-gbl-label` section for details. But first the ESP image containing the GBL app has to be flashed. Enter fastboot mode on your device: .. prompt:: bash => fastboot usb 0 And flash the ESP image: .. prompt:: bash $ 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 :ref:`booting-label` 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: .. prompt:: bash $ ./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: .. prompt:: bash => dfu 0 mmc 0 To update U-Boot via DFU: .. prompt:: bash $ 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.: .. code-block:: bash # $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: .. prompt:: bash $ 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: 1. Generate the "capsule" file for the desired bootloader binary 2. Copy this capsule file to a particular location in ESP partition 3. Reboot the board U-Boot will handle it automatically, using the next procedure: 1. Locate the capsule file and update the corresponding bootloader 2. Remove the capsule file from ESP after updating 3. 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 :ref:`Table 2 ` below. .. _table2: .. table:: Table 2: Image indexes and GUIDs for Capsule Update =========== ========== ======================================== Image index Image name GUID =========== ========== ======================================== 1 fwbl1 ``181cd3f2-e375-44d2-8078-3221e1dfb95e`` 2 epbl ``66c1a54d-d149-415d-aada-b8aee499b370`` 3 bl2 ``89471c2a-6c8d-4158-acad-23d3b2873d35`` 4 bootloader ``629578c3-ffb3-4a89-ac0c-611840727779`` 5 el3_mon ``df5718a2-930a-4916-bb19-3213214d8486`` =========== ========== ======================================== 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: .. prompt:: bash $ ./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-label: Booting Overview ---------------- OS booting is performed using a U-Boot mechanism called :doc:`/develop/bootstd/index`. 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 :ref:`esp-label` 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: .. prompt:: bash => 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 ``esp`` and ``rootfs`` partitions are bootable * Android: only ``esp`` is bootable Next boot methods are currently enabled in E850-86 U-Boot: .. _table3: .. table:: Table 3: Standard Boot methods ======== =============================================================== Method Description ======== =============================================================== efi_mgr EFI boot manager flow (booting using ``Boot*`` EFI variables) efi EFI boot from ``/EFI/BOOT/BOOTAA64.EFI`` file extlinux Booting using ``/boot/extlinux/extlinux.conf`` file from rootfs script Booting using ``/boot/boot.scr`` U-Boot script from rootfs 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 :doc:`/develop/bootstd/overview` documentation. .. _booting-efi-mgr-label: 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: .. prompt:: bash => eficonfig Add GRUB EFI app to the boot list, and make it the highest priority boot source: 1. Select "Add Boot Option" menu item 2. Set "Description:" to "GRUB" 3. Press "File:" -> "Select File" -> "mmc 0:1", and select the GRUB EFI app (e.g. ``/EFI\debian\grubaa64.efi``) 4. The created entry should look like this:: Description: GRUB File: mmc 0:1/EFI\debian\grubaa64.efi 5. Press "Save" 6. Press "Change Boot Order" and move the "GRUB" item on the top (using "+" key) 7. Press "Save" 8. 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): .. prompt:: bash => 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): .. prompt:: bash => 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: .. code-block:: bash 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: .. prompt:: bash $ 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-13 where ``'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 is ``02-36-f5-1c-81-13``, and it can be looked up in the ``$ethaddr`` environment 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=dhcp * If it's desired to mount the rootfs over NFS (instead of mounting it from eMMC or using an ``initrd`` ramdisk) -- 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: 1. First, make sure to enable USB host mode in U-Boot, as discussed in :ref:`usb-host-label` section 2. 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 3. Select and boot it: .. prompt:: bash => 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-label: 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 number * ``bootdevpart``: 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: .. prompt:: bash => 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: 1. First, make sure to enable USB host mode in U-Boot, as discussed in :ref:`usb-host-label` section 2. Format your USB stick to follow the ``$partitions`` layout:: 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 proceed 3. Copy Debian rootfs and ESP to your USB flash drive: .. prompt:: bash # dd if=esp.img of=/dev/sdX1 bs=64M dd if=rootfs.img of=/dev/sdX2 bs=64M status=progress 4. Insert the prepared USB media into the E850-96 USB port 5. Tell U-Boot to search for LDFW firmware on USB stick: .. prompt:: bash => setenv bootdev usb env save 6. Erase eMMC partition table to make U-Boot use ESP from USB drive: .. prompt:: bash => mmc dev 0 mmc erase 0 0x2400 reset 7. Make sure ``'bootflow scan -l'`` is able to detect boot methods on your USB stick 8. Setup EFI variables (using ``eficonfig`` command) for booting from USB stick with ``efi_mgr`` boot method, as described in :ref:`booting-label` section Now U-Boot will be able to boot the OS from the USB drive using Standard Boot. .. _booting-android-gbl-label: 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_PROTOCOL`` * ``ANDROID: [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: .. prompt:: bash $ 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: .. prompt:: bash $ 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 :ref:`booting-efi-mgr-label` section, and run ``efi_mgr`` boot method: .. prompt:: bash => 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 :ref:`flashing-android-label` section). 1. Press Backspace to enter GBL's fastboot mode. Flash E850-96 Android images as described in corresponding documentation. 2. 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]_. .. _esp-label: 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: .. prompt:: bash $ 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 :ref:`loadable-firmware-label` 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 :ref:`flashing-linux-label`. .. _loadable-firmware-label: 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 :ref:`booting-from-usb-label`. .. _usb-host-label: 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: 1. Modify ``dts/upstream/src/arm64/exynos/exynos850-e850-96.dts`` file like this: .. code-block:: diff &usbdrd_dwc3 { - dr_mode = "otg"; + dr_mode = "host"; usb-role-switch; role-switch-default-mode = "host"; Rebuild and flash the updated U-Boot binary. 2. Disconnect the micro-USB cable from the board. To re-enable USB peripheral mode, just revert the above changes. References ---------- .. [1] https://www.96boards.org/product/e850-96b/ .. [2] https://www.96boards.org/products/ce/ .. [3] https://www.96boards.org/products/mezzanine/ .. [4] https://www.96boards.org/documentation/consumer/e850-96b/hardware-docs/ .. [5] https://gitlab.com/Linaro/96boards/e850-96/ .. [6] https://gitlab.com/Linaro/96boards/e850-96/lk .. [7] https://gitlab.com/LinaroLtd/e850-96/images.git .. [8] https://gitlab.com/LinaroLtd/e850-96/tools/dltool.git .. [9] https://gitlab.com/Linaro/96boards/e850-96/doc .. [10] https://source.android.com/docs/core/architecture/bootloader/generic-bootloader .. [11] https://www.arm.com/architecture/system-architectures/systemready-compliance-program/systemready-devicetree-band .. [12] https://third-party-mirror.googlesource.com/u-boot/+log/refs/heads/vim3 .. [13] https://source.devboardsforandroid.linaro.org/platform/external/u-boot/+log/refs/heads/wip/sm8x50-gbl-fastboot .. [14] https://source.android.com/docs/core/architecture/bootloader/generic-bootloader/gbl-dev .. [15] https://source.devboardsforandroid.linaro.org/platform/manifest/