[PATCH v2 10/10] doc: falcon: Describe booting the OS through TF-A

Alexey Charkov <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
Falcon Mode documentation only covers SPL entering the kernel itself, which
is not what happens on ARM64 SoCs needing ARM Trusted Firmware resident to
provide firmware services: SPL loads a FIT holding BL31 as its firmware
image and the kernel as a loadable, and BL31 enters the kernel as BL33.

Describe that flow, what the kernel image may be given that neither
booti_setup() nor bootz_setup() runs, how it differs from the classic flow,
and how to configure and build it on Rockchip.

Signed-off-by: Alexey Charkov <[email protected]>
---
 doc/board/rockchip/rockchip.rst |   9 +++
 doc/develop/falcon.rst          | 131 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/doc/board/rockchip/rockchip.rst b/doc/board/rockchip/rockchip.rst
index de2df3046e28..42c47c51036f 100644
--- a/doc/board/rockchip/rockchip.rst
+++ b/doc/board/rockchip/rockchip.rst
@@ -325,6 +325,15 @@ To build rk3588 boards:
         make evb-rk3588_defconfig
         make CROSS_COMPILE=aarch64-linux-gnu-
 
+Falcon mode
+"""""""""""
+
+ARM64 Rockchip SoCs can also boot Linux straight from SPL through TF-A,
+without U-Boot proper running at all. Enabling CONFIG_ROCKCHIP_FALCON_IMAGE
+makes binman build a ``u-boot-rockchip-falcon.itb`` holding TF-A, the kernel
+and an optional initramfs, which are passed in with LINUX_KERNEL and
+LINUX_INITRD. See :doc:`../../develop/falcon` for the details.
+
 Flashing
 --------
 
diff --git a/doc/develop/falcon.rst b/doc/develop/falcon.rst
index 3fc23f65c458..f29aaee06a10 100644
--- a/doc/develop/falcon.rst
+++ b/doc/develop/falcon.rst
@@ -95,11 +95,138 @@ Function that a board must implement
 ------------------------------------
 
 void spl_board_prepare_for_linux(void)
-    optional, called from SPL before starting the kernel
+    optional, called from SPL before starting the kernel. Not called when the
+    kernel is entered through TF-A, see `Falcon Mode with TF-A`_; use
+    spl_board_prepare_for_boot() instead, which is called on every path.
 
 spl_start_uboot()
     required, returns "0" if SPL should start the kernel, "1" if U-Boot
-    must be started.
+    must be started. It may be called from more than one place in a single
+    SPL run, so prefer spl_falcon_boot() when querying the result - that
+    caches the answer, which matters for implementations that are not
+    idempotent, such as those sampling a button.
+
+Falcon Mode with TF-A
+---------------------
+
+On ARM64 SoCs which need ARM Trusted Firmware resident to provide firmware
+services to the OS, the kernel cannot usefully be entered directly from SPL.
+Instead SPL loads a FIT holding BL31 as its ``firmware`` image and the kernel
+as a ``loadable``, hands control to BL31, and BL31 enters the kernel as BL33.
+
+SPL picks BL33 in spl_invoke_atf(), which looks for an image with
+``os = "linux"`` in the ``/fit-images`` node it appended to the device tree
+and falls back to ``os = "u-boot"``. The kernel is entered at EL2 with the
+device tree address in x0, as the arm64 boot protocol requires.
+
+Nothing generates a FIT holding both an OS and a U-Boot payload, so the two
+are separate images, and it is the loader which decides where to read from.
+In Falcon mode it tries the OS image first and falls back to the U-Boot one
+if that cannot be loaded, unless secure Falcon mode is in effect, in which
+case there is no fallback. For UFS the two are addressed by
+CONFIG_SPL_UFS_RAW_OS_DEVNUM and CONFIG_SPL_UFS_RAW_OS_SECTOR against
+CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM and CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR, so
+they can live on different logical units, at different offsets, or both.
+spl_invoke_atf() then hands over to whichever of the two actually loaded,
+which is what makes that fallback work.
+
+Pointing both at one location is also possible, and is what the defaults do:
+only one region then has to be reserved, at the cost of having nothing left
+to fall back to.
+
+What the kernel image may be
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The payload is an ordinary FIT image node with ``type = "kernel"`` and
+``os = "linux"``. SPL copies it to its ``load`` address, and BL31 enters it
+at ``entry``, or at ``load`` if no entry point is given.
+
+Neither booti_setup() nor bootz_setup() runs in this flow - SPL does not
+enter the kernel itself, it only places it in memory for BL31 - so there is
+no inspection of the arm64 Image header and no relocation to the text offset
+the kernel asks for. The addresses in the FIT have to be directly usable,
+which for an arm64 ``Image`` means 2 MiB aligned, and clear of the device
+tree, of the initramfs and of every region BL31 and OP-TEE are linked to run
+from - each of those is split into several regions when it is supplied as an
+ELF, rather than occupying one contiguous range.
+
+The image is loaded verbatim unless CONFIG_SPL_GZIP or CONFIG_SPL_LZMA is
+enabled, in which case the FIT ``compression`` property may be set to
+``gzip`` or ``lzma`` and SPL decompresses while loading. Two limits apply
+then. The uncompressed image has to fit in CONFIG_SYS_BOOTM_LEN. And the
+compressed one is first staged at CONFIG_SYS_LOAD_ADDR, so that address has
+to clear both the region being decompressed to and, when the FIT is itself
+already in memory, the FIT: booting from RAM reads the image out of DRAM at
+CONFIG_SPL_LOAD_FIT_ADDRESS, and a staging buffer landing inside it makes
+the copy overwrite its own source, which shows up as::
+
+    ## Checking hash(es) for Image kernel ... sha256 error!
+
+The device trees in the FIT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each device tree in the FIT can be pre-patched at build time with a
+``/chosen`` node holding the kernel command line and the initramfs location,
+so that nothing has to fix them up before boot. See the ``fit,bootargs`` and
+``fit,initrd`` properties of binman's :ref:`etype_fit`.
+
+Differences from the classic flow
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* The device tree comes from the same FIT as the kernel, so no separate
+  'args' file is involved and CONFIG_SPL_OS_BOOT_ARGS is not needed.
+
+* CONFIG_SPL_BOOTI provides an entry path which is unused here.
+
+* Because U-Boot proper is never loaded in this flow, SPL panics rather than
+  jumping to CONFIG_TEXT_BASE if neither a kernel nor a U-Boot image can be
+  resolved from the FIT.
+
+Neither of the first two defaults to y when CONFIG_SPL_ATF is enabled, so
+nothing has to be turned off by hand.
+
+Example: Rockchip RK3576
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set the following in the board defconfig::
+
+        CONFIG_SPL_OS_BOOT=y
+        CONFIG_ROCKCHIP_FALCON_IMAGE=y
+
+On a board whose SPL can load from SPI flash, CONFIG_SYS_SPI_KERNEL_OFFS
+becomes visible and has no default, so give it a value suiting the flash
+layout even if the kernel is loaded from elsewhere. The load addresses of
+the kernel, device tree and initramfs default to offsets from the start of
+DRAM which clear BL31 and OP-TEE, and can be adjusted with
+CONFIG_ROCKCHIP_FALCON_KERNEL_LOAD and friends.
+
+Enabling CONFIG_SPL_LZMA or CONFIG_SPL_GZIP additionally compresses the
+kernel in the image, trading some decompression time for a smaller one - for
+a 30 MiB arm64 Image, roughly 35% of the original with LZMA and 39% with
+gzip. Note that this compresses U-Boot itself as well, since both use the
+same setting.
+
+The kernel and, optionally, an initramfs are passed in at build time::
+
+        $ make BL31=.../bl31.elf \
+               ROCKCHIP_TPL=.../rk3576_ddr_lp4_2112MHz_lp5_2736MHz_v1.13.bin \
+               LINUX_KERNEL=.../Image \
+               LINUX_INITRD=.../ramdisk.cpio.zst
+
+This produces ``u-boot-rockchip-falcon.itb``, to be written at
+CONFIG_SPL_UFS_RAW_OS_SECTOR (or the equivalent for the boot medium in use).
+Its default shares the region with U-Boot, which suits Falcon-only boot;
+point it elsewhere to keep a U-Boot image to fall back to.
+
+With CONFIG_ROCKCHIP_MASKROM_IMAGE enabled, an equivalent maskrom payload
+``u-boot-rockchip-usb472-falcon.bin`` is built as well, which can be loaded
+straight into RAM::
+
+        rockusb download-sram u-boot-rockchip-usb471.bin
+        rockusb download-ddr u-boot-rockchip-usb472-falcon.bin
+
+Rockchip attempts Falcon Mode boot whenever it is enabled. Boards which need
+a runtime choice override board_spl_start_uboot().
 
 Environment variables
 ---------------------

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.