xref: /rk3399_ARM-atf/plat/qemu/qemu_sbsa/sbsa_sip_svc.c (revision 9b076436182dd6113e67e19f7b6080dc77c57141)
1c681d02cSMarcin Juszkiewicz /*
2c681d02cSMarcin Juszkiewicz  * Copyright (c) 2023, Linaro Limited and Contributors. All rights reserved.
3c681d02cSMarcin Juszkiewicz  *
4c681d02cSMarcin Juszkiewicz  * SPDX-License-Identifier: BSD-3-Clause
5c681d02cSMarcin Juszkiewicz  */
6c681d02cSMarcin Juszkiewicz 
7c681d02cSMarcin Juszkiewicz #include <assert.h>
8c681d02cSMarcin Juszkiewicz 
91e67b1b1SMarcin Juszkiewicz #include <common/fdt_wrappers.h>
10c681d02cSMarcin Juszkiewicz #include <common/runtime_svc.h>
11c681d02cSMarcin Juszkiewicz #include <libfdt.h>
12c681d02cSMarcin Juszkiewicz #include <smccc_helpers.h>
13c681d02cSMarcin Juszkiewicz 
14c681d02cSMarcin Juszkiewicz /* default platform version is 0.0 */
15c681d02cSMarcin Juszkiewicz static int platform_version_major;
16c681d02cSMarcin Juszkiewicz static int platform_version_minor;
17c681d02cSMarcin Juszkiewicz 
18c681d02cSMarcin Juszkiewicz #define SMC_FASTCALL       0x80000000
19c681d02cSMarcin Juszkiewicz #define SMC64_FUNCTION     (SMC_FASTCALL   | 0x40000000)
20c681d02cSMarcin Juszkiewicz #define SIP_FUNCTION       (SMC64_FUNCTION | 0x02000000)
21c681d02cSMarcin Juszkiewicz #define SIP_FUNCTION_ID(n) (SIP_FUNCTION   | (n))
22c681d02cSMarcin Juszkiewicz 
23c681d02cSMarcin Juszkiewicz /*
24c681d02cSMarcin Juszkiewicz  * We do not use SMCCC_ARCH_SOC_ID here because qemu_sbsa is virtual platform
25c681d02cSMarcin Juszkiewicz  * which uses SoC present in QEMU. And they can change on their own while we
26c681d02cSMarcin Juszkiewicz  * need version of whole 'virtual hardware platform'.
27c681d02cSMarcin Juszkiewicz  */
28c681d02cSMarcin Juszkiewicz #define SIP_SVC_VERSION  SIP_FUNCTION_ID(1)
291e67b1b1SMarcin Juszkiewicz #define SIP_SVC_GET_GIC  SIP_FUNCTION_ID(100)
304171e981SMarcin Juszkiewicz #define SIP_SVC_GET_GIC_ITS SIP_FUNCTION_ID(101)
3142925c15SMarcin Juszkiewicz #define SIP_SVC_GET_CPU_COUNT SIP_FUNCTION_ID(200)
3242925c15SMarcin Juszkiewicz #define SIP_SVC_GET_CPU_NODE SIP_FUNCTION_ID(201)
334171e981SMarcin Juszkiewicz 
344171e981SMarcin Juszkiewicz static uint64_t gic_its_addr;
351e67b1b1SMarcin Juszkiewicz 
3642925c15SMarcin Juszkiewicz typedef struct {
3742925c15SMarcin Juszkiewicz 	uint32_t nodeid;
3842925c15SMarcin Juszkiewicz 	uint32_t mpidr;
3942925c15SMarcin Juszkiewicz } cpu_data;
4042925c15SMarcin Juszkiewicz 
4142925c15SMarcin Juszkiewicz static struct {
4242925c15SMarcin Juszkiewicz 	uint32_t num_cpus;
4342925c15SMarcin Juszkiewicz 	cpu_data cpu[PLATFORM_CORE_COUNT];
4442925c15SMarcin Juszkiewicz } dynamic_platform_info;
4542925c15SMarcin Juszkiewicz 
461e67b1b1SMarcin Juszkiewicz void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base);
471e67b1b1SMarcin Juszkiewicz uintptr_t sbsa_get_gicd(void);
481e67b1b1SMarcin Juszkiewicz uintptr_t sbsa_get_gicr(void);
491e67b1b1SMarcin Juszkiewicz 
50*9b076436SMarcin Juszkiewicz /*
51*9b076436SMarcin Juszkiewicz  * QEMU provides us with minimal information about hardware platform using
52*9b076436SMarcin Juszkiewicz  * minimalistic DeviceTree. This is not a Linux DeviceTree. It is not even
53*9b076436SMarcin Juszkiewicz  * a firmware DeviceTree.
54*9b076436SMarcin Juszkiewicz  *
55*9b076436SMarcin Juszkiewicz  * It is information passed from QEMU to describe the information a hardware
56*9b076436SMarcin Juszkiewicz  * platform would have other mechanisms to discover at runtime, that are
57*9b076436SMarcin Juszkiewicz  * affected by the QEMU command line.
58*9b076436SMarcin Juszkiewicz  *
59*9b076436SMarcin Juszkiewicz  * Ultimately this device tree will be replaced by IPC calls to an emulated SCP.
60*9b076436SMarcin Juszkiewicz  * And when we do that, we won't then have to rewrite Normal world firmware to
61*9b076436SMarcin Juszkiewicz  * cope.
62*9b076436SMarcin Juszkiewicz  */
63*9b076436SMarcin Juszkiewicz 
6442925c15SMarcin Juszkiewicz void read_cpuinfo_from_dt(void *dtb)
6542925c15SMarcin Juszkiewicz {
6642925c15SMarcin Juszkiewicz 	int node;
6742925c15SMarcin Juszkiewicz 	int prev;
6842925c15SMarcin Juszkiewicz 	int cpu = 0;
6942925c15SMarcin Juszkiewicz 	uint32_t nodeid = 0;
7042925c15SMarcin Juszkiewicz 	uintptr_t mpidr;
7142925c15SMarcin Juszkiewicz 
7242925c15SMarcin Juszkiewicz 	/*
7342925c15SMarcin Juszkiewicz 	 * QEMU gives us this DeviceTree node:
7442925c15SMarcin Juszkiewicz 	 * numa-node-id entries are only when NUMA config is used
7542925c15SMarcin Juszkiewicz 	 *
7642925c15SMarcin Juszkiewicz 	 *  cpus {
7742925c15SMarcin Juszkiewicz 	 *  	#size-cells = <0x00>;
7842925c15SMarcin Juszkiewicz 	 *  	#address-cells = <0x02>;
7942925c15SMarcin Juszkiewicz 	 *
8042925c15SMarcin Juszkiewicz 	 *  	cpu@0 {
8142925c15SMarcin Juszkiewicz 	 *  	        numa-node-id = <0x00>;
8242925c15SMarcin Juszkiewicz 	 *  		reg = <0x00 0x00>;
8342925c15SMarcin Juszkiewicz 	 *  	};
8442925c15SMarcin Juszkiewicz 	 *
8542925c15SMarcin Juszkiewicz 	 *  	cpu@1 {
8642925c15SMarcin Juszkiewicz 	 *  	        numa-node-id = <0x03>;
8742925c15SMarcin Juszkiewicz 	 *  		reg = <0x00 0x01>;
8842925c15SMarcin Juszkiewicz 	 *  	};
8942925c15SMarcin Juszkiewicz 	 *  };
9042925c15SMarcin Juszkiewicz 	 */
9142925c15SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/cpus");
9242925c15SMarcin Juszkiewicz 	if (node < 0) {
9342925c15SMarcin Juszkiewicz 		ERROR("No information about cpus in DeviceTree.\n");
9442925c15SMarcin Juszkiewicz 		panic();
9542925c15SMarcin Juszkiewicz 	}
9642925c15SMarcin Juszkiewicz 
9742925c15SMarcin Juszkiewicz 	/*
9842925c15SMarcin Juszkiewicz 	 * QEMU numbers cpus from 0 and there can be /cpus/cpu-map present so we
9942925c15SMarcin Juszkiewicz 	 * cannot use fdt_first_subnode() here
10042925c15SMarcin Juszkiewicz 	 */
10142925c15SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/cpus/cpu@0");
10242925c15SMarcin Juszkiewicz 
10342925c15SMarcin Juszkiewicz 	while (node > 0) {
10442925c15SMarcin Juszkiewicz 		if (fdt_getprop(dtb, node, "reg", NULL)) {
10542925c15SMarcin Juszkiewicz 			fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
10642925c15SMarcin Juszkiewicz 		}
10742925c15SMarcin Juszkiewicz 
10842925c15SMarcin Juszkiewicz 		if (fdt_getprop(dtb, node, "numa-node-id", NULL))  {
10942925c15SMarcin Juszkiewicz 			fdt_read_uint32(dtb, node, "numa-node-id", &nodeid);
11042925c15SMarcin Juszkiewicz 		}
11142925c15SMarcin Juszkiewicz 
11242925c15SMarcin Juszkiewicz 		dynamic_platform_info.cpu[cpu].nodeid = nodeid;
11342925c15SMarcin Juszkiewicz 		dynamic_platform_info.cpu[cpu].mpidr = mpidr;
11442925c15SMarcin Juszkiewicz 
11542925c15SMarcin Juszkiewicz 		INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu, nodeid, mpidr);
11642925c15SMarcin Juszkiewicz 
11742925c15SMarcin Juszkiewicz 		cpu++;
11842925c15SMarcin Juszkiewicz 
11942925c15SMarcin Juszkiewicz 		prev = node;
12042925c15SMarcin Juszkiewicz 		node = fdt_next_subnode(dtb, prev);
12142925c15SMarcin Juszkiewicz 	}
12242925c15SMarcin Juszkiewicz 
12342925c15SMarcin Juszkiewicz 	dynamic_platform_info.num_cpus = cpu;
12442925c15SMarcin Juszkiewicz 	INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
12542925c15SMarcin Juszkiewicz }
12642925c15SMarcin Juszkiewicz 
1271e67b1b1SMarcin Juszkiewicz void read_platform_config_from_dt(void *dtb)
1281e67b1b1SMarcin Juszkiewicz {
1291e67b1b1SMarcin Juszkiewicz 	int node;
1301e67b1b1SMarcin Juszkiewicz 	const fdt64_t *data;
1311e67b1b1SMarcin Juszkiewicz 	int err;
1321e67b1b1SMarcin Juszkiewicz 	uintptr_t gicd_base;
1331e67b1b1SMarcin Juszkiewicz 	uintptr_t gicr_base;
1341e67b1b1SMarcin Juszkiewicz 
1351e67b1b1SMarcin Juszkiewicz 	/*
1361e67b1b1SMarcin Juszkiewicz 	 * QEMU gives us this DeviceTree node:
1371e67b1b1SMarcin Juszkiewicz 	 *
1381e67b1b1SMarcin Juszkiewicz 	 * intc {
1394171e981SMarcin Juszkiewicz 	 *	 reg = < 0x00 0x40060000 0x00 0x10000
1404171e981SMarcin Juszkiewicz 	 *		 0x00 0x40080000 0x00 0x4000000>;
1414171e981SMarcin Juszkiewicz 	 *       its {
1424171e981SMarcin Juszkiewicz 	 *               reg = <0x00 0x44081000 0x00 0x20000>;
1434171e981SMarcin Juszkiewicz 	 *       };
1444171e981SMarcin Juszkiewicz 	 * };
1451e67b1b1SMarcin Juszkiewicz 	 */
1461e67b1b1SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/intc");
1471e67b1b1SMarcin Juszkiewicz 	if (node < 0) {
1481e67b1b1SMarcin Juszkiewicz 		return;
1491e67b1b1SMarcin Juszkiewicz 	}
1501e67b1b1SMarcin Juszkiewicz 
1511e67b1b1SMarcin Juszkiewicz 	data = fdt_getprop(dtb, node, "reg", NULL);
1521e67b1b1SMarcin Juszkiewicz 	if (data == NULL) {
1531e67b1b1SMarcin Juszkiewicz 		return;
1541e67b1b1SMarcin Juszkiewicz 	}
1551e67b1b1SMarcin Juszkiewicz 
1561e67b1b1SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL);
1571e67b1b1SMarcin Juszkiewicz 	if (err < 0) {
1581e67b1b1SMarcin Juszkiewicz 		ERROR("Failed to read GICD reg property of GIC node\n");
1591e67b1b1SMarcin Juszkiewicz 		return;
1601e67b1b1SMarcin Juszkiewicz 	}
1611e67b1b1SMarcin Juszkiewicz 	INFO("GICD base = 0x%lx\n", gicd_base);
1621e67b1b1SMarcin Juszkiewicz 
1631e67b1b1SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL);
1641e67b1b1SMarcin Juszkiewicz 	if (err < 0) {
1651e67b1b1SMarcin Juszkiewicz 		ERROR("Failed to read GICR reg property of GIC node\n");
1661e67b1b1SMarcin Juszkiewicz 		return;
1671e67b1b1SMarcin Juszkiewicz 	}
1681e67b1b1SMarcin Juszkiewicz 	INFO("GICR base = 0x%lx\n", gicr_base);
1691e67b1b1SMarcin Juszkiewicz 
1701e67b1b1SMarcin Juszkiewicz 	sbsa_set_gic_bases(gicd_base, gicr_base);
1714171e981SMarcin Juszkiewicz 
1724171e981SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/intc/its");
1734171e981SMarcin Juszkiewicz 	if (node < 0) {
1744171e981SMarcin Juszkiewicz 		return;
1754171e981SMarcin Juszkiewicz 	}
1764171e981SMarcin Juszkiewicz 
1774171e981SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 0, &gic_its_addr, NULL);
1784171e981SMarcin Juszkiewicz 	if (err < 0) {
1794171e981SMarcin Juszkiewicz 		ERROR("Failed to read GICI reg property of GIC node\n");
1804171e981SMarcin Juszkiewicz 		return;
1814171e981SMarcin Juszkiewicz 	}
1824171e981SMarcin Juszkiewicz 	INFO("GICI base = 0x%lx\n", gic_its_addr);
1831e67b1b1SMarcin Juszkiewicz }
1841e67b1b1SMarcin Juszkiewicz 
185c681d02cSMarcin Juszkiewicz void read_platform_version(void *dtb)
186c681d02cSMarcin Juszkiewicz {
187c681d02cSMarcin Juszkiewicz 	int node;
188c681d02cSMarcin Juszkiewicz 
189c681d02cSMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/");
190c681d02cSMarcin Juszkiewicz 	if (node >= 0) {
191c681d02cSMarcin Juszkiewicz 		platform_version_major = fdt32_ld(fdt_getprop(dtb, node,
192c681d02cSMarcin Juszkiewicz 							      "machine-version-major", NULL));
193c681d02cSMarcin Juszkiewicz 		platform_version_minor = fdt32_ld(fdt_getprop(dtb, node,
194c681d02cSMarcin Juszkiewicz 							      "machine-version-minor", NULL));
195c681d02cSMarcin Juszkiewicz 	}
196c681d02cSMarcin Juszkiewicz }
197c681d02cSMarcin Juszkiewicz 
198c681d02cSMarcin Juszkiewicz void sip_svc_init(void)
199c681d02cSMarcin Juszkiewicz {
200c681d02cSMarcin Juszkiewicz 	/* Read DeviceTree data before MMU is enabled */
201c681d02cSMarcin Juszkiewicz 
202c681d02cSMarcin Juszkiewicz 	void *dtb = (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
203c681d02cSMarcin Juszkiewicz 	int err;
204c681d02cSMarcin Juszkiewicz 
205c681d02cSMarcin Juszkiewicz 	err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE);
206c681d02cSMarcin Juszkiewicz 	if (err < 0) {
207c681d02cSMarcin Juszkiewicz 		ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
208c681d02cSMarcin Juszkiewicz 		return;
209c681d02cSMarcin Juszkiewicz 	}
210c681d02cSMarcin Juszkiewicz 
211c681d02cSMarcin Juszkiewicz 	err = fdt_check_header(dtb);
212c681d02cSMarcin Juszkiewicz 	if (err < 0) {
213c681d02cSMarcin Juszkiewicz 		ERROR("Invalid DTB file passed\n");
214c681d02cSMarcin Juszkiewicz 		return;
215c681d02cSMarcin Juszkiewicz 	}
216c681d02cSMarcin Juszkiewicz 
217c681d02cSMarcin Juszkiewicz 	read_platform_version(dtb);
218c681d02cSMarcin Juszkiewicz 	INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor);
2191e67b1b1SMarcin Juszkiewicz 
2201e67b1b1SMarcin Juszkiewicz 	read_platform_config_from_dt(dtb);
22142925c15SMarcin Juszkiewicz 	read_cpuinfo_from_dt(dtb);
222c681d02cSMarcin Juszkiewicz }
223c681d02cSMarcin Juszkiewicz 
224c681d02cSMarcin Juszkiewicz /*
225c681d02cSMarcin Juszkiewicz  * This function is responsible for handling all SiP calls from the NS world
226c681d02cSMarcin Juszkiewicz  */
227c681d02cSMarcin Juszkiewicz uintptr_t sbsa_sip_smc_handler(uint32_t smc_fid,
228c681d02cSMarcin Juszkiewicz 			       u_register_t x1,
229c681d02cSMarcin Juszkiewicz 			       u_register_t x2,
230c681d02cSMarcin Juszkiewicz 			       u_register_t x3,
231c681d02cSMarcin Juszkiewicz 			       u_register_t x4,
232c681d02cSMarcin Juszkiewicz 			       void *cookie,
233c681d02cSMarcin Juszkiewicz 			       void *handle,
234c681d02cSMarcin Juszkiewicz 			       u_register_t flags)
235c681d02cSMarcin Juszkiewicz {
236c681d02cSMarcin Juszkiewicz 	uint32_t ns;
23742925c15SMarcin Juszkiewicz 	uint64_t index;
238c681d02cSMarcin Juszkiewicz 
239c681d02cSMarcin Juszkiewicz 	/* Determine which security state this SMC originated from */
240c681d02cSMarcin Juszkiewicz 	ns = is_caller_non_secure(flags);
241c681d02cSMarcin Juszkiewicz 	if (!ns) {
242c681d02cSMarcin Juszkiewicz 		ERROR("%s: wrong world SMC (0x%x)\n", __func__, smc_fid);
243c681d02cSMarcin Juszkiewicz 		SMC_RET1(handle, SMC_UNK);
244c681d02cSMarcin Juszkiewicz 	}
245c681d02cSMarcin Juszkiewicz 
246c681d02cSMarcin Juszkiewicz 	switch (smc_fid) {
247c681d02cSMarcin Juszkiewicz 	case SIP_SVC_VERSION:
248c681d02cSMarcin Juszkiewicz 		INFO("Platform version requested\n");
249c681d02cSMarcin Juszkiewicz 		SMC_RET3(handle, NULL, platform_version_major, platform_version_minor);
250c681d02cSMarcin Juszkiewicz 
2511e67b1b1SMarcin Juszkiewicz 	case SIP_SVC_GET_GIC:
2521e67b1b1SMarcin Juszkiewicz 		SMC_RET3(handle, NULL, sbsa_get_gicd(), sbsa_get_gicr());
2531e67b1b1SMarcin Juszkiewicz 
2544171e981SMarcin Juszkiewicz 	case SIP_SVC_GET_GIC_ITS:
2554171e981SMarcin Juszkiewicz 		SMC_RET2(handle, NULL, gic_its_addr);
2564171e981SMarcin Juszkiewicz 
25742925c15SMarcin Juszkiewicz 	case SIP_SVC_GET_CPU_COUNT:
25842925c15SMarcin Juszkiewicz 		SMC_RET2(handle, NULL, dynamic_platform_info.num_cpus);
25942925c15SMarcin Juszkiewicz 
26042925c15SMarcin Juszkiewicz 	case SIP_SVC_GET_CPU_NODE:
26142925c15SMarcin Juszkiewicz 		index = x1;
26242925c15SMarcin Juszkiewicz 		if (index < PLATFORM_CORE_COUNT) {
26342925c15SMarcin Juszkiewicz 			SMC_RET3(handle, NULL,
26442925c15SMarcin Juszkiewicz 				dynamic_platform_info.cpu[index].nodeid,
26542925c15SMarcin Juszkiewicz 				dynamic_platform_info.cpu[index].mpidr);
26642925c15SMarcin Juszkiewicz 		} else {
26742925c15SMarcin Juszkiewicz 			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
26842925c15SMarcin Juszkiewicz 		}
26942925c15SMarcin Juszkiewicz 
270c681d02cSMarcin Juszkiewicz 	default:
271c681d02cSMarcin Juszkiewicz 		ERROR("%s: unhandled SMC (0x%x) (function id: %d)\n", __func__, smc_fid,
272c681d02cSMarcin Juszkiewicz 		      smc_fid - SIP_FUNCTION);
273c681d02cSMarcin Juszkiewicz 		SMC_RET1(handle, SMC_UNK);
274c681d02cSMarcin Juszkiewicz 	}
275c681d02cSMarcin Juszkiewicz }
276c681d02cSMarcin Juszkiewicz 
277c681d02cSMarcin Juszkiewicz int sbsa_sip_smc_setup(void)
278c681d02cSMarcin Juszkiewicz {
279c681d02cSMarcin Juszkiewicz 	return 0;
280c681d02cSMarcin Juszkiewicz }
281c681d02cSMarcin Juszkiewicz 
282c681d02cSMarcin Juszkiewicz /* Define a runtime service descriptor for fast SMC calls */
283c681d02cSMarcin Juszkiewicz DECLARE_RT_SVC(
284c681d02cSMarcin Juszkiewicz 	sbsa_sip_svc,
285c681d02cSMarcin Juszkiewicz 	OEN_SIP_START,
286c681d02cSMarcin Juszkiewicz 	OEN_SIP_END,
287c681d02cSMarcin Juszkiewicz 	SMC_TYPE_FAST,
288c681d02cSMarcin Juszkiewicz 	sbsa_sip_smc_setup,
289c681d02cSMarcin Juszkiewicz 	sbsa_sip_smc_handler
290c681d02cSMarcin Juszkiewicz );
291