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/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c index 1a1d056..2952cde 100644 --- a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c +++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c @@ -12,6 +12,7 @@ #include struct gicv3_config_t gicv3_config; +struct hw_topology_t soc_topology; int fconf_populate_gicv3_config(uintptr_t config) { @@ -48,5 +49,120 @@ 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/include/fconf_hw_config_getter.h b/plat/arm/board/fvp/include/fconf_hw_config_getter.h index cc1576e..cab832f 100644 --- a/plat/arm/board/fvp/include/fconf_hw_config_getter.h +++ b/plat/arm/board/fvp/include/fconf_hw_config_getter.h @@ -12,13 +12,24 @@ /* 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/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