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