diff --git a/Makefile b/Makefile index 3d5b395..47a544d 100644 --- a/Makefile +++ b/Makefile @@ -1000,6 +1000,8 @@ ifeq (${NEED_BL31},yes) BL31_SOURCES += ${SPD_SOURCES} +# Sort BL31 source files to remove duplicates +BL31_SOURCES := $(sort ${BL31_SOURCES}) ifneq (${DECRYPTION_SUPPORT},none) $(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw,,$(ENCRYPT_BL31))),\ $(eval $(call MAKE_BL,31,soc-fw,,$(ENCRYPT_BL31)))) @@ -1013,7 +1015,8 @@ # build system will call TOOL_ADD_IMG to print a warning message and abort the # process. Note that the dependency on BL32 applies to the FIP only. ifeq (${NEED_BL32},yes) - +# Sort BL32 source files to remove duplicates +BL32_SOURCES := $(sort ${BL32_SOURCES}) BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1)) ifneq (${DECRYPTION_SUPPORT},none) diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S index e0138ac..5f9f9df 100644 --- a/bl31/bl31.ld.S +++ b/bl31/bl31.ld.S @@ -55,6 +55,11 @@ KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; + . = ALIGN(8); + __FCONF_POPULATOR_START__ = .; + KEEP(*(.fconf_populator)) + __FCONF_POPULATOR_END__ = .; + #if ENABLE_PMF /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); @@ -102,6 +107,11 @@ KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; + . = ALIGN(8); + __FCONF_POPULATOR_START__ = .; + KEEP(*(.fconf_populator)) + __FCONF_POPULATOR_END__ = .; + #if ENABLE_PMF /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S index 3b1ca1b..a90a805 100644 --- a/bl32/sp_min/sp_min.ld.S +++ b/bl32/sp_min/sp_min.ld.S @@ -56,6 +56,11 @@ KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; + . = ALIGN(8); + __FCONF_POPULATOR_START__ = .; + KEEP(*(.fconf_populator)) + __FCONF_POPULATOR_END__ = .; + #if ENABLE_PMF /* Ensure 4-byte alignment for descriptors and ensure inclusion */ . = ALIGN(4); @@ -93,6 +98,11 @@ KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; + . = ALIGN(8); + __FCONF_POPULATOR_START__ = .; + KEEP(*(.fconf_populator)) + __FCONF_POPULATOR_END__ = .; + /* * Ensure 4-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. diff --git a/docs/components/fconf.rst b/docs/components/fconf.rst index cec3ceb..4ea1f5b 100644 --- a/docs/components/fconf.rst +++ b/docs/components/fconf.rst @@ -28,29 +28,45 @@ - (|TBBR|) Chain of Trust data: tbbr.cot.trusted_boot_fw_cert - (|TBBR|) dynamic configuration info: tbbr.dyn_config.disable_auth - Arm io policies: arm.io_policies.bl2_image +- GICv3 properties: hw_config.gicv3_config.gicr_base Properties can be accessed with the ``FCONF_GET_PROPERTY(a,b,property)`` macro. Defining properties ~~~~~~~~~~~~~~~~~~~ -Properties composing the |FCONF| have to be stored in C structures. If another -backing store is wanted to be used, the platform has to provide a ``populate()`` -function to fill the corresponding C structure. +Properties composing the |FCONF| have to be stored in C structures. If +properties originate from a different backend source such as a device tree, +then the platform has to provide a ``populate()`` function which essentially +captures the property and stores them into a corresponding |FCONF| based C +structure. -The ``populate()`` function must be registered to the |FCONF| framework with -the ``FCONF_REGISTER_POPULATOR()`` macro. This ensures that the function would -be called inside the generic ``fconf_populate()`` function during +Such a ``populate()`` function is usually platform specific and is associated +with a specific backend source. For example, a populator function which +captures the hardware topology of the platform from the HW_CONFIG device tree. +Hence each ``populate()`` function must be registered with a specific +``config_type`` identifier. It broadly represents a logical grouping of +configuration properties which is usually a device tree file. + +Example: + - TB_FW: properties related to trusted firmware such as IO policies, + base address of other DTBs, mbedtls heap info etc. + - HW_CONFIG: properties related to hardware configuration of the SoC + such as topology, GIC controller, PSCI hooks, CPU ID etc. + +Hence the ``populate()`` callback must be registered to the (|FCONF|) framework +with the ``FCONF_REGISTER_POPULATOR()`` macro. This ensures that the function +would be called inside the generic ``fconf_populate()`` function during initialization. :: - int fconf_populate_tbbr_dyn_config(uintptr_t config) + int fconf_populate_topology(uintptr_t config) { - /* read dtb and fill tbbr_dyn_config struct */ + /* read hw config dtb and fill soc_topology struct */ } - FCONF_REGISTER_POPULATOR(fconf_populate_tbbr_dyn_config); + FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology); Then, a wrapper has to be provided to match the ``FCONF_GET_PROPERTY()`` macro: @@ -60,7 +76,7 @@ #define FCONF_GET_PROPERTY(a,b,property) a##__##b##_getter(property) /* my specific getter */ - #define tbbr__dyn_config_getter(id) tbbr_dyn_config.id + #define hw_config__topology_getter(prop) soc_topology.prop This second level wrapper can be used to remap the ``FCONF_GET_PROPERTY()`` to anything appropriate: structure, array, function, etc.. @@ -80,6 +96,6 @@ Once a valid device tree is available, the ``fconf_populate(config)`` function can be used to fill the C data structure with the data from the config |DTB|. This function will call all the ``populate()`` callbacks which have been -registered with ``FCONF_REGISTER_POPULATOR()``. +registered with ``FCONF_REGISTER_POPULATOR()`` as described above. .. uml:: ../resources/diagrams/plantuml/fconf_bl2_populate.puml diff --git a/fdts/fvp-base-gicv2-psci-aarch32.dts b/fdts/fvp-base-gicv2-psci-aarch32.dts index e71a395..fcef927 100644 --- a/fdts/fvp-base-gicv2-psci-aarch32.dts +++ b/fdts/fvp-base-gicv2-psci-aarch32.dts @@ -35,6 +35,7 @@ cpu_on = <0x84000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/fdts/fvp-base-gicv2-psci.dts b/fdts/fvp-base-gicv2-psci.dts index c9c9d95..1e0a81c 100644 --- a/fdts/fvp-base-gicv2-psci.dts +++ b/fdts/fvp-base-gicv2-psci.dts @@ -35,6 +35,7 @@ cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi b/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi index f9809db..a28a4a5 100644 --- a/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi +++ b/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi @@ -33,6 +33,7 @@ cpu_on = <0x84000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi index 5b0470d..fb73f60 100644 --- a/fdts/fvp-base-gicv3-psci-common.dtsi +++ b/fdts/fvp-base-gicv3-psci-common.dtsi @@ -33,6 +33,7 @@ cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi b/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi index f3f7684..4bed36f 100644 --- a/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi +++ b/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi @@ -11,6 +11,9 @@ /* DynamIQ based designs have upto 8 CPUs in each cluster */ &CPU_MAP { + /delete-node/ cluster0; + /delete-node/ cluster1; + cluster0 { core0 { cpu = <&CPU0>; diff --git a/fdts/fvp-foundation-gicv2-psci.dts b/fdts/fvp-foundation-gicv2-psci.dts index b6da905..3a204cb 100644 --- a/fdts/fvp-foundation-gicv2-psci.dts +++ b/fdts/fvp-foundation-gicv2-psci.dts @@ -35,6 +35,7 @@ cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/fdts/fvp-foundation-gicv3-psci.dts b/fdts/fvp-foundation-gicv3-psci.dts index 81071e2..d85305a 100644 --- a/fdts/fvp-foundation-gicv3-psci.dts +++ b/fdts/fvp-foundation-gicv3-psci.dts @@ -35,6 +35,7 @@ cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; + max-pwr-lvl = <2>; }; cpus { diff --git a/include/lib/fconf/fconf.h b/include/lib/fconf/fconf.h index 0401e5c..09d2b59 100644 --- a/include/lib/fconf/fconf.h +++ b/include/lib/fconf/fconf.h @@ -12,9 +12,16 @@ /* Public API */ #define FCONF_GET_PROPERTY(a, b, c) a##__##b##_getter(c) -#define FCONF_REGISTER_POPULATOR(name, callback) \ +/* + * This macro takes three arguments: + * config: Configuration identifier + * name: property namespace + * callback: populate() function + */ +#define FCONF_REGISTER_POPULATOR(config, name, callback) \ __attribute__((used, section(".fconf_populator"))) \ const struct fconf_populator (name##__populator) = { \ + .config_type = (#config), \ .info = (#name), \ .populate = (callback) \ }; @@ -27,6 +34,7 @@ */ struct fconf_populator { /* Description of the data loaded by the callback */ + const char *config_type; const char *info; /* Callback used by fconf_populate function with a provided config dtb. @@ -45,7 +53,7 @@ * * Panic on error. */ -void fconf_populate(uintptr_t config); +void fconf_populate(const char *config_type, uintptr_t config); /* FCONF specific getter */ #define fconf__dtb_getter(prop) fconf_dtb_info.prop diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index babde41..6c2925a 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -222,6 +222,7 @@ void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config, uintptr_t hw_config, void *plat_params_from_bl2); void arm_sp_min_plat_runtime_setup(void); +void arm_sp_min_plat_arch_setup(void); /* FIP TOC validity check */ bool arm_io_is_toc_valid(void); diff --git a/lib/fconf/fconf.c b/lib/fconf/fconf.c index a6da56b..9ce4635 100644 --- a/lib/fconf/fconf.c +++ b/lib/fconf/fconf.c @@ -53,17 +53,17 @@ INFO("FCONF: FW_CONFIG loaded at address = 0x%lx\n", arm_tb_fw_info.image_base); } -void fconf_populate(uintptr_t config) +void fconf_populate(const char *config_type, uintptr_t config) { assert(config != 0UL); /* Check if the pointer to DTB is correct */ if (fdt_check_header((void *)config) != 0) { - ERROR("FCONF: Invalid DTB file passed for FW_CONFIG\n"); + ERROR("FCONF: Invalid DTB file passed for %s\n", config_type); panic(); } - INFO("FCONF: Reading firmware configuration file from: 0x%lx\n", config); + INFO("FCONF: Reading %s firmware configuration file from: 0x%lx\n", config_type, config); /* Go through all registered populate functions */ IMPORT_SYM(struct fconf_populator *, __FCONF_POPULATOR_START__, start); @@ -73,10 +73,12 @@ for (populator = start; populator != end; populator++) { assert((populator->info != NULL) && (populator->populate != NULL)); - INFO("FCONF: Reading firmware configuration information for: %s\n", populator->info); - if (populator->populate(config) != 0) { - /* TODO: handle property miss */ - panic(); + if (strcmp(populator->config_type, config_type) == 0) { + INFO("FCONF: Reading firmware configuration information for: %s\n", populator->info); + if (populator->populate(config) != 0) { + /* TODO: handle property miss */ + panic(); + } } } diff --git a/lib/fconf/fconf_dyn_cfg_getter.c b/lib/fconf/fconf_dyn_cfg_getter.c index d313a56..317d3e5 100644 --- a/lib/fconf/fconf_dyn_cfg_getter.c +++ b/lib/fconf/fconf_dyn_cfg_getter.c @@ -92,4 +92,4 @@ return 0; } -FCONF_REGISTER_POPULATOR(dyn_cfg, fconf_populate_dtb_registry); +FCONF_REGISTER_POPULATOR(TB_FW, dyn_cfg, fconf_populate_dtb_registry); diff --git a/lib/fconf/fconf_tbbr_getter.c b/lib/fconf/fconf_tbbr_getter.c index c6df9c8..a4d61d8 100644 --- a/lib/fconf/fconf_tbbr_getter.c +++ b/lib/fconf/fconf_tbbr_getter.c @@ -72,4 +72,4 @@ return 0; } -FCONF_REGISTER_POPULATOR(tbbr, fconf_populate_tbbr_dyn_config); +FCONF_REGISTER_POPULATOR(TB_FW, tbbr, fconf_populate_tbbr_dyn_config); diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c new file mode 100644 index 0000000..2952cde --- /dev/null +++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +struct gicv3_config_t gicv3_config; +struct hw_topology_t soc_topology; + +int fconf_populate_gicv3_config(uintptr_t config) +{ + int err; + int node; + int addr[20]; + + /* Necessary to work with libfdt APIs */ + const void *hw_config_dtb = (const void *)config; + + /* + * Find the offset of the node containing "arm,gic-v3" compatible property. + * Populating fconf strucutures dynamically is not supported for legacy + * systems which use GICv2 IP. Simply skip extracting GIC properties. + */ + node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3"); + if (node < 0) { + WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n"); + return 0; + } + /* Read the reg cell holding base address of GIC controller modules + A sample reg cell array is shown here: + reg = <0x0 0x2f000000 0 0x10000>, // GICD + <0x0 0x2f100000 0 0x200000>, // GICR + <0x0 0x2c000000 0 0x2000>, // GICC + <0x0 0x2c010000 0 0x2000>, // GICH + <0x0 0x2c02f000 0 0x2000>; // GICV + */ + + err = fdtw_read_array(hw_config_dtb, node, "reg", 20, &addr); + if (err < 0) { + ERROR("FCONF: Failed to read reg property of GIC node\n"); + } + return err; +} + +int fconf_populate_topology(uintptr_t config) +{ + int err, node, cluster_node, core_node, thread_node, max_pwr_lvl = 0; + uint32_t cluster_count = 0, max_cpu_per_cluster = 0, total_cpu_count = 0; + + /* Necessary to work with libfdt APIs */ + const void *hw_config_dtb = (const void *)config; + + /* Find the offset of the node containing "arm,psci-1.0" compatible property */ + node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,psci-1.0"); + if (node < 0) { + ERROR("FCONF: Unable to locate node with arm,psci-1.0 compatible property\n"); + return node; + } + + err = fdtw_read_cells(hw_config_dtb, node, "max-pwr-lvl", 1, &max_pwr_lvl); + if (err < 0) { + /* + * Some legacy FVP dts may not have this property. Assign the default + * value. + */ + WARN("FCONF: Could not locate max-pwr-lvl property\n"); + max_pwr_lvl = 2; + } + + assert((uint32_t)max_pwr_lvl <= MPIDR_AFFLVL2); + + /* Find the offset of the "cpus" node */ + node = fdt_path_offset(hw_config_dtb, "/cpus"); + if (node < 0) { + ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpus"); + return node; + } + + /* A typical cpu-map node in a device tree is shown here for reference + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU2>; + }; + core1 { + cpu = <&CPU3>; + }; + }; + }; + */ + + /* Locate the cpu-map child node */ + node = fdt_subnode_offset(hw_config_dtb, node, "cpu-map"); + if (node < 0) { + ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpu-map"); + return node; + } + + uint32_t cpus_per_cluster[PLAT_ARM_CLUSTER_COUNT] = {0}; + + /* Iterate through cluster nodes */ + fdt_for_each_subnode(cluster_node, hw_config_dtb, node) { + assert(cluster_count < PLAT_ARM_CLUSTER_COUNT); + + /* Iterate through core nodes */ + fdt_for_each_subnode(core_node, hw_config_dtb, cluster_node) { + /* core nodes may have child nodes i.e., "thread" nodes */ + if (fdt_first_subnode(hw_config_dtb, core_node) < 0) { + cpus_per_cluster[cluster_count]++; + } else { + /* Multi-threaded CPU description is found in dtb */ + fdt_for_each_subnode(thread_node, hw_config_dtb, core_node) { + cpus_per_cluster[cluster_count]++; + } + + /* Since in some dtbs, core nodes may not have thread node, + * no need to error if even one child node is not found. + */ + } + } + + /* Ensure every cluster node has at least 1 child node */ + if (cpus_per_cluster[cluster_count] < 1U) { + ERROR("FCONF: Unable to locate the core node in cluster %d\n", cluster_count); + return -1; + } + + INFO("CLUSTER ID: %d cpu-count: %d\n", cluster_count, cpus_per_cluster[cluster_count]); + + /* Find the maximum number of cpus in any cluster */ + max_cpu_per_cluster = MAX(max_cpu_per_cluster, cpus_per_cluster[cluster_count]); + total_cpu_count += cpus_per_cluster[cluster_count]; + cluster_count++; + } + + + /* At least one cluster node is expected in hardware configuration dtb */ + if (cluster_count < 1U) { + ERROR("FCONF: Unable to locate the cluster node in cpu-map node\n"); + return -1; + } + + soc_topology.plat_max_pwr_level = (uint32_t)max_pwr_lvl; + soc_topology.plat_cluster_count = cluster_count; + soc_topology.cluster_cpu_count = max_cpu_per_cluster; + soc_topology.plat_cpu_count = total_cpu_count; + + return 0; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config); +FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology); diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c index 8627c5e..dc7bfa2 100644 --- a/plat/arm/board/fvp/fvp_bl31_setup.c +++ b/plat/arm/board/fvp/fvp_bl31_setup.c @@ -1,16 +1,21 @@ /* - * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include #include +#include #include #include #include #include "fvp_private.h" +uintptr_t hw_config_dtb; + void __init bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { @@ -40,4 +45,23 @@ /* On FVP RevC, initialize SMMUv3 */ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) smmuv3_init(PLAT_FVP_SMMUV3_BASE); + + hw_config_dtb = arg2; +} + +void __init bl31_plat_arch_setup(void) +{ + arm_bl31_plat_arch_setup(); + + /* + * For RESET_TO_BL31 systems, BL31 is the first bootloader to run. + * So there is no BL2 to load the HW_CONFIG dtb into memory before + * control is passed to BL31. + */ +#if !RESET_TO_BL31 && !BL2_AT_EL3 + assert(hw_config_dtb != 0U); + + INFO("BL31 FCONF: HW_CONFIG address = %p\n", (void *)hw_config_dtb); + fconf_populate("HW_CONFIG", hw_config_dtb); +#endif } diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c index 2c880fc..33f3067 100644 --- a/plat/arm/board/fvp/fvp_common.c +++ b/plat/arm/board/fvp/fvp_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -134,6 +134,8 @@ #if SPM_MM ARM_SPM_BUF_EL3_MMAP, #endif + /* Required by fconf APIs to read HW_CONFIG dtb loaded into DRAM */ + ARM_MAP_NS_DRAM1, {0} }; @@ -160,6 +162,8 @@ V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, + /* Required by fconf APIs to read HW_CONFIG dtb loaded into DRAM */ + ARM_MAP_NS_DRAM1, {0} }; #endif diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c index 24e79b4..80cfbd5 100644 --- a/plat/arm/board/fvp/fvp_topology.c +++ b/plat/arm/board/fvp/fvp_topology.c @@ -1,18 +1,21 @@ /* - * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include #include +#include #include #include #include #include +#include + /* The FVP power domain tree descriptor */ static unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2]; @@ -21,24 +24,47 @@ assert_invalid_fvp_cluster_count); /******************************************************************************* - * This function dynamically constructs the topology according to - * FVP_CLUSTER_COUNT and returns it. + * This function dynamically constructs the topology according to cpu-map node + * in HW_CONFIG dtb and returns it. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { - int i; + unsigned int i; + uint32_t cluster_count, cpus_per_cluster; + + /* + * fconf APIs are not supported for RESET_TO_SP_MIN, RESET_TO_BL31 and + * BL2_AT_EL3 systems. + */ +#if RESET_TO_SP_MIN || RESET_TO_BL31 || BL2_AT_EL3 + cluster_count = FVP_CLUSTER_COUNT; + cpus_per_cluster = FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU; +#else + cluster_count = FCONF_GET_PROPERTY(hw_config, topology, plat_cluster_count); + cpus_per_cluster = FCONF_GET_PROPERTY(hw_config, topology, cluster_cpu_count); + /* Several FVP Models use the same blanket dts. Ex: FVP_Base_Cortex-A65x4 + * and FVP_Base_Cortex-A65AEx8 both use same dts but have different number of + * CPUs in the cluster, as reflected by build flags FVP_MAX_CPUS_PER_CLUSTER. + * Take the minimum of two to ensure PSCI functions do not exceed the size of + * the PSCI data structures allocated at build time. + */ + cpus_per_cluster = MIN(cpus_per_cluster, + (uint32_t)(FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU)); + +#endif + + assert(cluster_count > 0U); + assert(cpus_per_cluster > 0U); /* * The highest level is the system level. The next level is constituted * by clusters and then cores in clusters. */ fvp_power_domain_tree_desc[0] = 1; - fvp_power_domain_tree_desc[1] = FVP_CLUSTER_COUNT; + fvp_power_domain_tree_desc[1] = (unsigned char)cluster_count; - for (i = 0; i < FVP_CLUSTER_COUNT; i++) - fvp_power_domain_tree_desc[i + 2] = - FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU; - + for (i = 0; i < cluster_count; i++) + fvp_power_domain_tree_desc[i + 2] = (unsigned char)cpus_per_cluster; return fvp_power_domain_tree_desc; } diff --git a/plat/arm/board/fvp/include/fconf_hw_config_getter.h b/plat/arm/board/fvp/include/fconf_hw_config_getter.h new file mode 100644 index 0000000..cab832f --- /dev/null +++ b/plat/arm/board/fvp/include/fconf_hw_config_getter.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FCONF_HW_CONFIG_GETTER_H +#define FCONF_HW_CONFIG_GETTER_H + +#include + +/* Hardware Config related getter */ +#define hw_config__gicv3_config_getter(prop) gicv3_config.prop + +#define hw_config__topology_getter(prop) soc_topology.prop + +struct gicv3_config_t { + void *gicd_base; + void *gicr_base; +}; + +struct hw_topology_t { + uint32_t plat_cluster_count; + uint32_t cluster_cpu_count; + uint32_t plat_cpu_count; + uint32_t plat_max_pwr_level; +}; + +int fconf_populate_gicv3_config(uintptr_t config); +int fconf_populate_topology(uintptr_t config); + +extern struct gicv3_config_t gicv3_config; +extern struct hw_topology_t soc_topology; + +#endif /* FCONF_HW_CONFIG_GETTER_H */ diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index bfe207a..69d49ba 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -63,12 +63,12 @@ */ #if defined(IMAGE_BL31) # if SPM_MM -# define PLAT_ARM_MMAP_ENTRIES 9 +# define PLAT_ARM_MMAP_ENTRIES 10 # define MAX_XLAT_TABLES 9 # define PLAT_SP_IMAGE_MMAP_REGIONS 30 # define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10 # else -# define PLAT_ARM_MMAP_ENTRIES 8 +# define PLAT_ARM_MMAP_ENTRIES 9 # if USE_DEBUGFS # define MAX_XLAT_TABLES 6 # else @@ -76,7 +76,7 @@ # endif # endif #elif defined(IMAGE_BL32) -# define PLAT_ARM_MMAP_ENTRIES 8 +# define PLAT_ARM_MMAP_ENTRIES 9 # define MAX_XLAT_TABLES 5 #elif !USE_ROMLIB # define PLAT_ARM_MMAP_ENTRIES 11 diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i index b1b9ed4..0c93d0a 100644 --- a/plat/arm/board/fvp/jmptbl.i +++ b/plat/arm/board/fvp/jmptbl.i @@ -22,6 +22,8 @@ fdt fdt_setprop_inplace_namelen_partial fdt fdt_first_subnode fdt fdt_next_subnode +fdt fdt_path_offset +fdt fdt_subnode_offset mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index c32b302..ca35697 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -204,6 +204,12 @@ ${FVP_INTERCONNECT_SOURCES} \ ${FVP_SECURITY_SOURCES} +# Support for fconf in BL31 +# Added separately from the above list for better readability +BL31_SOURCES += common/fdt_wrappers.c \ + lib/fconf/fconf.c \ + plat/arm/board/fvp/fconf/fconf_hw_config_getter.c + ifeq (${FVP_USE_SP804_TIMER},1) BL31_SOURCES += drivers/arm/sp804/sp804_delay_timer.c else diff --git a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c index 88c91e6..763b42a 100644 --- a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c +++ b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c @@ -1,13 +1,20 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include + +#include +#include +#include #include #include "../fvp_private.h" +uintptr_t hw_config_dtb; + void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { @@ -30,4 +37,24 @@ * FVP PSCI code will enable coherency for other clusters. */ fvp_interconnect_enable(); + + hw_config_dtb = arg2; +} + +void sp_min_plat_arch_setup(void) +{ + arm_sp_min_plat_arch_setup(); + + /* + * For RESET_TO_SP_MIN systems, SP_MIN(BL32) is the first bootloader + * to run. So there is no BL2 to load the HW_CONFIG dtb into memory + * before control is passed to SP_MIN. + * Also, BL2 skips loading HW_CONFIG dtb for BL2_AT_EL3 builds. + */ +#if !RESET_TO_SP_MIN && !BL2_AT_EL3 + assert(hw_config_dtb != 0U); + + INFO("SP_MIN FCONF: HW_CONFIG address = %p\n", (void *)hw_config_dtb); + fconf_populate("HW_CONFIG", hw_config_dtb); +#endif } diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk index 0250a5f..520a70f 100644 --- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk +++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -18,4 +18,10 @@ ${FVP_INTERCONNECT_SOURCES} \ ${FVP_SECURITY_SOURCES} +# Support for fconf in SP_MIN(BL32) +# Added separately from the above list for better readability +BL32_SOURCES += common/fdt_wrappers.c \ + lib/fconf/fconf.c \ + plat/arm/board/fvp/fconf/fconf_hw_config_getter.c + include plat/arm/common/sp_min/arm_sp_min.mk diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c index 136e65a..d9fc84e 100644 --- a/plat/arm/common/arm_bl2_setup.c +++ b/plat/arm/common/arm_bl2_setup.c @@ -61,7 +61,7 @@ /* Fill the properties struct with the info from the config dtb */ if (tb_fw_config != 0U) { - fconf_populate(tb_fw_config); + fconf_populate("TB_FW", tb_fw_config); } /* Initialise the IO layer and register platform IO devices */ diff --git a/plat/arm/common/fconf/arm_fconf_io.c b/plat/arm/common/fconf/arm_fconf_io.c index cfcddc2..017af79 100644 --- a/plat/arm/common/fconf/arm_fconf_io.c +++ b/plat/arm/common/fconf/arm_fconf_io.c @@ -138,6 +138,6 @@ return 0; } -FCONF_REGISTER_POPULATOR(arm_io, fconf_populate_arm_io_policies); +FCONF_REGISTER_POPULATOR(TB_FW, arm_io, fconf_populate_arm_io_policies); #endif /* IMAGE_BL2 */ diff --git a/plat/arm/common/fconf/arm_fconf_sp.c b/plat/arm/common/fconf/arm_fconf_sp.c index bb88aff..9b6fa9b 100644 --- a/plat/arm/common/fconf/arm_fconf_sp.c +++ b/plat/arm/common/fconf/arm_fconf_sp.c @@ -102,6 +102,6 @@ return 0; } -FCONF_REGISTER_POPULATOR(arm_sp, fconf_populate_arm_sp); +FCONF_REGISTER_POPULATOR(TB_FW, arm_sp, fconf_populate_arm_sp); #endif /* IMAGE_BL2 */ diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c index cbbdfa2..2904ad9 100644 --- a/plat/arm/common/sp_min/arm_sp_min_setup.c +++ b/plat/arm/common/sp_min/arm_sp_min_setup.c @@ -217,7 +217,7 @@ * Perform the very early platform specific architectural setup here. At the * moment this only initializes the MMU ******************************************************************************/ -void sp_min_plat_arch_setup(void) +void arm_sp_min_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_BL_SP_MIN_TOTAL, @@ -232,3 +232,8 @@ enable_mmu_svc_mon(0); } + +void sp_min_plat_arch_setup(void) +{ + arm_sp_min_plat_arch_setup(); +}