xref: /rk3399_ARM-atf/plat/qemu/qemu_sbsa/sbsa_platform.c (revision 95977c2e4dd7fd7ccce83d2b836bd54c3c60b425)
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 
read_cpu_topology_from_dt(void * dtb)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 
read_cpuinfo_from_dt(void * dtb)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 
read_meminfo_from_dt(void * dtb)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 
read_platform_config_from_dt(void * dtb)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 
read_platform_version(void * dtb)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
set_system_memory_base(void * dtb,uintptr_t new_base)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 */
set_system_memory_base(void * dtb,uintptr_t new_base)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 
sbsa_platform_init(void)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 
sbsa_platform_version_major(void)426ecadac7cSMathieu Poirier int sbsa_platform_version_major(void)
427ecadac7cSMathieu Poirier {
428ecadac7cSMathieu Poirier 	return platform_version_major;
429ecadac7cSMathieu Poirier }
430ecadac7cSMathieu Poirier 
sbsa_platform_version_minor(void)431ecadac7cSMathieu Poirier int sbsa_platform_version_minor(void)
432ecadac7cSMathieu Poirier {
433ecadac7cSMathieu Poirier 	return platform_version_minor;
434ecadac7cSMathieu Poirier }
435ecadac7cSMathieu Poirier 
sbsa_platform_num_cpus(void)436ecadac7cSMathieu Poirier uint32_t sbsa_platform_num_cpus(void)
437ecadac7cSMathieu Poirier {
438ecadac7cSMathieu Poirier 	return dynamic_platform_info.num_cpus;
439ecadac7cSMathieu Poirier }
440ecadac7cSMathieu Poirier 
sbsa_platform_num_memnodes(void)441ecadac7cSMathieu Poirier uint32_t sbsa_platform_num_memnodes(void)
442ecadac7cSMathieu Poirier {
443ecadac7cSMathieu Poirier 	return dynamic_platform_info.num_memnodes;
444ecadac7cSMathieu Poirier }
445ecadac7cSMathieu Poirier 
sbsa_platform_gic_its_addr(void)446ecadac7cSMathieu Poirier uint64_t sbsa_platform_gic_its_addr(void)
447ecadac7cSMathieu Poirier {
448ecadac7cSMathieu Poirier 	return gic_its_addr;
449ecadac7cSMathieu Poirier }
450ecadac7cSMathieu Poirier 
sbsa_platform_cpu_node(uint64_t index)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 
sbsa_platform_memory_node(uint64_t index)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 
sbsa_platform_cpu_topology(void)461ecadac7cSMathieu Poirier struct platform_cpu_topology sbsa_platform_cpu_topology(void)
462ecadac7cSMathieu Poirier {
463ecadac7cSMathieu Poirier 	return dynamic_platform_info.cpu_topo;
464ecadac7cSMathieu Poirier }
465