xref: /rk3399_ARM-atf/plat/amd/versal2/plat_topology.c (revision 74c7f3f934091ed1e58ca0189fd0f30a89edc5a5)
1 /*
2  * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
3  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
4  * Copyright (c) 2022-2026, Advanced Micro Devices, Inc. All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include <libfdt.h>
10 
11 #include <common/debug.h>
12 #include <plat/common/platform.h>
13 
14 #include <plat_fdt.h>
15 #include <platform_def.h>
16 
17 #include <plat_private.h>
18 
19 /* Global definition of primary core variable */
20 uint32_t plat_primary_cpu_core = PLAT_INVALID_CPU_CORE;
21 
22 /* Global definition of core and cluster variables defaulting to fixed configuration */
23 uint32_t plat_cluster_count = PLATFORM_CLUSTER_COUNT;
24 uint32_t plat_cores_per_cluster = PLATFORM_CORE_COUNT_PER_CLUSTER;
25 
26 #if VERSAL2_VARIANT == 14
27 static const uint8_t plat_power_domain_tree_desc[] = {
28 	/* Number of root nodes */
29 	1,
30 	/* Number of clusters */
31 	PLATFORM_CLUSTER_COUNT,
32 	/* Number of children for the only cluster node */
33 	PLATFORM_CORE_COUNT_PER_CLUSTER,
34 };
35 #elif VERSAL2_VARIANT == 42
36 static const uint8_t plat_power_domain_tree_desc[] = {
37 	/* Number of root nodes */
38 	1,
39 	/* Number of clusters */
40 	PLATFORM_CLUSTER_COUNT,
41 	/* Number of children for the first cluster node */
42 	PLATFORM_CORE_COUNT_PER_CLUSTER,
43 	/* Number of children for the second cluster node */
44 	PLATFORM_CORE_COUNT_PER_CLUSTER,
45 	/* Number of children for the third cluster node */
46 	PLATFORM_CORE_COUNT_PER_CLUSTER,
47 	/* Number of children for the fourth cluster node */
48 	PLATFORM_CORE_COUNT_PER_CLUSTER,
49 };
50 #endif
51 
52 #if VERSAL2_VARIANT == 42
53 /* cluster and core updated at runtime */
54 static uint8_t plat_power_domain_tree_dyn[PLATFORM_CLUSTER_COUNT + PLAT_PWR_DOMAIN_PREFIX_SIZE] = {0};
55 
56 /*
57  * Parse DT /cpus and cpu-map to determine cluster/core topology.
58  * Returns 0 on success, <0 on error.
59  */
parse_dt_topology(uint8_t * out_clusters,uint8_t * out_cores_per_cluster,uint8_t * out_children_per_cluster,uint32_t max_clusters)60 static int32_t parse_dt_topology(uint8_t *out_clusters, uint8_t *out_cores_per_cluster,
61 		uint8_t *out_children_per_cluster, uint32_t max_clusters)
62 {
63 	void *dtb = (void *)plat_retrieve_dt_addr();
64 	int32_t cpus_off, cmap_off, cluster_off;
65 	int32_t ret = 0;
66 	int32_t core_off;
67 	uint8_t clusters = 0, cores = 0;
68 	const char *node_name;
69 	uint8_t i;
70 
71 	if (dtb == NULL) {
72 		ret = -FDT_ERR_NOTFOUND;
73 		goto exit_on_failure;
74 	}
75 
76 	ret = add_mmap_dynamic_region((unsigned long long)dtb,
77 			(uintptr_t)dtb,
78 			XILINX_OF_BOARD_DTB_MAX_SIZE,
79 			MT_MEMORY | MT_RO | MT_NS);
80 	if (ret != 0) {
81 		goto exit_on_failure;
82 	}
83 
84 	ret = fdt_check_header(dtb);
85 	if (ret < 0) {
86 		goto unmap_dtb;
87 	}
88 
89 	/* cpus node in DT */
90 	cpus_off = fdt_path_offset(dtb, "/cpus");
91 	if (cpus_off < 0) {
92 		ret = cpus_off;
93 		goto unmap_dtb;
94 	}
95 
96 	/* cpu-map dt path /cpus/cpu-map */
97 	cmap_off = fdt_subnode_offset(dtb, cpus_off, "cpu-map");
98 	if (cmap_off < 0) {
99 		ret = cmap_off;
100 		goto unmap_dtb;
101 	}
102 
103 	/* Count clusters under cpu-map */
104 	fdt_for_each_subnode(cluster_off, dtb, cmap_off) {
105 		/* Validate cluster node name */
106 		node_name = fdt_get_name(dtb, cluster_off, NULL);
107 		if ((node_name == NULL) || (strncmp(node_name, "cluster", 7) != 0)) {
108 			continue;
109 		}
110 
111 		if (clusters >= max_clusters) {
112 			WARN("cluster count exceeds max clusters: %u\n", max_clusters);
113 			break;
114 		}
115 
116 		/* Count cores in this cluster */
117 		fdt_for_each_subnode(core_off, dtb, cluster_off) {
118 			/* Validate core node name */
119 			node_name = fdt_get_name(dtb, core_off, NULL);
120 			if ((node_name == NULL) || (strncmp(node_name, "core", 4) != 0)) {
121 				continue;
122 			}
123 			cores++;
124 		}
125 
126 		/* If this cluster has no cores return error */
127 		if (cores == 0) {
128 			ret = E_INVALID_CORE_COUNT;
129 			goto unmap_dtb;
130 		}
131 
132 		out_children_per_cluster[clusters] = cores;
133 		clusters++;
134 		/* reset the core count for next cluster */
135 		cores = 0;
136 	}
137 
138 	if (clusters == 0) {
139 		ret = -FDT_ERR_NOTFOUND;
140 		goto unmap_dtb;
141 	}
142 
143 	/* Check if all clusters have the same number of cores */
144 	for (i = 1; i < clusters; i++) {
145 		if (out_children_per_cluster[i] != out_children_per_cluster[0]) {
146 			ret = E_INVALID_CORE_COUNT;
147 			WARN("Asymmetric cluster: cluster %u has %u cores, cluster0 has %u cores\n",
148 					i, out_children_per_cluster[i],
149 					out_children_per_cluster[0]);
150 			goto unmap_dtb;
151 		}
152 	}
153 
154 	*out_clusters = clusters;
155 	*out_cores_per_cluster = out_children_per_cluster[0];
156 
157 unmap_dtb:
158 	(void)remove_mmap_dynamic_region((uintptr_t)dtb,
159 			XILINX_OF_BOARD_DTB_MAX_SIZE);
160 
161 exit_on_failure:
162 	return ret;
163 }
164 
init_topology_from_dt(void)165 static int32_t init_topology_from_dt(void)
166 {
167 	static bool topology_initialized;
168 	static int32_t cached_result = E_INVALID_CORE_COUNT;
169 	uint8_t clusters = PLATFORM_CLUSTER_COUNT;
170 	uint8_t cores_per_cluster = PLATFORM_CORE_COUNT_PER_CLUSTER;
171 	uint8_t children[PLATFORM_CLUSTER_COUNT] = {0};
172 	int32_t ret = 0;
173 	uint8_t i;
174 
175 	if (topology_initialized) {
176 		ret = cached_result;
177 		goto done;
178 	}
179 
180 	ret = parse_dt_topology(&clusters, &cores_per_cluster, children, PLATFORM_CLUSTER_COUNT);
181 	if (ret != 0) {
182 		goto exit_on_failure;
183 	}
184 
185 	if ((clusters * cores_per_cluster) > PLATFORM_CORE_COUNT) {
186 		ERROR("cluster * core count exceeds max cores %u\n", PLATFORM_CORE_COUNT);
187 		ret = E_INVALID_CORE_COUNT;
188 		goto exit_on_failure;
189 	}
190 
191 	plat_cluster_count = clusters;
192 	plat_cores_per_cluster = cores_per_cluster;
193 
194 	plat_power_domain_tree_dyn[0] = 1;
195 	plat_power_domain_tree_dyn[1] = clusters;
196 
197 	for (i = 0; i < clusters; i++) {
198 		plat_power_domain_tree_dyn[PLAT_PWR_DOMAIN_PREFIX_SIZE + i] = children[i];
199 	}
200 
201 exit_on_failure:
202 	topology_initialized = true;
203 	cached_result = ret;
204 done:
205 	return ret;
206 }
207 #endif
208 
plat_get_power_domain_tree_desc(void)209 const uint8_t *plat_get_power_domain_tree_desc(void)
210 {
211 	const uint8_t *ret = NULL;
212 
213 #if VERSAL2_VARIANT == 14
214 	ret = plat_power_domain_tree_desc;
215 #elif VERSAL2_VARIANT == 42
216 	if (init_topology_from_dt() == 0) {
217 		ret = plat_power_domain_tree_dyn;
218 	} else {
219 		ret = plat_power_domain_tree_desc;
220 	}
221 #endif
222 
223 	return ret;
224 }
225