1 /* 2 * Copyright (c) 2020, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <common/debug.h> 9 #include <common/fdt_wrappers.h> 10 #include <fconf_hw_config_getter.h> 11 #include <libfdt.h> 12 #include <plat/common/platform.h> 13 14 struct gicv3_config_t gicv3_config; 15 struct hw_topology_t soc_topology; 16 17 int fconf_populate_gicv3_config(uintptr_t config) 18 { 19 int err; 20 int node; 21 uintptr_t addr; 22 23 /* Necessary to work with libfdt APIs */ 24 const void *hw_config_dtb = (const void *)config; 25 26 /* 27 * Find the offset of the node containing "arm,gic-v3" compatible property. 28 * Populating fconf strucutures dynamically is not supported for legacy 29 * systems which use GICv2 IP. Simply skip extracting GIC properties. 30 */ 31 node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3"); 32 if (node < 0) { 33 WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n"); 34 return 0; 35 } 36 /* The GICv3 DT binding holds at least two address/size pairs, 37 * the first describing the distributor, the second the redistributors. 38 * See: bindings/interrupt-controller/arm,gic-v3.yaml 39 */ 40 err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL); 41 if (err < 0) { 42 ERROR("FCONF: Failed to read GICD reg property of GIC node\n"); 43 return err; 44 } 45 gicv3_config.gicd_base = addr; 46 47 err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL); 48 if (err < 0) { 49 ERROR("FCONF: Failed to read GICR reg property of GIC node\n"); 50 } else { 51 gicv3_config.gicr_base = addr; 52 } 53 54 return err; 55 } 56 57 int fconf_populate_topology(uintptr_t config) 58 { 59 int err, node, cluster_node, core_node, thread_node; 60 uint32_t cluster_count = 0, max_cpu_per_cluster = 0, total_cpu_count = 0; 61 uint32_t max_pwr_lvl = 0; 62 63 /* Necessary to work with libfdt APIs */ 64 const void *hw_config_dtb = (const void *)config; 65 66 /* Find the offset of the node containing "arm,psci-1.0" compatible property */ 67 node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,psci-1.0"); 68 if (node < 0) { 69 ERROR("FCONF: Unable to locate node with arm,psci-1.0 compatible property\n"); 70 return node; 71 } 72 73 err = fdt_read_uint32(hw_config_dtb, node, "max-pwr-lvl", &max_pwr_lvl); 74 if (err < 0) { 75 /* 76 * Some legacy FVP dts may not have this property. Assign the default 77 * value. 78 */ 79 WARN("FCONF: Could not locate max-pwr-lvl property\n"); 80 max_pwr_lvl = 2; 81 } 82 83 assert(max_pwr_lvl <= MPIDR_AFFLVL2); 84 85 /* Find the offset of the "cpus" node */ 86 node = fdt_path_offset(hw_config_dtb, "/cpus"); 87 if (node < 0) { 88 ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpus"); 89 return node; 90 } 91 92 /* A typical cpu-map node in a device tree is shown here for reference 93 cpu-map { 94 cluster0 { 95 core0 { 96 cpu = <&CPU0>; 97 }; 98 core1 { 99 cpu = <&CPU1>; 100 }; 101 }; 102 103 cluster1 { 104 core0 { 105 cpu = <&CPU2>; 106 }; 107 core1 { 108 cpu = <&CPU3>; 109 }; 110 }; 111 }; 112 */ 113 114 /* Locate the cpu-map child node */ 115 node = fdt_subnode_offset(hw_config_dtb, node, "cpu-map"); 116 if (node < 0) { 117 ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpu-map"); 118 return node; 119 } 120 121 uint32_t cpus_per_cluster[PLAT_ARM_CLUSTER_COUNT] = {0}; 122 123 /* Iterate through cluster nodes */ 124 fdt_for_each_subnode(cluster_node, hw_config_dtb, node) { 125 assert(cluster_count < PLAT_ARM_CLUSTER_COUNT); 126 127 /* Iterate through core nodes */ 128 fdt_for_each_subnode(core_node, hw_config_dtb, cluster_node) { 129 /* core nodes may have child nodes i.e., "thread" nodes */ 130 if (fdt_first_subnode(hw_config_dtb, core_node) < 0) { 131 cpus_per_cluster[cluster_count]++; 132 } else { 133 /* Multi-threaded CPU description is found in dtb */ 134 fdt_for_each_subnode(thread_node, hw_config_dtb, core_node) { 135 cpus_per_cluster[cluster_count]++; 136 } 137 138 /* Since in some dtbs, core nodes may not have thread node, 139 * no need to error if even one child node is not found. 140 */ 141 } 142 } 143 144 /* Ensure every cluster node has at least 1 child node */ 145 if (cpus_per_cluster[cluster_count] < 1U) { 146 ERROR("FCONF: Unable to locate the core node in cluster %d\n", cluster_count); 147 return -1; 148 } 149 150 INFO("CLUSTER ID: %d cpu-count: %d\n", cluster_count, cpus_per_cluster[cluster_count]); 151 152 /* Find the maximum number of cpus in any cluster */ 153 max_cpu_per_cluster = MAX(max_cpu_per_cluster, cpus_per_cluster[cluster_count]); 154 total_cpu_count += cpus_per_cluster[cluster_count]; 155 cluster_count++; 156 } 157 158 159 /* At least one cluster node is expected in hardware configuration dtb */ 160 if (cluster_count < 1U) { 161 ERROR("FCONF: Unable to locate the cluster node in cpu-map node\n"); 162 return -1; 163 } 164 165 soc_topology.plat_max_pwr_level = max_pwr_lvl; 166 soc_topology.plat_cluster_count = cluster_count; 167 soc_topology.cluster_cpu_count = max_cpu_per_cluster; 168 soc_topology.plat_cpu_count = total_cpu_count; 169 170 return 0; 171 } 172 173 FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config); 174 FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology); 175