1 /* 2 * Copyright (c) 2024-2025, Linaro Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <common/fdt_wrappers.h> 10 #include <libfdt.h> 11 12 #include <sbsa_platform.h> 13 14 #include "qemu_private.h" 15 16 /* default platform version is 0.0 */ 17 static int platform_version_major; 18 static int platform_version_minor; 19 20 static uint64_t gic_its_addr; 21 static struct qemu_platform_info dynamic_platform_info; 22 23 void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base); 24 25 /* 26 * QEMU provides us with minimal information about hardware platform using 27 * minimalistic DeviceTree. This is not a Linux DeviceTree. It is not even 28 * a firmware DeviceTree. 29 * 30 * It is information passed from QEMU to describe the information a hardware 31 * platform would have other mechanisms to discover at runtime, that are 32 * affected by the QEMU command line. 33 * 34 * Ultimately this device tree will be replaced by IPC calls to an emulated SCP. 35 * And when we do that, we won't then have to rewrite Normal world firmware to 36 * cope. 37 */ 38 39 static void read_cpu_topology_from_dt(void *dtb) 40 { 41 int node; 42 43 /* 44 * QEMU gives us this DeviceTree node when we config: 45 * -smp 16,sockets=2,clusters=2,cores=2,threads=2 46 * 47 * topology { 48 * threads = <0x02>; 49 * cores = <0x02>; 50 * clusters = <0x02>; 51 * sockets = <0x02>; 52 * }; 53 */ 54 55 node = fdt_path_offset(dtb, "/cpus/topology"); 56 if (node > 0) { 57 dynamic_platform_info.cpu_topo.sockets = 58 fdt_read_uint32_default(dtb, node, "sockets", 0); 59 dynamic_platform_info.cpu_topo.clusters = 60 fdt_read_uint32_default(dtb, node, "clusters", 0); 61 dynamic_platform_info.cpu_topo.cores = 62 fdt_read_uint32_default(dtb, node, "cores", 0); 63 dynamic_platform_info.cpu_topo.threads = 64 fdt_read_uint32_default(dtb, node, "threads", 0); 65 } 66 67 INFO("Cpu topology: sockets: %d, clusters: %d, cores: %d, threads: %d\n", 68 dynamic_platform_info.cpu_topo.sockets, 69 dynamic_platform_info.cpu_topo.clusters, 70 dynamic_platform_info.cpu_topo.cores, 71 dynamic_platform_info.cpu_topo.threads); 72 } 73 74 static void read_cpuinfo_from_dt(void *dtb) 75 { 76 int node; 77 int prev; 78 int cpu = 0; 79 uintptr_t mpidr; 80 81 /* 82 * QEMU gives us this DeviceTree node: 83 * numa-node-id entries are only when NUMA config is used 84 * 85 * cpus { 86 * #size-cells = <0x00>; 87 * #address-cells = <0x02>; 88 * 89 * cpu@0 { 90 * numa-node-id = <0x00>; 91 * reg = <0x00 0x00>; 92 * }; 93 * 94 * cpu@1 { 95 * numa-node-id = <0x03>; 96 * reg = <0x00 0x01>; 97 * }; 98 * }; 99 */ 100 node = fdt_path_offset(dtb, "/cpus"); 101 if (node < 0) { 102 ERROR("No information about cpus in DeviceTree.\n"); 103 panic(); 104 } 105 106 /* 107 * QEMU numbers cpus from 0 and there can be /cpus/cpu-map present so we 108 * cannot use fdt_first_subnode() here 109 */ 110 node = fdt_path_offset(dtb, "/cpus/cpu@0"); 111 112 while (node > 0) { 113 if (fdt_getprop(dtb, node, "reg", NULL)) { 114 fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL); 115 } else { 116 ERROR("Incomplete information for cpu %d in DeviceTree.\n", cpu); 117 panic(); 118 } 119 120 dynamic_platform_info.cpu[cpu].mpidr = mpidr; 121 dynamic_platform_info.cpu[cpu].nodeid = 122 fdt_read_uint32_default(dtb, node, "numa-node-id", 0); 123 124 INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu, 125 dynamic_platform_info.cpu[cpu].nodeid, mpidr); 126 127 cpu++; 128 129 prev = node; 130 node = fdt_next_subnode(dtb, prev); 131 } 132 133 dynamic_platform_info.num_cpus = cpu; 134 INFO("Found %d cpus\n", dynamic_platform_info.num_cpus); 135 136 read_cpu_topology_from_dt(dtb); 137 } 138 139 static void read_meminfo_from_dt(void *dtb) 140 { 141 const fdt32_t *prop; 142 const char *type; 143 int prev, node; 144 int len; 145 uint32_t memnode = 0; 146 uint32_t higher_value, lower_value; 147 uint64_t cur_base, cur_size; 148 149 /* 150 * QEMU gives us this DeviceTree node: 151 * 152 * memory@100c0000000 { 153 * numa-node-id = <0x01>; 154 * reg = <0x100 0xc0000000 0x00 0x40000000>; 155 * device_type = "memory"; 156 * }; 157 * 158 * memory@10000000000 { 159 * numa-node-id = <0x00>; 160 * reg = <0x100 0x00 0x00 0xc0000000>; 161 * device_type = "memory"; 162 * } 163 */ 164 165 for (prev = 0;; prev = node) { 166 node = fdt_next_node(dtb, prev, NULL); 167 if (node < 0) { 168 break; 169 } 170 171 type = fdt_getprop(dtb, node, "device_type", &len); 172 if (type && strncmp(type, "memory", len) == 0) { 173 dynamic_platform_info.memory[memnode].nodeid = 174 fdt_read_uint32_default(dtb, node, "numa-node-id", 0); 175 176 /* 177 * Get the 'reg' property of this node and 178 * assume two 8 bytes for base and size. 179 */ 180 prop = fdt_getprop(dtb, node, "reg", &len); 181 if (prop != 0 && len == (2 * sizeof(int64_t))) { 182 higher_value = fdt32_to_cpu(*prop); 183 lower_value = fdt32_to_cpu(*(prop + 1)); 184 cur_base = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32); 185 186 higher_value = fdt32_to_cpu(*(prop + 2)); 187 lower_value = fdt32_to_cpu(*(prop + 3)); 188 cur_size = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32); 189 190 dynamic_platform_info.memory[memnode].addr_base = cur_base; 191 dynamic_platform_info.memory[memnode].addr_size = cur_size; 192 193 INFO("RAM %d: node-id: %d, address: 0x%lx - 0x%lx\n", 194 memnode, 195 dynamic_platform_info.memory[memnode].nodeid, 196 dynamic_platform_info.memory[memnode].addr_base, 197 dynamic_platform_info.memory[memnode].addr_base + 198 dynamic_platform_info.memory[memnode].addr_size - 1); 199 } 200 201 memnode++; 202 } 203 } 204 205 dynamic_platform_info.num_memnodes = memnode; 206 } 207 208 static void read_platform_config_from_dt(void *dtb) 209 { 210 int node; 211 const fdt64_t *data; 212 int err; 213 uintptr_t gicd_base; 214 uintptr_t gicr_base; 215 216 /* 217 * QEMU gives us this DeviceTree node: 218 * 219 * intc { 220 * reg = < 0x00 0x40060000 0x00 0x10000 221 * 0x00 0x40080000 0x00 0x4000000>; 222 * its { 223 * reg = <0x00 0x44081000 0x00 0x20000>; 224 * }; 225 * }; 226 */ 227 node = fdt_path_offset(dtb, "/intc"); 228 if (node < 0) { 229 return; 230 } 231 232 data = fdt_getprop(dtb, node, "reg", NULL); 233 if (data == NULL) { 234 return; 235 } 236 237 err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL); 238 if (err < 0) { 239 ERROR("Failed to read GICD reg property of GIC node\n"); 240 return; 241 } 242 INFO("GICD base = 0x%lx\n", gicd_base); 243 244 err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL); 245 if (err < 0) { 246 ERROR("Failed to read GICR reg property of GIC node\n"); 247 return; 248 } 249 INFO("GICR base = 0x%lx\n", gicr_base); 250 251 sbsa_set_gic_bases(gicd_base, gicr_base); 252 253 node = fdt_path_offset(dtb, "/intc/its"); 254 if (node < 0) { 255 return; 256 } 257 258 err = fdt_get_reg_props_by_index(dtb, node, 0, &gic_its_addr, NULL); 259 if (err < 0) { 260 ERROR("Failed to read GICI reg property of GIC node\n"); 261 return; 262 } 263 INFO("GICI base = 0x%lx\n", gic_its_addr); 264 } 265 266 static void read_platform_version(void *dtb) 267 { 268 int node; 269 270 node = fdt_path_offset(dtb, "/"); 271 if (node >= 0) { 272 platform_version_major = 273 fdt_read_uint32_default(dtb, node, "machine-version-major", 0); 274 platform_version_minor = 275 fdt_read_uint32_default(dtb, node, "machine-version-minor", 0); 276 } 277 } 278 279 #if !ENABLE_RME 280 static int set_system_memory_base(void *dtb, uintptr_t new_base) 281 { 282 (void)dtb; 283 (void)new_base; 284 285 return 0; 286 } 287 #else /* !ENABLE_RME */ 288 static int set_system_memory_base(void *dtb, uintptr_t new_base) 289 { 290 uint64_t cur_base, cur_size, new_size, delta; 291 int len, prev, node, ret; 292 const fdt32_t *prop; 293 uint32_t node_id; 294 const char *type; 295 fdt64_t new[2]; 296 297 /* 298 * QEMU gives us this DeviceTree node: 299 * 300 * memory@100c0000000 { 301 * numa-node-id = <0x01>; 302 * reg = <0x100 0xc0000000 0x00 0x40000000>; 303 * device_type = "memory"; 304 * }; 305 * 306 * memory@10000000000 { 307 * numa-node-id = <0x00>; 308 * reg = <0x100 0x00 0x00 0xc0000000>; 309 * device_type = "memory"; 310 * } 311 */ 312 313 for (prev = 0;; prev = node) { 314 node = fdt_next_node(dtb, prev, NULL); 315 if (node < 0) { 316 return node; 317 } 318 319 type = fdt_getprop(dtb, node, "device_type", &len); 320 if (type && strncmp(type, "memory", len) == 0) { 321 322 /* 323 * We are looking for numa node 0, i.e the start of the 324 * system memory. If a "numa-node-id" doesn't exists we 325 * take the first one. 326 */ 327 node_id = fdt_read_uint32_default(dtb, node, 328 "numa-node-id", 0); 329 330 if (node_id == 0) { 331 break; 332 } 333 } 334 } 335 336 /* 337 * Get the 'reg' property of this node and 338 * assume two 8 bytes for base and size. 339 */ 340 prop = fdt_getprop(dtb, node, "reg", &len); 341 if (!prop || len < 0) { 342 return len; 343 } 344 345 if (len != (2 * sizeof(uint64_t))) { 346 return -FDT_ERR_BADVALUE; 347 } 348 349 ret = fdt_get_reg_props_by_index(dtb, node, 0, &cur_base, &cur_size); 350 if (ret < 0) 351 return ret; 352 353 /* 354 * @cur_base is the base of the NS RAM given to us by QEMU, we can't 355 * go lower than that. 356 */ 357 if (new_base < cur_base) { 358 return -FDT_ERR_BADVALUE; 359 } 360 361 if (new_base == cur_base) { 362 return 0; 363 } 364 365 /* 366 * The new base is higher than the base set by QEMU, i.e we are moving 367 * the base memory up and shrinking the size. 368 */ 369 delta = (size_t)(new_base - cur_base); 370 371 /* 372 * Make sure the new base is still within the base memory node, i.e 373 * the base memory node is big enough for the RMM. 374 */ 375 if (delta >= cur_size) { 376 ERROR("Not enough space in base memory node for RMM\n"); 377 return -FDT_ERR_BADVALUE; 378 } 379 380 new_size = cur_size - delta; 381 382 new[0] = cpu_to_fdt64(new_base); 383 new[1] = cpu_to_fdt64(new_size); 384 385 ret = fdt_setprop(dtb, node, "reg", new, len); 386 if (ret < 0) { 387 return ret; 388 } 389 390 return fdt_pack(dtb); 391 } 392 #endif /* !ENABLE_RME */ 393 394 void sbsa_platform_init(void) 395 { 396 /* Read DeviceTree data before MMU is enabled */ 397 398 void *dtb = plat_qemu_dt_runtime_address(); 399 int err; 400 401 err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE); 402 if (err < 0) { 403 ERROR("Invalid Device Tree at %p: error %d\n", dtb, err); 404 return; 405 } 406 407 err = fdt_check_header(dtb); 408 if (err < 0) { 409 ERROR("Invalid DTB file passed\n"); 410 return; 411 } 412 413 read_platform_version(dtb); 414 INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor); 415 416 if (set_system_memory_base(dtb, NS_DRAM0_BASE)) { 417 ERROR("Failed to set system memory in Device Tree\n"); 418 return; 419 } 420 421 read_platform_config_from_dt(dtb); 422 read_cpuinfo_from_dt(dtb); 423 read_meminfo_from_dt(dtb); 424 } 425 426 int sbsa_platform_version_major(void) 427 { 428 return platform_version_major; 429 } 430 431 int sbsa_platform_version_minor(void) 432 { 433 return platform_version_minor; 434 } 435 436 uint32_t sbsa_platform_num_cpus(void) 437 { 438 return dynamic_platform_info.num_cpus; 439 } 440 441 uint32_t sbsa_platform_num_memnodes(void) 442 { 443 return dynamic_platform_info.num_memnodes; 444 } 445 446 uint64_t sbsa_platform_gic_its_addr(void) 447 { 448 return gic_its_addr; 449 } 450 451 struct platform_cpu_data sbsa_platform_cpu_node(uint64_t index) 452 { 453 return dynamic_platform_info.cpu[index]; 454 } 455 456 struct platform_memory_data sbsa_platform_memory_node(uint64_t index) 457 { 458 return dynamic_platform_info.memory[index]; 459 } 460 461 struct platform_cpu_topology sbsa_platform_cpu_topology(void) 462 { 463 return dynamic_platform_info.cpu_topo; 464 } 465