xref: /rk3399_ARM-atf/plat/amd/versal2/plat_topology.c (revision 95b6c510b4044258754e791b48617640c956197c)
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 static const uint8_t plat_power_domain_tree_desc[] = {
27 	/* Number of root nodes */
28 	1,
29 	/* Number of clusters */
30 	PLATFORM_CLUSTER_COUNT,
31 	/* Number of children for the first cluster node */
32 	PLATFORM_CORE_COUNT_PER_CLUSTER,
33 	/* Number of children for the second cluster node */
34 	PLATFORM_CORE_COUNT_PER_CLUSTER,
35 	/* Number of children for the third cluster node */
36 	PLATFORM_CORE_COUNT_PER_CLUSTER,
37 	/* Number of children for the fourth cluster node */
38 	PLATFORM_CORE_COUNT_PER_CLUSTER,
39 };
40 
41 /* cluster and core updated at runtime */
42 static uint8_t plat_power_domain_tree_dyn[PLATFORM_CLUSTER_COUNT + PLAT_PWR_DOMAIN_PREFIX_SIZE] = {0};
43 
44 /*
45  * Parse DT /cpus and cpu-map to determine cluster/core topology.
46  * Returns 0 on success, <0 on error.
47  */
parse_dt_topology(uint8_t * out_clusters,uint8_t * out_cores_per_cluster,uint8_t * out_children_per_cluster,uint32_t max_clusters)48 static int32_t parse_dt_topology(uint8_t *out_clusters, uint8_t *out_cores_per_cluster,
49 		uint8_t *out_children_per_cluster, uint32_t max_clusters)
50 {
51 	void *dtb = (void *)plat_retrieve_dt_addr();
52 	int32_t cpus_off, cmap_off, cluster_off;
53 	int32_t ret = 0;
54 	int32_t core_off;
55 	uint8_t clusters = 0, cores = 0;
56 	const char *node_name;
57 	uint8_t i;
58 
59 	if (dtb == NULL) {
60 		ret = -FDT_ERR_NOTFOUND;
61 		goto exit_on_failure;
62 	}
63 
64 	ret = add_mmap_dynamic_region((unsigned long long)dtb,
65 			(uintptr_t)dtb,
66 			XILINX_OF_BOARD_DTB_MAX_SIZE,
67 			MT_MEMORY | MT_RO | MT_NS);
68 	if (ret != 0) {
69 		goto exit_on_failure;
70 	}
71 
72 	ret = fdt_check_header(dtb);
73 	if (ret < 0) {
74 		goto unmap_dtb;
75 	}
76 
77 	/* cpus node in DT */
78 	cpus_off = fdt_path_offset(dtb, "/cpus");
79 	if (cpus_off < 0) {
80 		ret = cpus_off;
81 		goto unmap_dtb;
82 	}
83 
84 	/* cpu-map dt path /cpus/cpu-map */
85 	cmap_off = fdt_subnode_offset(dtb, cpus_off, "cpu-map");
86 	if (cmap_off < 0) {
87 		ret = cmap_off;
88 		goto unmap_dtb;
89 	}
90 
91 	/* Count clusters under cpu-map */
92 	fdt_for_each_subnode(cluster_off, dtb, cmap_off) {
93 		/* Validate cluster node name */
94 		node_name = fdt_get_name(dtb, cluster_off, NULL);
95 		if ((node_name == NULL) || (strncmp(node_name, "cluster", 7) != 0)) {
96 			continue;
97 		}
98 
99 		if (clusters >= max_clusters) {
100 			WARN("cluster count exceeds max clusters: %u\n", max_clusters);
101 			break;
102 		}
103 
104 		/* Count cores in this cluster */
105 		fdt_for_each_subnode(core_off, dtb, cluster_off) {
106 			/* Validate core node name */
107 			node_name = fdt_get_name(dtb, core_off, NULL);
108 			if ((node_name == NULL) || (strncmp(node_name, "core", 4) != 0)) {
109 				continue;
110 			}
111 			cores++;
112 		}
113 
114 		/* If this cluster has no cores return error */
115 		if (cores == 0) {
116 			ret = E_INVALID_CORE_COUNT;
117 			goto unmap_dtb;
118 		}
119 
120 		out_children_per_cluster[clusters] = cores;
121 		clusters++;
122 		/* reset the core count for next cluster */
123 		cores = 0;
124 	}
125 
126 	if (clusters == 0) {
127 		ret = -FDT_ERR_NOTFOUND;
128 		goto unmap_dtb;
129 	}
130 
131 	/* Check if all clusters have the same number of cores */
132 	for (i = 1; i < clusters; i++) {
133 		if (out_children_per_cluster[i] != out_children_per_cluster[0]) {
134 			ret = E_INVALID_CORE_COUNT;
135 			WARN("Asymmetric cluster: cluster %u has %u cores, cluster0 has %u cores\n",
136 					i, out_children_per_cluster[i],
137 					out_children_per_cluster[0]);
138 			goto unmap_dtb;
139 		}
140 	}
141 
142 	*out_clusters = clusters;
143 	*out_cores_per_cluster = out_children_per_cluster[0];
144 
145 unmap_dtb:
146 	(void)remove_mmap_dynamic_region((uintptr_t)dtb,
147 			XILINX_OF_BOARD_DTB_MAX_SIZE);
148 
149 exit_on_failure:
150 	return ret;
151 }
152 
init_topology_from_dt(void)153 static int32_t init_topology_from_dt(void)
154 {
155 	static bool topology_initialized;
156 	static int32_t cached_result = E_INVALID_CORE_COUNT;
157 	uint8_t clusters = PLATFORM_CLUSTER_COUNT;
158 	uint8_t cores_per_cluster = PLATFORM_CORE_COUNT_PER_CLUSTER;
159 	uint8_t children[PLATFORM_CLUSTER_COUNT] = {0};
160 	int32_t ret = 0;
161 	uint8_t i;
162 
163 	if (topology_initialized) {
164 		ret = cached_result;
165 		goto done;
166 	}
167 
168 	ret = parse_dt_topology(&clusters, &cores_per_cluster, children, PLATFORM_CLUSTER_COUNT);
169 	if (ret != 0) {
170 		goto exit_on_failure;
171 	}
172 
173 	if ((clusters * cores_per_cluster) > PLATFORM_CORE_COUNT) {
174 		ERROR("cluster * core count exceeds max cores %u\n", PLATFORM_CORE_COUNT);
175 		ret = E_INVALID_CORE_COUNT;
176 		goto exit_on_failure;
177 	}
178 
179 	plat_cluster_count = clusters;
180 	plat_cores_per_cluster = cores_per_cluster;
181 
182 	plat_power_domain_tree_dyn[0] = 1;
183 	plat_power_domain_tree_dyn[1] = clusters;
184 
185 	for (i = 0; i < clusters; i++) {
186 		plat_power_domain_tree_dyn[PLAT_PWR_DOMAIN_PREFIX_SIZE + i] = children[i];
187 	}
188 
189 exit_on_failure:
190 	topology_initialized = true;
191 	cached_result = ret;
192 done:
193 	return ret;
194 }
195 
plat_get_power_domain_tree_desc(void)196 const uint8_t *plat_get_power_domain_tree_desc(void)
197 {
198 	const uint8_t *ret = NULL;
199 
200 	if (init_topology_from_dt() == 0) {
201 		ret = plat_power_domain_tree_dyn;
202 	} else {
203 		ret = plat_power_domain_tree_desc;
204 	}
205 
206 	return ret;
207 }
208