xref: /rk3399_ARM-atf/plat/qemu/qemu_sbsa/sbsa_sip_svc.c (revision 4fc54c99d08926c2d42173902c8aaf3862722c84)
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 
509b076436SMarcin Juszkiewicz /*
519b076436SMarcin Juszkiewicz  * QEMU provides us with minimal information about hardware platform using
529b076436SMarcin Juszkiewicz  * minimalistic DeviceTree. This is not a Linux DeviceTree. It is not even
539b076436SMarcin Juszkiewicz  * a firmware DeviceTree.
549b076436SMarcin Juszkiewicz  *
559b076436SMarcin Juszkiewicz  * It is information passed from QEMU to describe the information a hardware
569b076436SMarcin Juszkiewicz  * platform would have other mechanisms to discover at runtime, that are
579b076436SMarcin Juszkiewicz  * affected by the QEMU command line.
589b076436SMarcin Juszkiewicz  *
599b076436SMarcin Juszkiewicz  * Ultimately this device tree will be replaced by IPC calls to an emulated SCP.
609b076436SMarcin Juszkiewicz  * And when we do that, we won't then have to rewrite Normal world firmware to
619b076436SMarcin Juszkiewicz  * cope.
629b076436SMarcin Juszkiewicz  */
639b076436SMarcin 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);
106*4fc54c99SMarcin Juszkiewicz 		} else {
107*4fc54c99SMarcin Juszkiewicz 			ERROR("Incomplete information for cpu %d in DeviceTree.\n", cpu);
108*4fc54c99SMarcin Juszkiewicz 			panic();
10942925c15SMarcin Juszkiewicz 		}
11042925c15SMarcin Juszkiewicz 
11142925c15SMarcin Juszkiewicz 		if (fdt_getprop(dtb, node, "numa-node-id", NULL))  {
11242925c15SMarcin Juszkiewicz 			fdt_read_uint32(dtb, node, "numa-node-id", &nodeid);
11342925c15SMarcin Juszkiewicz 		}
11442925c15SMarcin Juszkiewicz 
11542925c15SMarcin Juszkiewicz 		dynamic_platform_info.cpu[cpu].nodeid = nodeid;
11642925c15SMarcin Juszkiewicz 		dynamic_platform_info.cpu[cpu].mpidr = mpidr;
11742925c15SMarcin Juszkiewicz 
11842925c15SMarcin Juszkiewicz 		INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu, nodeid, mpidr);
11942925c15SMarcin Juszkiewicz 
12042925c15SMarcin Juszkiewicz 		cpu++;
12142925c15SMarcin Juszkiewicz 
12242925c15SMarcin Juszkiewicz 		prev = node;
12342925c15SMarcin Juszkiewicz 		node = fdt_next_subnode(dtb, prev);
12442925c15SMarcin Juszkiewicz 	}
12542925c15SMarcin Juszkiewicz 
12642925c15SMarcin Juszkiewicz 	dynamic_platform_info.num_cpus = cpu;
12742925c15SMarcin Juszkiewicz 	INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
12842925c15SMarcin Juszkiewicz }
12942925c15SMarcin Juszkiewicz 
1301e67b1b1SMarcin Juszkiewicz void read_platform_config_from_dt(void *dtb)
1311e67b1b1SMarcin Juszkiewicz {
1321e67b1b1SMarcin Juszkiewicz 	int node;
1331e67b1b1SMarcin Juszkiewicz 	const fdt64_t *data;
1341e67b1b1SMarcin Juszkiewicz 	int err;
1351e67b1b1SMarcin Juszkiewicz 	uintptr_t gicd_base;
1361e67b1b1SMarcin Juszkiewicz 	uintptr_t gicr_base;
1371e67b1b1SMarcin Juszkiewicz 
1381e67b1b1SMarcin Juszkiewicz 	/*
1391e67b1b1SMarcin Juszkiewicz 	 * QEMU gives us this DeviceTree node:
1401e67b1b1SMarcin Juszkiewicz 	 *
1411e67b1b1SMarcin Juszkiewicz 	 * intc {
1424171e981SMarcin Juszkiewicz 	 *	 reg = < 0x00 0x40060000 0x00 0x10000
1434171e981SMarcin Juszkiewicz 	 *		 0x00 0x40080000 0x00 0x4000000>;
1444171e981SMarcin Juszkiewicz 	 *       its {
1454171e981SMarcin Juszkiewicz 	 *               reg = <0x00 0x44081000 0x00 0x20000>;
1464171e981SMarcin Juszkiewicz 	 *       };
1474171e981SMarcin Juszkiewicz 	 * };
1481e67b1b1SMarcin Juszkiewicz 	 */
1491e67b1b1SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/intc");
1501e67b1b1SMarcin Juszkiewicz 	if (node < 0) {
1511e67b1b1SMarcin Juszkiewicz 		return;
1521e67b1b1SMarcin Juszkiewicz 	}
1531e67b1b1SMarcin Juszkiewicz 
1541e67b1b1SMarcin Juszkiewicz 	data = fdt_getprop(dtb, node, "reg", NULL);
1551e67b1b1SMarcin Juszkiewicz 	if (data == NULL) {
1561e67b1b1SMarcin Juszkiewicz 		return;
1571e67b1b1SMarcin Juszkiewicz 	}
1581e67b1b1SMarcin Juszkiewicz 
1591e67b1b1SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL);
1601e67b1b1SMarcin Juszkiewicz 	if (err < 0) {
1611e67b1b1SMarcin Juszkiewicz 		ERROR("Failed to read GICD reg property of GIC node\n");
1621e67b1b1SMarcin Juszkiewicz 		return;
1631e67b1b1SMarcin Juszkiewicz 	}
1641e67b1b1SMarcin Juszkiewicz 	INFO("GICD base = 0x%lx\n", gicd_base);
1651e67b1b1SMarcin Juszkiewicz 
1661e67b1b1SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL);
1671e67b1b1SMarcin Juszkiewicz 	if (err < 0) {
1681e67b1b1SMarcin Juszkiewicz 		ERROR("Failed to read GICR reg property of GIC node\n");
1691e67b1b1SMarcin Juszkiewicz 		return;
1701e67b1b1SMarcin Juszkiewicz 	}
1711e67b1b1SMarcin Juszkiewicz 	INFO("GICR base = 0x%lx\n", gicr_base);
1721e67b1b1SMarcin Juszkiewicz 
1731e67b1b1SMarcin Juszkiewicz 	sbsa_set_gic_bases(gicd_base, gicr_base);
1744171e981SMarcin Juszkiewicz 
1754171e981SMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/intc/its");
1764171e981SMarcin Juszkiewicz 	if (node < 0) {
1774171e981SMarcin Juszkiewicz 		return;
1784171e981SMarcin Juszkiewicz 	}
1794171e981SMarcin Juszkiewicz 
1804171e981SMarcin Juszkiewicz 	err = fdt_get_reg_props_by_index(dtb, node, 0, &gic_its_addr, NULL);
1814171e981SMarcin Juszkiewicz 	if (err < 0) {
1824171e981SMarcin Juszkiewicz 		ERROR("Failed to read GICI reg property of GIC node\n");
1834171e981SMarcin Juszkiewicz 		return;
1844171e981SMarcin Juszkiewicz 	}
1854171e981SMarcin Juszkiewicz 	INFO("GICI base = 0x%lx\n", gic_its_addr);
1861e67b1b1SMarcin Juszkiewicz }
1871e67b1b1SMarcin Juszkiewicz 
188c681d02cSMarcin Juszkiewicz void read_platform_version(void *dtb)
189c681d02cSMarcin Juszkiewicz {
190c681d02cSMarcin Juszkiewicz 	int node;
191c681d02cSMarcin Juszkiewicz 
192c681d02cSMarcin Juszkiewicz 	node = fdt_path_offset(dtb, "/");
193c681d02cSMarcin Juszkiewicz 	if (node >= 0) {
194c681d02cSMarcin Juszkiewicz 		platform_version_major = fdt32_ld(fdt_getprop(dtb, node,
195c681d02cSMarcin Juszkiewicz 							      "machine-version-major", NULL));
196c681d02cSMarcin Juszkiewicz 		platform_version_minor = fdt32_ld(fdt_getprop(dtb, node,
197c681d02cSMarcin Juszkiewicz 							      "machine-version-minor", NULL));
198c681d02cSMarcin Juszkiewicz 	}
199c681d02cSMarcin Juszkiewicz }
200c681d02cSMarcin Juszkiewicz 
201c681d02cSMarcin Juszkiewicz void sip_svc_init(void)
202c681d02cSMarcin Juszkiewicz {
203c681d02cSMarcin Juszkiewicz 	/* Read DeviceTree data before MMU is enabled */
204c681d02cSMarcin Juszkiewicz 
205c681d02cSMarcin Juszkiewicz 	void *dtb = (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
206c681d02cSMarcin Juszkiewicz 	int err;
207c681d02cSMarcin Juszkiewicz 
208c681d02cSMarcin Juszkiewicz 	err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE);
209c681d02cSMarcin Juszkiewicz 	if (err < 0) {
210c681d02cSMarcin Juszkiewicz 		ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
211c681d02cSMarcin Juszkiewicz 		return;
212c681d02cSMarcin Juszkiewicz 	}
213c681d02cSMarcin Juszkiewicz 
214c681d02cSMarcin Juszkiewicz 	err = fdt_check_header(dtb);
215c681d02cSMarcin Juszkiewicz 	if (err < 0) {
216c681d02cSMarcin Juszkiewicz 		ERROR("Invalid DTB file passed\n");
217c681d02cSMarcin Juszkiewicz 		return;
218c681d02cSMarcin Juszkiewicz 	}
219c681d02cSMarcin Juszkiewicz 
220c681d02cSMarcin Juszkiewicz 	read_platform_version(dtb);
221c681d02cSMarcin Juszkiewicz 	INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor);
2221e67b1b1SMarcin Juszkiewicz 
2231e67b1b1SMarcin Juszkiewicz 	read_platform_config_from_dt(dtb);
22442925c15SMarcin Juszkiewicz 	read_cpuinfo_from_dt(dtb);
225c681d02cSMarcin Juszkiewicz }
226c681d02cSMarcin Juszkiewicz 
227c681d02cSMarcin Juszkiewicz /*
228c681d02cSMarcin Juszkiewicz  * This function is responsible for handling all SiP calls from the NS world
229c681d02cSMarcin Juszkiewicz  */
230c681d02cSMarcin Juszkiewicz uintptr_t sbsa_sip_smc_handler(uint32_t smc_fid,
231c681d02cSMarcin Juszkiewicz 			       u_register_t x1,
232c681d02cSMarcin Juszkiewicz 			       u_register_t x2,
233c681d02cSMarcin Juszkiewicz 			       u_register_t x3,
234c681d02cSMarcin Juszkiewicz 			       u_register_t x4,
235c681d02cSMarcin Juszkiewicz 			       void *cookie,
236c681d02cSMarcin Juszkiewicz 			       void *handle,
237c681d02cSMarcin Juszkiewicz 			       u_register_t flags)
238c681d02cSMarcin Juszkiewicz {
239c681d02cSMarcin Juszkiewicz 	uint32_t ns;
24042925c15SMarcin Juszkiewicz 	uint64_t index;
241c681d02cSMarcin Juszkiewicz 
242c681d02cSMarcin Juszkiewicz 	/* Determine which security state this SMC originated from */
243c681d02cSMarcin Juszkiewicz 	ns = is_caller_non_secure(flags);
244c681d02cSMarcin Juszkiewicz 	if (!ns) {
245c681d02cSMarcin Juszkiewicz 		ERROR("%s: wrong world SMC (0x%x)\n", __func__, smc_fid);
246c681d02cSMarcin Juszkiewicz 		SMC_RET1(handle, SMC_UNK);
247c681d02cSMarcin Juszkiewicz 	}
248c681d02cSMarcin Juszkiewicz 
249c681d02cSMarcin Juszkiewicz 	switch (smc_fid) {
250c681d02cSMarcin Juszkiewicz 	case SIP_SVC_VERSION:
251c681d02cSMarcin Juszkiewicz 		INFO("Platform version requested\n");
252c681d02cSMarcin Juszkiewicz 		SMC_RET3(handle, NULL, platform_version_major, platform_version_minor);
253c681d02cSMarcin Juszkiewicz 
2541e67b1b1SMarcin Juszkiewicz 	case SIP_SVC_GET_GIC:
2551e67b1b1SMarcin Juszkiewicz 		SMC_RET3(handle, NULL, sbsa_get_gicd(), sbsa_get_gicr());
2561e67b1b1SMarcin Juszkiewicz 
2574171e981SMarcin Juszkiewicz 	case SIP_SVC_GET_GIC_ITS:
2584171e981SMarcin Juszkiewicz 		SMC_RET2(handle, NULL, gic_its_addr);
2594171e981SMarcin Juszkiewicz 
26042925c15SMarcin Juszkiewicz 	case SIP_SVC_GET_CPU_COUNT:
26142925c15SMarcin Juszkiewicz 		SMC_RET2(handle, NULL, dynamic_platform_info.num_cpus);
26242925c15SMarcin Juszkiewicz 
26342925c15SMarcin Juszkiewicz 	case SIP_SVC_GET_CPU_NODE:
26442925c15SMarcin Juszkiewicz 		index = x1;
26542925c15SMarcin Juszkiewicz 		if (index < PLATFORM_CORE_COUNT) {
26642925c15SMarcin Juszkiewicz 			SMC_RET3(handle, NULL,
26742925c15SMarcin Juszkiewicz 				dynamic_platform_info.cpu[index].nodeid,
26842925c15SMarcin Juszkiewicz 				dynamic_platform_info.cpu[index].mpidr);
26942925c15SMarcin Juszkiewicz 		} else {
27042925c15SMarcin Juszkiewicz 			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
27142925c15SMarcin Juszkiewicz 		}
27242925c15SMarcin Juszkiewicz 
273c681d02cSMarcin Juszkiewicz 	default:
274c681d02cSMarcin Juszkiewicz 		ERROR("%s: unhandled SMC (0x%x) (function id: %d)\n", __func__, smc_fid,
275c681d02cSMarcin Juszkiewicz 		      smc_fid - SIP_FUNCTION);
276c681d02cSMarcin Juszkiewicz 		SMC_RET1(handle, SMC_UNK);
277c681d02cSMarcin Juszkiewicz 	}
278c681d02cSMarcin Juszkiewicz }
279c681d02cSMarcin Juszkiewicz 
280c681d02cSMarcin Juszkiewicz int sbsa_sip_smc_setup(void)
281c681d02cSMarcin Juszkiewicz {
282c681d02cSMarcin Juszkiewicz 	return 0;
283c681d02cSMarcin Juszkiewicz }
284c681d02cSMarcin Juszkiewicz 
285c681d02cSMarcin Juszkiewicz /* Define a runtime service descriptor for fast SMC calls */
286c681d02cSMarcin Juszkiewicz DECLARE_RT_SVC(
287c681d02cSMarcin Juszkiewicz 	sbsa_sip_svc,
288c681d02cSMarcin Juszkiewicz 	OEN_SIP_START,
289c681d02cSMarcin Juszkiewicz 	OEN_SIP_END,
290c681d02cSMarcin Juszkiewicz 	SMC_TYPE_FAST,
291c681d02cSMarcin Juszkiewicz 	sbsa_sip_smc_setup,
292c681d02cSMarcin Juszkiewicz 	sbsa_sip_smc_handler
293c681d02cSMarcin Juszkiewicz );
294