blob: 2952cde80d2298f31bf13b8f06ced1adfbba8e27 [file] [log] [blame]
Madhukar Pappireddyae9677b2020-01-27 13:37:51 -06001/*
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
14struct gicv3_config_t gicv3_config;
Madhukar Pappireddy26b945c2019-12-27 12:02:34 -060015struct hw_topology_t soc_topology;
Madhukar Pappireddyae9677b2020-01-27 13:37:51 -060016
17int fconf_populate_gicv3_config(uintptr_t config)
18{
19 int err;
20 int node;
21 int addr[20];
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 /* Read the reg cell holding base address of GIC controller modules
37 A sample reg cell array is shown here:
38 reg = <0x0 0x2f000000 0 0x10000>, // GICD
39 <0x0 0x2f100000 0 0x200000>, // GICR
40 <0x0 0x2c000000 0 0x2000>, // GICC
41 <0x0 0x2c010000 0 0x2000>, // GICH
42 <0x0 0x2c02f000 0 0x2000>; // GICV
43 */
44
45 err = fdtw_read_array(hw_config_dtb, node, "reg", 20, &addr);
46 if (err < 0) {
47 ERROR("FCONF: Failed to read reg property of GIC node\n");
48 }
49 return err;
50}
51
Madhukar Pappireddy26b945c2019-12-27 12:02:34 -060052int fconf_populate_topology(uintptr_t config)
53{
54 int err, node, cluster_node, core_node, thread_node, max_pwr_lvl = 0;
55 uint32_t cluster_count = 0, max_cpu_per_cluster = 0, total_cpu_count = 0;
56
57 /* Necessary to work with libfdt APIs */
58 const void *hw_config_dtb = (const void *)config;
59
60 /* Find the offset of the node containing "arm,psci-1.0" compatible property */
61 node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,psci-1.0");
62 if (node < 0) {
63 ERROR("FCONF: Unable to locate node with arm,psci-1.0 compatible property\n");
64 return node;
65 }
66
67 err = fdtw_read_cells(hw_config_dtb, node, "max-pwr-lvl", 1, &max_pwr_lvl);
68 if (err < 0) {
69 /*
70 * Some legacy FVP dts may not have this property. Assign the default
71 * value.
72 */
73 WARN("FCONF: Could not locate max-pwr-lvl property\n");
74 max_pwr_lvl = 2;
75 }
76
77 assert((uint32_t)max_pwr_lvl <= MPIDR_AFFLVL2);
78
79 /* Find the offset of the "cpus" node */
80 node = fdt_path_offset(hw_config_dtb, "/cpus");
81 if (node < 0) {
82 ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpus");
83 return node;
84 }
85
86 /* A typical cpu-map node in a device tree is shown here for reference
87 cpu-map {
88 cluster0 {
89 core0 {
90 cpu = <&CPU0>;
91 };
92 core1 {
93 cpu = <&CPU1>;
94 };
95 };
96
97 cluster1 {
98 core0 {
99 cpu = <&CPU2>;
100 };
101 core1 {
102 cpu = <&CPU3>;
103 };
104 };
105 };
106 */
107
108 /* Locate the cpu-map child node */
109 node = fdt_subnode_offset(hw_config_dtb, node, "cpu-map");
110 if (node < 0) {
111 ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpu-map");
112 return node;
113 }
114
115 uint32_t cpus_per_cluster[PLAT_ARM_CLUSTER_COUNT] = {0};
116
117 /* Iterate through cluster nodes */
118 fdt_for_each_subnode(cluster_node, hw_config_dtb, node) {
119 assert(cluster_count < PLAT_ARM_CLUSTER_COUNT);
120
121 /* Iterate through core nodes */
122 fdt_for_each_subnode(core_node, hw_config_dtb, cluster_node) {
123 /* core nodes may have child nodes i.e., "thread" nodes */
124 if (fdt_first_subnode(hw_config_dtb, core_node) < 0) {
125 cpus_per_cluster[cluster_count]++;
126 } else {
127 /* Multi-threaded CPU description is found in dtb */
128 fdt_for_each_subnode(thread_node, hw_config_dtb, core_node) {
129 cpus_per_cluster[cluster_count]++;
130 }
131
132 /* Since in some dtbs, core nodes may not have thread node,
133 * no need to error if even one child node is not found.
134 */
135 }
136 }
137
138 /* Ensure every cluster node has at least 1 child node */
139 if (cpus_per_cluster[cluster_count] < 1U) {
140 ERROR("FCONF: Unable to locate the core node in cluster %d\n", cluster_count);
141 return -1;
142 }
143
144 INFO("CLUSTER ID: %d cpu-count: %d\n", cluster_count, cpus_per_cluster[cluster_count]);
145
146 /* Find the maximum number of cpus in any cluster */
147 max_cpu_per_cluster = MAX(max_cpu_per_cluster, cpus_per_cluster[cluster_count]);
148 total_cpu_count += cpus_per_cluster[cluster_count];
149 cluster_count++;
150 }
151
152
153 /* At least one cluster node is expected in hardware configuration dtb */
154 if (cluster_count < 1U) {
155 ERROR("FCONF: Unable to locate the cluster node in cpu-map node\n");
156 return -1;
157 }
158
159 soc_topology.plat_max_pwr_level = (uint32_t)max_pwr_lvl;
160 soc_topology.plat_cluster_count = cluster_count;
161 soc_topology.cluster_cpu_count = max_cpu_per_cluster;
162 soc_topology.plat_cpu_count = total_cpu_count;
163
164 return 0;
165}
Madhukar Pappireddyae9677b2020-01-27 13:37:51 -0600166
167FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config);
Madhukar Pappireddy26b945c2019-12-27 12:02:34 -0600168FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology);