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
