From 79d89e3da078fa0e169a47bcc360c5e3308cdf42 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 7 Sep 2020 14:53:58 +0100 Subject: [PATCH 1/8] drivers: arm: gicv3: Allow detecting number of cores A GICv3 interrupt controller will be instantiated for a certain number of cores. This will result in the respective number of GICR frames. The last frame will have the "Last" bit set in its GICR_TYPER register. For platforms with a topology unknown at build time (the Arm FPGAs, for instance), we need to learn the number of used cores at runtime, to size the GICR region in the devicetree accordingly. Add a generic function that iterates over all GICR frames until it encounters one with the "Last" bit set. It returns the number of cores the GICv3 has been configured for. Change-Id: I79f033c50dfc1c275aba7122725868811abcc4f8 Signed-off-by: Andre Przywara --- drivers/arm/gic/v3/gicv3_helpers.c | 30 ++++++++++++++++++++++++++++++ include/drivers/arm/gicv3.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 09fa6786e..ff346f9df 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -326,3 +326,33 @@ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, return ctlr_enable; } + +/** + * gicv3_rdistif_get_number_frames() - determine size of GICv3 GICR region + * @gicr_frame: base address of the GICR region to check + * + * This iterates over the GICR_TYPER registers of multiple GICR frames in + * a GICR region, to find the instance which has the LAST bit set. For most + * systems this corresponds to the number of cores handled by a redistributor, + * but there could be disabled cores among them. + * It assumes that each GICR region is fully accessible (till the LAST bit + * marks the end of the region). + * If a platform has multiple GICR regions, this function would need to be + * called multiple times, providing the respective GICR base address each time. + * + * Return: number of valid GICR frames (at least 1, up to PLATFORM_CORE_COUNT) + ******************************************************************************/ +unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame) +{ + uintptr_t rdistif_base = gicr_frame; + unsigned int count; + + for (count = 1; count < PLATFORM_CORE_COUNT; count++) { + if ((gicr_read_typer(rdistif_base) & TYPER_LAST_BIT) != 0U) { + break; + } + rdistif_base += (1U << GICR_PCPUBASE_SHIFT); + } + + return count; +} diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index 18d5b73e2..d8ac4cb33 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -488,6 +488,7 @@ void gicv3_distif_init(void); void gicv3_rdistif_init(unsigned int proc_num); void gicv3_rdistif_on(unsigned int proc_num); void gicv3_rdistif_off(unsigned int proc_num); +unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame); void gicv3_cpuif_enable(unsigned int proc_num); void gicv3_cpuif_disable(unsigned int proc_num); unsigned int gicv3_get_pending_interrupt_type(void); From 9f7bab42a103a44246116d89a3cca20ed935467c Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 24 Aug 2020 18:28:44 +0100 Subject: [PATCH 2/8] fdt: Add function to adjust GICv3 redistributor size We now have code to detect the CPU topology at runtime, and can also populate the CPU nodes in a devicetree accordingly. This is used by the ARM FPGA port, for instance. But also a GICv3 compatible interrupt controller provides MMIO frames per core, so the size of this region needs to be adjusted in the DT, to match the number of cores as well. Provide a generic function to find the GICv3 interrupt controller in the DT, then adjust the "reg" entry to match the number of detected cores. Since the size of the GICR frame per cores differs between GICv4 and GICv3, this size is supplied as a parameter to the function. The caller should determine the applicable value by either hardcoding it or by observing GICR_TYPER.VLPIS. Change-Id: Ic2a6445c2c5381a36bf24263f52fcbefad378c05 Signed-off-by: Andre Przywara --- common/fdt_fixup.c | 61 ++++++++++++++++++++++++++++++++++++++ include/common/fdt_fixup.h | 2 ++ 2 files changed, 63 insertions(+) diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c index 980e60d45..a1604e74f 100644 --- a/common/fdt_fixup.c +++ b/common/fdt_fixup.c @@ -377,3 +377,64 @@ int fdt_add_cpus_node(void *dtb, unsigned int afflv0, return offs; } + +/** + * fdt_adjust_gic_redist() - Adjust GICv3 redistributor size + * @dtb: Pointer to the DT blob in memory + * @nr_cores: Number of CPU cores on this system. + * @gicr_frame_size: Size of the GICR frame per core + * + * On a GICv3 compatible interrupt controller, the redistributor provides + * a number of 64k pages per each supported core. So with a dynamic topology, + * this size cannot be known upfront and thus can't be hardcoded into the DTB. + * + * Find the DT node describing the GICv3 interrupt controller, and adjust + * the size of the redistributor to match the number of actual cores on + * this system. + * A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs + * without support for direct injection of virtual interrupts use two 64K pages. + * The @gicr_frame_size parameter should be 262144 and 131072, respectively. + * + * Return: 0 on success, negative error value otherwise. + */ +int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores, + unsigned int gicr_frame_size) +{ + int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3"); + uint64_t redist_size_64; + uint32_t redist_size_32; + void *val; + int parent; + int ac, sc; + + if (offset < 0) { + return offset; + } + + parent = fdt_parent_offset(dtb, offset); + if (parent < 0) { + return parent; + } + ac = fdt_address_cells(dtb, parent); + sc = fdt_size_cells(dtb, parent); + if (ac < 0 || sc < 0) { + return -EINVAL; + } + + if (sc == 1) { + redist_size_32 = cpu_to_fdt32(nr_cores * gicr_frame_size); + val = &redist_size_32; + } else { + redist_size_64 = cpu_to_fdt64(nr_cores * gicr_frame_size); + val = &redist_size_64; + } + + /* + * The redistributor is described in the second "reg" entry. + * So we have to skip one address and one size cell, then another + * address cell to get to the second size cell. + */ + return fdt_setprop_inplace_namelen_partial(dtb, offset, "reg", 3, + (ac + sc + ac) * 4, + val, sc * 4); +} diff --git a/include/common/fdt_fixup.h b/include/common/fdt_fixup.h index 29d8b3aa0..2e9d49d53 100644 --- a/include/common/fdt_fixup.h +++ b/include/common/fdt_fixup.h @@ -13,5 +13,7 @@ int fdt_add_reserved_memory(void *dtb, const char *node_name, uintptr_t base, size_t size); int fdt_add_cpus_node(void *dtb, unsigned int afflv0, unsigned int afflv1, unsigned int afflv2); +int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores, + unsigned int gicr_frame_size); #endif /* FDT_FIXUP_H */ From 283e5595afa28a5930ac5f0dcdf7c18804221070 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 24 Aug 2020 18:34:50 +0100 Subject: [PATCH 3/8] arm_fpga: Adjust GICR size in DT to match number of cores The size of a GICv3 redistributor region depends on the number of cores in the system. For the ARM FPGA port, we detect the topology at runtime, and adjust the CPU DT nodes accordingly. Now the size of the GICR region must also be adjusted, or Linux will fail to initialise the GICv3. Use the newly introduced function to overwrite the GICR size entry in the GICv3 reg property. We count the number of existing cores by iterating over the GICR frames until we find the LAST bit set in TYPER. Change-Id: Ib69565600859de9b1b15ceb8495172cd26d16fce Signed-off-by: Andre Przywara --- plat/arm/board/arm_fpga/fpga_bl31_setup.c | 11 +++++++++++ plat/arm/board/arm_fpga/fpga_gicv3.c | 5 +++++ plat/arm/board/arm_fpga/fpga_private.h | 1 + 3 files changed, 17 insertions(+) diff --git a/plat/arm/board/arm_fpga/fpga_bl31_setup.c b/plat/arm/board/arm_fpga/fpga_bl31_setup.c index de6d9d5e3..d5478d2d6 100644 --- a/plat/arm/board/arm_fpga/fpga_bl31_setup.c +++ b/plat/arm/board/arm_fpga/fpga_bl31_setup.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -210,6 +211,16 @@ static void fpga_prepare_dtb(void) if (err < 0) { ERROR("Error %d creating the /cpus DT node\n", err); panic(); + } else { + unsigned int nr_cores = fpga_get_nr_gic_cores(); + + INFO("Adjusting GICR DT region to cover %u cores\n", + nr_cores); + err = fdt_adjust_gic_redist(fdt, nr_cores, + 1U << GICR_PCPUBASE_SHIFT); + if (err < 0) { + ERROR("Error %d fixing up GIC DT node\n", err); + } } } diff --git a/plat/arm/board/arm_fpga/fpga_gicv3.c b/plat/arm/board/arm_fpga/fpga_gicv3.c index 9fb5fa935..bfc116bef 100644 --- a/plat/arm/board/arm_fpga/fpga_gicv3.c +++ b/plat/arm/board/arm_fpga/fpga_gicv3.c @@ -77,3 +77,8 @@ void fpga_pwr_gic_off(void) gicv3_cpuif_disable(plat_my_core_pos()); gicv3_rdistif_off(plat_my_core_pos()); } + +unsigned int fpga_get_nr_gic_cores(void) +{ + return gicv3_rdistif_get_number_frames(fpga_gicv3_driver_data.gicr_base); +} diff --git a/plat/arm/board/arm_fpga/fpga_private.h b/plat/arm/board/arm_fpga/fpga_private.h index 47059d64a..1ca241f26 100644 --- a/plat/arm/board/arm_fpga/fpga_private.h +++ b/plat/arm/board/arm_fpga/fpga_private.h @@ -24,6 +24,7 @@ void plat_fpga_gic_init(void); void fpga_pwr_gic_on_finish(void); void fpga_pwr_gic_off(void); unsigned int plat_fpga_calc_core_pos(uint32_t mpid); +unsigned int fpga_get_nr_gic_cores(void); #endif /* __ASSEMBLER__ */ From 40a0de1972bc9a12470b10bc08b7174e4990b30c Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 3 Aug 2020 12:55:28 +0100 Subject: [PATCH 4/8] arm_fpga: Remove SPE PMU DT node if SPE is not available The Statistical Profiling Extension (SPE) is an architectural feature we can safely detect at runtime. However it still relies on one piece of platform-specific information: the interrupt line it is connected to. This requires SPE to be described in a devicetree node. Since SPE support varies with the CPU cores found on an FPGA image, we should detect the presence of SPE at runtime, and remove a potentially existing SPE PMU node from the DT. This allows to always have the SPE node in a generic devicetree file, without risking exposing it on a CPU without this feature. Change-Id: I73d83ea8509b03fe7bba20b9cce8d1335035fa31 Signed-off-by: Andre Przywara --- plat/arm/board/arm_fpga/fpga_bl31_setup.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plat/arm/board/arm_fpga/fpga_bl31_setup.c b/plat/arm/board/arm_fpga/fpga_bl31_setup.c index d5478d2d6..a5f5ea0f3 100644 --- a/plat/arm/board/arm_fpga/fpga_bl31_setup.c +++ b/plat/arm/board/arm_fpga/fpga_bl31_setup.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "fpga_private.h" @@ -224,6 +225,16 @@ static void fpga_prepare_dtb(void) } } + /* Check whether we support the SPE PMU. Remove the DT node if not. */ + if (!spe_supported()) { + int node = fdt_node_offset_by_compatible(fdt, 0, + "arm,statistical-profiling-extension-v1"); + + if (node >= 0) { + fdt_del_node(fdt, node); + } + } + err = fdt_pack(fdt); if (err < 0) { ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err); From b48883c79a7abd1495ba55c3d0dcc95464c30c7e Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 3 Aug 2020 12:54:58 +0100 Subject: [PATCH 5/8] arm_fpga: Add devicetree file The FPGA images used in Arm Ltd. focus on CPU cores, so they share a common platform, with a minimal set of peripherals (interconnect, GIC, UART). This allows to support most platforms with a single devicetree file. The topology and number of CPU cores differ, but those will added at runtime, in BL31. Other adjustments (GICR size, SPE node, command line) are also done at this point. Add the common devicetree file to TF-A's build system, so it can be build together with BL31. At runtime, the resulting .dtb file should be uploaded to the address given with FPGA_PRELOADED_DTB_BASE at build time. Change-Id: I3206d6131059502ec96896e95329865452c9d83e Signed-off-by: Andre Przywara --- fdts/arm_fpga.dts | 102 ++++++++++++++++++++++++++++ plat/arm/board/arm_fpga/platform.mk | 2 + 2 files changed, 104 insertions(+) create mode 100644 fdts/arm_fpga.dts diff --git a/fdts/arm_fpga.dts b/fdts/arm_fpga.dts new file mode 100644 index 000000000..6a966fd85 --- /dev/null +++ b/fdts/arm_fpga.dts @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause) +/* + * Copyright (c) 2020, Arm Limited. All rights reserved. + * + * Devicetree for the Arm Ltd. FPGA platform + * Number and kind of CPU cores differs from image to image, so the + * topology is auto-detected by BL31, and the /cpus node is created and + * populated accordingly at runtime. + */ + +#include + +/dts-v1/; + +/ { + model = "ARM FPGA"; + compatible = "arm,fpga", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &dbg_uart; + }; + + chosen { + stdout-path = "serial0:38400n8"; + bootargs = "console=ttyAMA0,38400n8 earlycon"; + /* Allow to upload a generous 100MB initrd payload. */ + linux,initrd-start = <0x0 0x84000000>; + linux,initrd-end = <0x0 0x85400000>; + }; + + /* /cpus node will be added by BL31 at runtime. */ + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + clock-frequency = <10000000>; + interrupts = , + , + , + ; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + /* This node will be removed at runtime on cores without SPE. */ + spe-pmu { + compatible = "arm,statistical-profiling-extension-v1"; + interrupts = ; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x80000000>, + <0x8 0x80000000 0x1 0x80000000>; + }; + + + bus_refclk: refclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "apb_pclk"; + }; + + uartclk: baudclock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <10000000>; + clock-output-names = "uartclk"; + }; + + dbg_uart: serial@7ff80000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0x7ff80000 0x0 0x00001000>; + interrupts = ; + clocks = <&uartclk>, <&bus_refclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + gic: interrupt-controller@30000000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #interrupt-cells = <3>; + #size-cells = <2>; + ranges; + interrupt-controller; + reg = <0x0 0x30000000 0x0 0x00010000>, /* GICD */ + /* The GICR size will be adjusted at runtime to match the cores. */ + <0x0 0x30040000 0x0 0x00020000>; /* GICR for one core */ + interrupts = ; + }; +}; diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk index 890433983..daf9f9f58 100644 --- a/plat/arm/board/arm_fpga/platform.mk +++ b/plat/arm/board/arm_fpga/platform.mk @@ -81,6 +81,8 @@ FPGA_GIC_SOURCES := ${GICV3_SOURCES} \ plat/common/plat_gicv3.c \ plat/arm/board/arm_fpga/fpga_gicv3.c +FDT_SOURCES := fdts/arm_fpga.dts + PLAT_INCLUDES := -Iplat/arm/board/arm_fpga/include PLAT_BL_COMMON_SOURCES := plat/arm/board/arm_fpga/${ARCH}/fpga_helpers.S From f45c6d8623309a256718212a1a2c72ad5efe925d Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 3 Aug 2020 13:06:38 +0100 Subject: [PATCH 6/8] arm_fpga: Add ROM trampoline The application cores of the FPGAs used in Arm Ltd. start execution at address 0x0. This is the location of some (emulated) ROM area (which can be written to by the uploading tool). Since the arm_fpga port is configured to run from DRAM, we load BL31 to the beginning of DRAM (mapped at 2GB). This requires some small trampoline code in the "ROM" to jump to the BL31 entry point. To avoid some extra magic binary, add a tiny assembly file with that trivial jump instruction to the tree, so this binary can be created alongside BL31. Change-Id: I9e4439fc0f093fa24dd49a8377c9edb030fbb477 Signed-off-by: Andre Przywara --- plat/arm/board/arm_fpga/platform.mk | 2 ++ plat/arm/board/arm_fpga/rom_trampoline.S | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 plat/arm/board/arm_fpga/rom_trampoline.S diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk index daf9f9f58..f3be3cd32 100644 --- a/plat/arm/board/arm_fpga/platform.mk +++ b/plat/arm/board/arm_fpga/platform.mk @@ -100,4 +100,6 @@ BL31_SOURCES += common/fdt_wrappers.c \ ${FPGA_CPU_LIBS} \ ${FPGA_GIC_SOURCES} +$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,31)) + all: bl31 diff --git a/plat/arm/board/arm_fpga/rom_trampoline.S b/plat/arm/board/arm_fpga/rom_trampoline.S new file mode 100644 index 000000000..cd66c7927 --- /dev/null +++ b/plat/arm/board/arm_fpga/rom_trampoline.S @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * The Arm Ltd. FPGA images start execution at address 0x0, which is + * mapped at an (emulated) ROM image. The payload uploader can write to + * this memory, but write access by the CPU cores is prohibited. + * + * Provide a simple trampoline to start BL31 execution at the actual + * load address. We put the DTB address in x0, so any code in DRAM could + * make use of that information (not yet used in BL31 right now). + */ + +#include +#include + +.text +.global _start + +_start: + mov_imm x1, BL31_BASE /* beginning of DRAM */ + mov_imm x0, FPGA_PRELOADED_DTB_BASE + br x1 From 01301b116ea32c6529a69bfc679cab2d2fdaa4d9 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 16 Sep 2020 17:13:33 +0100 Subject: [PATCH 7/8] arm_fpga: Add post-build linker script For the Arm Ltd. FPGAs to run, we need to load several payloads into the FPGA's memory: - Some trampoline code at address 0x0, to jump to BL31's entry point. - The actual BL31 binary at the beginning of DRAM. - The (generic) DTB image to describe the hardware. - The actual non-secure payloads (kernel, ramdisks, ...) The latter is application specific, but the first three blobs are rather generic. Since the uploader tool supports ELF binaries, it seems helpful to combine these three images into one .axf file, as this also simplifies the command line. Add a post-build linker script, that combines those three bits into one ELF file, together with their specific load addresses. Include a call to "ld" with this linker script in the platform Makefile, so it will be build automatically. The result will be called "bl31.axf". Change-Id: I4a90da16fa1e0e83b51d19e5b1daf61f5a0bbfca Signed-off-by: Andre Przywara --- plat/arm/board/arm_fpga/build_axf.ld.S | 47 ++++++++++++++++++++++++++ plat/arm/board/arm_fpga/platform.mk | 7 +++- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 plat/arm/board/arm_fpga/build_axf.ld.S diff --git a/plat/arm/board/arm_fpga/build_axf.ld.S b/plat/arm/board/arm_fpga/build_axf.ld.S new file mode 100644 index 000000000..d7cd00882 --- /dev/null +++ b/plat/arm/board/arm_fpga/build_axf.ld.S @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Linker script for the Arm Ltd. FPGA boards to generate an ELF file that + * contains the ROM trampoline, BL31 and the DTB. + * + * This allows to pass just one file to the uploader tool, and automatically + * provides the correct load addresses. + */ + +#include + +OUTPUT_FORMAT("elf64-littleaarch64") +OUTPUT_ARCH(aarch64) + +INPUT(./bl31/bl31.elf) +INPUT(./rom_trampoline.o) + +TARGET(binary) +INPUT(./fdts/arm_fpga.dtb) + +ENTRY(_start) + +SECTIONS +{ + .rom (0x0): { + *rom_trampoline.o(.text*) + KEEP(*(.rom)) + } + + .bl31 (BL31_BASE): { + ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE is not page aligned"); + *bl31.elf(.text* .data* .rodata* ro* .bss*) + *bl31.elf(.stack) + } + + .dtb (FPGA_PRELOADED_DTB_BASE): { + ASSERT(. == ALIGN(8), "DTB address is not 8-byte aligned"); + *arm_fpga.dtb + } + + /DISCARD/ : { *(.debug_*) } + /DISCARD/ : { *(.note*) } + /DISCARD/ : { *(.comment*) } +} diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk index f3be3cd32..ad9001b56 100644 --- a/plat/arm/board/arm_fpga/platform.mk +++ b/plat/arm/board/arm_fpga/platform.mk @@ -101,5 +101,10 @@ BL31_SOURCES += common/fdt_wrappers.c \ ${FPGA_GIC_SOURCES} $(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,31)) +$(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,31)) -all: bl31 +bl31.axf: bl31 dtbs ${BUILD_PLAT}/rom_trampoline.o ${BUILD_PLAT}/build_axf.ld + $(ECHO) " LD $@" + $(Q)$(LD) -T ${BUILD_PLAT}/build_axf.ld -L ${BUILD_PLAT} --strip-debug -o ${BUILD_PLAT}/bl31.axf + +all: bl31.axf From a6c07e0ddfa3658d7bc0ad1693b6e908293c1c96 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 27 Aug 2020 12:13:30 +0100 Subject: [PATCH 8/8] arm_fpga: Add platform documentation As the Arm Ltd. FPGA port is now working for all existing images, add some documentation file. Change-Id: I9e2c532ed15bbc121bb54b3dfc1bdfee8f1443a6 Signed-off-by: Andre Przywara --- docs/plat/arm/arm_fpga/index.rst | 97 ++++++++++++++++++++++++++++++++ docs/plat/arm/index.rst | 1 + 2 files changed, 98 insertions(+) create mode 100644 docs/plat/arm/arm_fpga/index.rst diff --git a/docs/plat/arm/arm_fpga/index.rst b/docs/plat/arm/arm_fpga/index.rst new file mode 100644 index 000000000..5427c1dde --- /dev/null +++ b/docs/plat/arm/arm_fpga/index.rst @@ -0,0 +1,97 @@ +Arm FPGA Platform +================= + +This platform supports FPGA images used internally in Arm Ltd., for +testing and bringup of new cores. With that focus, peripheral support is +minimal: there is no mass storage or display output, for instance. Also +this port ignores any power management features of the platform. +Some interconnect setup is done internally by the platform, so the TF-A code +just needs to setup UART and GIC. + +The FPGA platform requires to pass on a DTB for the non-secure payload +(mostly Linux), so we let TF-A use information from the DTB for dynamic +configuration: the UART and GIC base addresses are read from there. + +As a result this port is a fairly generic BL31-only port, which can serve +as a template for a minimal new (and possibly DT-based) platform port. + +The aim of this port is to support as many FPGA images as possible with +a single build. Image specific data must be described in the DTB or should +be auto-detected at runtime. + +As the number and topology layout of the CPU cores differs significantly +across the various images, this is detected at runtime by BL31. +The /cpus node in the DT will be added and filled accordingly, as long as +it does not exist already. + +Platform-specific build options +------------------------------- + +- ``SUPPORT_UNKNOWN_MPID`` : Boolean option to allow unknown MPIDR registers. + Normally TF-A panics if it encounters a MPID value not matched to its + internal list, but for new or experimental cores this creates a lot of + churn. With this option, the code will fall back to some basic CPU support + code (only architectural system registers, and no errata). + Default value of this flag is 1. + +- ``PRELOADED_BL33_BASE`` : Physical address of the BL33 non-secure payload. + It must have been loaded into DRAM already, typically this is done by + the script that also loads BL31 and the DTB. + It defaults to 0x80080000, which is the traditional load address for an + arm64 Linux kernel. + +- ``FPGA_PRELOADED_DTB_BASE`` : Physical address of the flattened device + tree blob (DTB). This DT will be used by TF-A for dynamic configuration, + so it must describe at least the UART and a GICv3 interrupt controller. + The DT gets amended by the code, to potentially add a command line and + fill the CPU topology nodes. It will also be passed on to BL33, by + putting its address into the x0 register before jumping to the entry + point (following the Linux kernel boot protocol). + It defaults to 0x80070000, which is 64KB before the BL33 load address. + +- ``FPGA_PRELOADED_CMD_LINE`` : Physical address of the command line to + put into the devicetree blob. Due to the lack of a proper bootloader, + a command line can be put somewhere into memory, so that BL31 will + detect it and copy it into the DTB passed on to BL33. + To avoid random garbage, there needs to be a "CMD:" signature before the + actual command line. + Defaults to 0x1000, which is normally in the "ROM" space of the typical + FPGA image (which can be written by the FPGA payload uploader, but is + read-only to the CPU). The FPGA payload tool should be given a text file + containing the desired command line, prefixed by the "CMD:" signature. + +Building the TF-A image +----------------------- + + .. code:: shell + + make PLAT=arm_fgpa DEBUG=1 + + This will use the default load addresses as described above. When those + addresses need to differ for a certain setup, they can be passed on the + make command line: + + .. code:: shell + + make PLAT=arm_fgpa DEBUG=1 PRELOADED_BL33_BASE=0x80200000 FPGA_PRELOADED_DTB_BASE=0x80180000 bl31 + +Running the TF-A image +---------------------- + +After building TF-A, the actual TF-A code will be located in ``bl31.bin`` in +the build directory. +Additionally there is a ``bl31.axf`` ELF file, which contains BL31, as well +as some simple ROM trampoline code (required by the Arm FPGA boot flow) and +a generic DTB to support most of the FPGA images. This can be simply handed +over to the FPGA payload uploader, which will take care of loading the +components at their respective load addresses. In addition to this file +you need at least a BL33 payload (typically a Linux kernel image), optionally +a Linux initrd image file and possibly a command line: + + .. code:: shell + + fpga-run ... -m bl31.axf -l auto -m Image -l 0x80080000 -m initrd.gz -l 0x84000000 -m cmdline.txt -l 0x1000 + +-------------- + +*Copyright (c) 2020, Arm Limited. All rights reserved.* diff --git a/docs/plat/arm/index.rst b/docs/plat/arm/index.rst index 1afe475c6..9c2fcb102 100644 --- a/docs/plat/arm/index.rst +++ b/docs/plat/arm/index.rst @@ -9,6 +9,7 @@ Arm Development Platforms fvp/index fvp-ve/index tc0/index + arm_fpga/index arm-build-options This chapter holds documentation related to Arm's development platforms,