On Wed, Jul 7, 2021 at 12:06 PM Stephan Gerhold <[email protected]> wrote: > > At the moment the U-Boot port for the DragonBoard 410c is designed > to be loaded as an Android boot image after Qualcomm's Little Kernel (LK) > bootloader. This is simple to set up but LK is redundant in this case, > since everything done by LK can be also done directly by U-Boot. > > Dropping LK entirely has at least the following advantages: > - Easier installation/board code (no need for Android boot images) > - (Slightly) faster boot > - Boot directly in 64-bit without a round trip to 32-bit for LK > > So far this was not possible yet because of unsolved problems: > > 1. Signing tool: The firmware expects a "signed" ELF image with extra > (Qualcomm-specific) ELF headers, usually used for secure boot. > The DragonBoard 410c does not have secure boot by default but the > extra ELF headers are still required. > > 2. PSCI bug: There seems to be a bug in the PSCI implementation > (part of the TrustZone/tz firmware) that causes all other CPU cores > to be started in 32-bit mode if LK is missing in the boot chain. > This causes Linux to hang early during boot. > > There is a solution for both problems now: > > 1. qtestsign (https://github.com/msm8916-mainline/qtestsign) > can be used as a "signing" tool for U-Boot and other firmware. > > 2. A workaround for the "PSCI bug" is to execute the TZ syscall when > entering U-Boot. That way PSCI is made aware of the 64-bit switch > and starts all other CPU cores in 64-bit mode as well. > > Simplify the dragonboard410c board by removing all the extra code that > is only used to build an Android boot image that can be loaded by LK. > This allows dropping the custom linker script, special image magic, > as well as most of the special build/installation instructions. > > CONFIG_REMAKE_ELF is used to build a new ELF image that has both U-Boot > and the appended DTB combined. The resulting u-boot.elf can then be > passed to the "signing" tool (e.g. qtestsign). > > The PSCI workaround is placed in the "boot0" hook that is enabled > with CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK. The extra check for EL1 allows > compatibility with custom firmware that enters U-Boot in EL2 or EL3, > e.g. qhypstub (https://github.com/msm8916-mainline/qhypstub). > > As a first step these changes apply only to DragonBoard410c. > Similar changes could likely also work for the DragonBoard 820c. > > Note that removing LK wouldn't be possible that easily without a lot of > work already done three years ago by Ramon Fried. A lot of missing > initialization, pinctrl etc was already added back then even though > it was not strictly needed yet. > > Cc: Ramon Fried <[email protected]> > Signed-off-by: Stephan Gerhold <[email protected]> > --- > > Related RFC with even more detailed explanations: > https://lore.kernel.org/u-boot/[email protected]/ > > In my tests both U-Boot and Linux are fully functional with this patch. > However, I would appreciate further testing, since my testing does > likely not represent a typical usage scenario for the DragonBoard 410c. > > When testing, please pick the following pending patch additionally: > https://lore.kernel.org/u-boot/[email protected]/ > on top of u-boot/master. > > --- > arch/arm/mach-snapdragon/Kconfig | 1 + > arch/arm/mach-snapdragon/include/mach/boot0.h | 54 ++++++++ > board/qualcomm/dragonboard410c/MAINTAINERS | 1 + > board/qualcomm/dragonboard410c/Makefile | 2 - > .../dragonboard410c/dragonboard410c.c | 13 -- > board/qualcomm/dragonboard410c/head.S | 33 ----- > .../qualcomm/dragonboard410c/lowlevel_init.S | 27 ---- > board/qualcomm/dragonboard410c/readme.txt | 73 +---------- > board/qualcomm/dragonboard410c/u-boot.lds | 118 ------------------ > configs/dragonboard410c_defconfig | 2 +- > doc/board/index.rst | 1 + > doc/board/qualcomm/dragonboard410c.rst | 45 +++++++ > doc/board/qualcomm/index.rst | 9 ++ > include/configs/dragonboard410c.h | 3 + > 14 files changed, 120 insertions(+), 262 deletions(-) > create mode 100644 arch/arm/mach-snapdragon/include/mach/boot0.h > delete mode 100644 board/qualcomm/dragonboard410c/head.S > delete mode 100644 board/qualcomm/dragonboard410c/lowlevel_init.S > delete mode 100644 board/qualcomm/dragonboard410c/u-boot.lds > create mode 100644 doc/board/qualcomm/dragonboard410c.rst > create mode 100644 doc/board/qualcomm/index.rst > > diff --git a/arch/arm/mach-snapdragon/Kconfig > b/arch/arm/mach-snapdragon/Kconfig > index e562d693c6..0ec74fa5d3 100644 > --- a/arch/arm/mach-snapdragon/Kconfig > +++ b/arch/arm/mach-snapdragon/Kconfig > @@ -15,6 +15,7 @@ choice > config TARGET_DRAGONBOARD410C > bool "96Boards Dragonboard 410C" > select BOARD_LATE_INIT > + select ENABLE_ARM_SOC_BOOT0_HOOK > help > Support for 96Boards Dragonboard 410C. This board complies with > 96Board Open Platform Specifications. Features: > diff --git a/arch/arm/mach-snapdragon/include/mach/boot0.h > b/arch/arm/mach-snapdragon/include/mach/boot0.h > new file mode 100644 > index 0000000000..953cccad79 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/include/mach/boot0.h > @@ -0,0 +1,54 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Workaround for "PSCI bug" on DragonBoard 410c > + * Copyright (C) 2021 Stephan Gerhold <[email protected]> > + * > + * Syscall parameters taken from Qualcomm's LK fork (scm.h): > + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. > + * > + * The PSCI implementation in the TrustZone/tz firmware on DragonBoard 410c > has > + * a bug that starts all other CPU cores in 32-bit mode unless the TZ syscall > + * that switches from 32-bit to 64-bit mode is executed at least once. > + * > + * Normally this happens inside Qualcomm's LK bootloader which runs in 32-bit > + * mode and uses the TZ syscall to boot a kernel in 64-bit mode. However, if > + * U-Boot is installed to the "aboot" partition (replacing LK) the switch to > + * 64-bit mode never happens since U-Boot is already running in 64-bit mode. > + * > + * A workaround for this "PSCI bug" is to execute the TZ syscall when > entering > + * U-Boot. That way PSCI is made aware of the 64-bit switch and starts all > other > + * CPU cores in 64-bit mode as well. > + */ > +#include <linux/arm-smccc.h> > + > +#define ARM_SMCCC_SIP32_FAST_CALL \ > + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, > ARM_SMCCC_OWNER_SIP, 0) > + > + /* > + * U-Boot might be started in EL2 or EL3 with custom firmware. > + * In that case, we assume that the workaround is not necessary or is > + * handled already by the alternative firmware. Using the syscall in > EL2 > + * would demote U-Boot to EL1; in EL3 it would probably just crash. > + */ > + mrs x0, CurrentEL > + cmp x0, #(1 << 2) /* EL1 */ > + bne reset > + > + /* Prepare TZ syscall parameters */ > + mov x0, #ARM_SMCCC_SIP32_FAST_CALL > + movk x0, #0x10f /* SCM_SVC_MILESTONE_CMD_ID */ > + mov x1, #0x12 /* MAKE_SCM_ARGS(0x2, > SMC_PARAM_TYPE_BUFFER_READ) */ > + adr x2, el1_system_param > + mov x3, el1_system_param_end - el1_system_param > + > + /* Switch PSCI to 64-bit mode. Resets CPU and returns at el1_elr */ > + smc #0 > + > + /* Something went wrong, perhaps PSCI is already in 64-bit mode? */ > + b reset > + > + .align 3 > +el1_system_param: > + .quad 0, 0, 0, 0, 0, 0, 0, 0, 0 /* el1_x0-x8 */ > + .quad reset /* el1_elr */ > +el1_system_param_end: > diff --git a/board/qualcomm/dragonboard410c/MAINTAINERS > b/board/qualcomm/dragonboard410c/MAINTAINERS > index 83448f5c13..e78f5b2d64 100644 > --- a/board/qualcomm/dragonboard410c/MAINTAINERS > +++ b/board/qualcomm/dragonboard410c/MAINTAINERS > @@ -4,3 +4,4 @@ S: Maintained > F: board/qualcomm/dragonboard410c/ > F: include/configs/dragonboard410c.h > F: configs/dragonboard410c_defconfig > +F: doc/board/qualcomm/dragonboard410c.rst > diff --git a/board/qualcomm/dragonboard410c/Makefile > b/board/qualcomm/dragonboard410c/Makefile > index 9b452041f4..1b99c8b0ef 100644 > --- a/board/qualcomm/dragonboard410c/Makefile > +++ b/board/qualcomm/dragonboard410c/Makefile > @@ -3,5 +3,3 @@ > # (C) Copyright 2015 Mateusz Kulikowski <[email protected]> > > obj-y := dragonboard410c.o > -obj-y += lowlevel_init.o > -extra-y += head.o > diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c > b/board/qualcomm/dragonboard410c/dragonboard410c.c > index 0d282de958..3b71881cac 100644 > --- a/board/qualcomm/dragonboard410c/dragonboard410c.c > +++ b/board/qualcomm/dragonboard410c/dragonboard410c.c > @@ -22,19 +22,6 @@ > > DECLARE_GLOBAL_DATA_PTR; > > -/* pointer to the device tree ammended by the firmware */ > -extern void *fw_dtb; > - > -void *board_fdt_blob_setup(void) > -{ > - if (fdt_magic(fw_dtb) != FDT_MAGIC) { > - printf("Firmware provided invalid dtb!\n"); > - return NULL; > - } > - > - return fw_dtb; > -} > - > int dram_init(void) > { > gd->ram_size = PHYS_SDRAM_1_SIZE; > diff --git a/board/qualcomm/dragonboard410c/head.S > b/board/qualcomm/dragonboard410c/head.S > deleted file mode 100644 > index 33e9d305f9..0000000000 > --- a/board/qualcomm/dragonboard410c/head.S > +++ /dev/null > @@ -1,33 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0+ */ > -/* > - * ARM64 header for proper chain-loading with Little Kernel. > - * > - * Little Kernel shipped with Dragonboard410C boots standard Linux images for > - * ARM64. This file adds header that is required to boot U-Boot properly. > - * > - * For details see: > - * https://www.kernel.org/doc/Documentation/arm64/booting.txt > - * > - * (C) Copyright 2015 Mateusz Kulikowski <[email protected]> > - */ > - > -#include <config.h> > - > -.global _arm64_header > -_arm64_header: > - b _start > - .word 0 > - /* Image load offset from start of RAM, little-endian */ > - .quad CONFIG_SYS_TEXT_BASE-PHYS_SDRAM_1 > - /* Effective size of kernel image, little-endian */ > - .quad 0 /* 0x60000 - ignored */ > - /* Informative flags, little-endian */ > - .quad 0 > - .quad 0 /* reserved */ > - .quad 0 /* reserved */ > - .quad 0 /* reserved */ > - .byte 0x41 /* Magic number, "ARM\x64" */ > - .byte 0x52 > - .byte 0x4d > - .byte 0x64 > - .word 0 /* reserved */ > diff --git a/board/qualcomm/dragonboard410c/lowlevel_init.S > b/board/qualcomm/dragonboard410c/lowlevel_init.S > deleted file mode 100644 > index 762fed5617..0000000000 > --- a/board/qualcomm/dragonboard410c/lowlevel_init.S > +++ /dev/null > @@ -1,27 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0+ */ > -/* > - * (C) Copyright 2016 > - * Cédric Schieli <[email protected]> > - */ > - > -#include <config.h> > - > -.align 8 > -.global fw_dtb > -fw_dtb: > - .dword 0x0 > - > -/* > - * Routine: save_boot_params (called after reset from start.S) > - * Description: save ATAG/FDT address provided by the firmware at boot time > - */ > - > -.global save_boot_params > -save_boot_params: > - > - /* The firmware provided ATAG/FDT address can be found in r2/x0 */ > - adr x8, fw_dtb > - str x0, [x8] > - > - /* Returns */ > - b save_boot_params_ret > diff --git a/board/qualcomm/dragonboard410c/readme.txt > b/board/qualcomm/dragonboard410c/readme.txt > index a90d0f52e7..dfdb299fb7 100644 > --- a/board/qualcomm/dragonboard410c/readme.txt > +++ b/board/qualcomm/dragonboard410c/readme.txt > @@ -1,69 +1,6 @@ > -# SPDX-License-Identifier: GPL-2.0+ > -# > -# (C) Copyright 2015 Mateusz Kulikowski <[email protected]> > +Documentation for DragonBoard 410c is now located at: > + doc/board/qualcomm/dragonboard410c.rst > > -Build & Run instructions: > - > -1) Install mkbootimg and dtbTool from > - git://codeaurora.org/quic/kernel/skales (15ece94f09 worked for me) > -2) Setup CROSS_COMPILE to aarch64 compiler > -3) make dragonboard410c_config > -4) make > -5) generate fake, empty ramdisk (can have 0 bytes) > -$ touch rd > - > -6) Generate qualcomm device tree table with dtbTool [1] > -$ dtbTool -o dt.img arch/arm/dts > - > -7) Generate Android boot image with mkbootimg [2]: > -$ mkbootimg --kernel=u-boot-dtb.bin --output=u-boot.img --dt=dt.img \ > - --pagesize 2048 --base 0x80000000 --ramdisk=rd --cmdline="" > - > -8) Enter fastboot (reboot board with vol- button pressed) > - > -9) Boot it: > -$ fastboot boot u-boot.img > -or flash as kernel: > -$ fastboot flash boot u-boot.img > -$ fastboot reboot > - > - > -What is working: > -- UART > -- GPIO (SoC) > -- SD > -- eMMC > -- Reset > -- USB in EHCI mode (usb starts does switch device->host, usb stop does the > opposite) > -- PMIC GPIOS (but not in generic subsystem) > -- PMIC "special" buttons (power, vol-) > - > -What is not working / known bugs: > -- SDHCI is slow (~2.5MiB/s for SD and eMMC) > - > -[1] To boot any kernel image, Little Kernel requires valid device tree for > the > -platform it runs on. dtbTool creates device tree table that Little Kernel > scans. > -Later on proper device tree is passed to next boot stage. > -Full device tree is not required to boot u-boot. Enough would be: > -/dts-v1/; > - > -/ { > - model = "Qualcomm Technologies, Inc. Dragonboard 410c"; > - compatible = "qcom,dragonboard", "qcom,apq8016-sbc"; > - qcom,msm-id = <0xce 0x0 0xf8 0x0 0xf9 0x0 0xfa 0x0 0xf7 0x0>; > - qcom,board-id = <0x10018 0x0>; > - #address-cells = <0x2>; > - #size-cells = <0x2>; > - chosen { }; > - aliases { }; > - > - memory { > - device_type = "memory"; > - reg = <0 0x80000000 0 0x3da00000>; > - }; > -}; > - > -but for simplicity (and because size of image is not that critical) we use > -existing Qualcomm device trees. > - > -[2] Note that ramdisk is required, even if it is unused. > +Note that the installation method has changed: U-Boot is now installed into > the > +"aboot" partition (replacing Little Kernel/LK). It is no longer packaged into > +an Android boot image and loaded through Qualcomm's LK bootloader. > diff --git a/board/qualcomm/dragonboard410c/u-boot.lds > b/board/qualcomm/dragonboard410c/u-boot.lds > deleted file mode 100644 > index fc1bba8cf0..0000000000 > --- a/board/qualcomm/dragonboard410c/u-boot.lds > +++ /dev/null > @@ -1,118 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0+ */ > -/* > - * Override linker script for fastboot-readable images > - * > - * (C) Copyright 2015 Mateusz Kulikowski <[email protected]> > - * > - * Based on arch/arm/cpu/armv8/u-boot.lds (Just add header) > - */ > - > -OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", > "elf64-littleaarch64") > -OUTPUT_ARCH(aarch64) > -ENTRY(_arm64_header) > -SECTIONS > -{ > - . = 0x00000000; > - > - . = ALIGN(8); > - .text : > - { > - *(.__image_copy_start) > - board/qualcomm/dragonboard410c/head.o (.text*) > - CPUDIR/start.o (.text*) > - } > - > - /* This needs to come before *(.text*) */ > - .efi_runtime : { > - __efi_runtime_start = .; > - *(.text.efi_runtime*) > - *(.rodata.efi_runtime*) > - *(.data.efi_runtime*) > - __efi_runtime_stop = .; > - } > - > - .text_rest : > - { > - *(.text*) > - } > - > - . = ALIGN(8); > - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } > - > - . = ALIGN(8); > - .data : { > - *(.data*) > - } > - > - . = ALIGN(8); > - > - . = .; > - > - . = ALIGN(8); > - .u_boot_list : { > - KEEP(*(SORT(.u_boot_list*))); > - } > - > - . = ALIGN(8); > - > - .efi_runtime : { > - __efi_runtime_start = .; > - *(efi_runtime_text) > - *(efi_runtime_data) > - __efi_runtime_stop = .; > - } > - > - .efi_runtime_rel : { > - __efi_runtime_rel_start = .; > - *(.rel*.efi_runtime) > - *(.rel*.efi_runtime.*) > - __efi_runtime_rel_stop = .; > - } > - > - . = ALIGN(8); > - > - .image_copy_end : > - { > - *(.__image_copy_end) > - } > - > - . = ALIGN(8); > - > - .rel_dyn_start : > - { > - *(.__rel_dyn_start) > - } > - > - .rela.dyn : { > - *(.rela*) > - } > - > - .rel_dyn_end : > - { > - *(.__rel_dyn_end) > - } > - > - _end = .; > - > - . = ALIGN(8); > - > - .bss_start : { > - KEEP(*(.__bss_start)); > - } > - > - .bss : { > - *(.bss*) > - . = ALIGN(8); > - } > - > - .bss_end : { > - KEEP(*(.__bss_end)); > - } > - > - /DISCARD/ : { *(.dynsym) } > - /DISCARD/ : { *(.dynstr*) } > - /DISCARD/ : { *(.dynamic*) } > - /DISCARD/ : { *(.plt*) } > - /DISCARD/ : { *(.interp*) } > - /DISCARD/ : { *(.gnu*) } > -} > diff --git a/configs/dragonboard410c_defconfig > b/configs/dragonboard410c_defconfig > index 7b7b32c0a2..dc9d0d893c 100644 > --- a/configs/dragonboard410c_defconfig > +++ b/configs/dragonboard410c_defconfig > @@ -1,6 +1,6 @@ > CONFIG_ARM=y > CONFIG_ARCH_SNAPDRAGON=y > -CONFIG_SYS_TEXT_BASE=0x80080000 > +CONFIG_SYS_TEXT_BASE=0x8f600000 > CONFIG_NR_DRAM_BANKS=1 > CONFIG_ENV_SIZE=0x2000 > CONFIG_ENV_OFFSET=0x0 > diff --git a/doc/board/index.rst b/doc/board/index.rst > index 196b597609..a6b395238a 100644 > --- a/doc/board/index.rst > +++ b/doc/board/index.rst > @@ -20,6 +20,7 @@ Board-specific doc > kontron/index > microchip/index > openpiton/index > + qualcomm/index > rockchip/index > sifive/index > sipeed/index > diff --git a/doc/board/qualcomm/dragonboard410c.rst > b/doc/board/qualcomm/dragonboard410c.rst > new file mode 100644 > index 0000000000..d0de9dbcbc > --- /dev/null > +++ b/doc/board/qualcomm/dragonboard410c.rst > @@ -0,0 +1,45 @@ > +.. SPDX-License-Identifier: GPL-2.0+ > +.. sectionauthor:: Stephan Gerhold <[email protected]> > + > +DragonBoard 410c > +================ > + > +The DragonBoard 410c is a development board based on the Qualcomm APQ8016E > SoC. > +More information can be found on the `96Boards product page`_. > + > +U-Boot can be used as a replacement for Qualcomm's original Android > bootloader > +(a fork of Little Kernel/LK). Like LK, it is installed directly into the > ``aboot`` > +partition. Note that the U-Boot port used to be loaded as an Android boot > image > +through LK. This is no longer the case, now U-Boot can replace LK entirely. > + > +.. _96Boards product page: https://www.96boards.org/product/dragonboard410c/ > + > +Installation > +------------ > +First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for > ``dragonboard410c``:: > + > + $ export CROSS_COMPILE=<aarch64 toolchain prefix> > + $ make dragonboard410c_defconfig > + $ make > + > +This will build ``u-boot.elf`` in the configured output directory. > + > +Although the DragonBoard 410c does not have secure boot set up by default, > +the firmware still expects firmware ELF images to be "signed". The signature > +does not provide any security in this case, but it provides the firmware with > +some required metadata. > + > +To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_:: > + > + $ ./qtestsign.py aboot u-boot.elf > + > +Then install the resulting ``u-boot-test-signed.mbn`` to the ``aboot`` > partition > +on your device, e.g. with ``fastboot flash aboot u-boot-test-signed.mbn``. > + > +U-Boot should be running after a reboot (``fastboot reboot``). > + > +.. _qtestsign: https://github.com/msm8916-mainline/qtestsign > + > +Usage > +----- > +Press Volume Down during boot to enter Fastboot mode. > diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst > new file mode 100644 > index 0000000000..f7e0aa9298 > --- /dev/null > +++ b/doc/board/qualcomm/index.rst > @@ -0,0 +1,9 @@ > +.. SPDX-License-Identifier: GPL-2.0+ > + > +Qualcomm > +======== > + > +.. toctree:: > + :maxdepth: 2 > + > + dragonboard410c > diff --git a/include/configs/dragonboard410c.h > b/include/configs/dragonboard410c.h > index 65537e4778..1f08508c4d 100644 > --- a/include/configs/dragonboard410c.h > +++ b/include/configs/dragonboard410c.h > @@ -11,6 +11,9 @@ > #include <linux/sizes.h> > #include <asm/arch/sysmap-apq8016.h> > > +/* Build new ELF image from u-boot.bin (U-Boot + appended DTB) */ > +#define CONFIG_REMAKE_ELF > + > /* Physical Memory Map */ > #define PHYS_SDRAM_1 0x80000000 > /* 1008 MB (the last ~30Mb are secured for TrustZone by ATF*/ > -- > 2.32.0 > Thanks Stephan, it looks very good. I started testing it, it builds correctly and I flashed and everything seems to work. I do have a problem with my TFTP setup, so I didn't boot Linux yet, but I will get to it, if it will boot successfully we can merge this one.
U-boot doesn't know how to boot qcom android kernel partitions, I'm not sure this is something I even want to start supporting in U-boot. Nico, do you think you can change the format of the BOOT partition to host a u-boot FIT image ? Thanks, Ramon

