xref: /optee_os/core/drivers/versal_pm.c (revision e4c76cc2a69cd88b0b5ec973b4b58ff1a42eafe3)
140e40cd2SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
240e40cd2SJorge Ramirez-Ortiz /*
340e40cd2SJorge Ramirez-Ortiz  * Copyright (C) 2022 Foundries.io Ltd
440e40cd2SJorge Ramirez-Ortiz  * Jorge Ramirez-Ortiz <jorge@foundries.io>
540e40cd2SJorge Ramirez-Ortiz  */
640e40cd2SJorge Ramirez-Ortiz 
740e40cd2SJorge Ramirez-Ortiz #include <arm.h>
840e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_mbox.h>
940e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_pm.h>
1040e40cd2SJorge Ramirez-Ortiz #include <initcall.h>
1140e40cd2SJorge Ramirez-Ortiz #include <kernel/cache_helpers.h>
1240e40cd2SJorge Ramirez-Ortiz #include <kernel/delay.h>
1340e40cd2SJorge Ramirez-Ortiz #include <kernel/panic.h>
1440e40cd2SJorge Ramirez-Ortiz #include <kernel/thread.h>
1540e40cd2SJorge Ramirez-Ortiz #include <mm/core_memprot.h>
1640e40cd2SJorge Ramirez-Ortiz #include <string.h>
1740e40cd2SJorge Ramirez-Ortiz #include <tee/cache.h>
1840e40cd2SJorge Ramirez-Ortiz #include <tee_api_types.h>
1940e40cd2SJorge Ramirez-Ortiz #include <utee_defines.h>
2040e40cd2SJorge Ramirez-Ortiz 
2140e40cd2SJorge Ramirez-Ortiz /* VERSAL_SIP_UID: 2ab9e4ec-93b9-11e7-a019dfe0dbad0ae0 */
2240e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_0 U(0xece4b92a)
2340e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_1 U(0xe711b993)
2440e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_2 U(0xe0df19a0)
2540e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_3 U(0xe00aaddb)
2640e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MAJOR  0
2740e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MINOR  1
2840e40cd2SJorge Ramirez-Ortiz 
2940e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_VERSION		0x8200ff03
3040e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_UID		0x8200ff01
3140e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC			0xc2000000
3240e40cd2SJorge Ramirez-Ortiz 
3340e40cd2SJorge Ramirez-Ortiz #define PAYLOAD_ARG_CNT		8
3440e40cd2SJorge Ramirez-Ortiz 
3540e40cd2SJorge Ramirez-Ortiz /* MBOX IPI */
3640e40cd2SJorge Ramirez-Ortiz #define PM_MODULE_SHIFT		8
3740e40cd2SJorge Ramirez-Ortiz #define PM_MODULE		2
3840e40cd2SJorge Ramirez-Ortiz #define PM_API_ID(x)		((PM_MODULE << PM_MODULE_SHIFT) | (x))
3940e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MAJOR		0
4040e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MINOR		1
4140e40cd2SJorge Ramirez-Ortiz 
4240e40cd2SJorge Ramirez-Ortiz /* PM API ids */
4340e40cd2SJorge Ramirez-Ortiz #define PM_GET_API_VERSION		1
4440e40cd2SJorge Ramirez-Ortiz #define PM_GET_DEVICE_STATUS		3
4540e40cd2SJorge Ramirez-Ortiz #define PM_GET_OP_CHARACTERISTIC	4
4640e40cd2SJorge Ramirez-Ortiz #define PM_REGISTER_NOTIFIER		5
4740e40cd2SJorge Ramirez-Ortiz #define PM_REQ_SUSPEND			6
4840e40cd2SJorge Ramirez-Ortiz #define PM_SELF_SUSPEND			7
4940e40cd2SJorge Ramirez-Ortiz #define PM_FORCE_POWERDOWN		8
5040e40cd2SJorge Ramirez-Ortiz #define PM_ABORT_SUSPEND		9
5140e40cd2SJorge Ramirez-Ortiz #define PM_REQ_WAKEUP			10
5240e40cd2SJorge Ramirez-Ortiz #define PM_SET_WAKEUP_SOURCE		11
5340e40cd2SJorge Ramirez-Ortiz #define PM_SYSTEM_SHUTDOWN		12
5440e40cd2SJorge Ramirez-Ortiz #define PM_REQUEST_DEVICE		13
5540e40cd2SJorge Ramirez-Ortiz #define PM_RELEASE_DEVICE		14
5640e40cd2SJorge Ramirez-Ortiz #define PM_SET_REQUIREMENT		15
5740e40cd2SJorge Ramirez-Ortiz #define PM_SET_MAX_LATENCY		16
5840e40cd2SJorge Ramirez-Ortiz #define PM_RESET_ASSERT			17
5940e40cd2SJorge Ramirez-Ortiz #define PM_RESET_GET_STATUS		18
6040e40cd2SJorge Ramirez-Ortiz #define PM_INIT_FINALIZE		21
6140e40cd2SJorge Ramirez-Ortiz #define PM_GET_CHIPID			24
6240e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_REQUEST		28
6340e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_RELEASE		29
6440e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_GET_FUNCTION		30
6540e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_SET_FUNCTION		31
6640e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_CONFIG_PARAM_GET	32
6740e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_CONFIG_PARAM_SET	33
6840e40cd2SJorge Ramirez-Ortiz #define PM_IOCTL			34
6940e40cd2SJorge Ramirez-Ortiz #define PM_QUERY_DATA			35
7040e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_ENABLE			36
7140e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_DISABLE		37
7240e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETSTATE		38
7340e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETDIVIDER		39
7440e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETDIVIDER		40
7540e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETRATE		41
7640e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETRATE		42
7740e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETPARENT		43
7840e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETPARENT		44
7940e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_PARAMETER		48
8040e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_PARAMETER		49
8140e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_MODE			50
8240e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_MODE			51
8340e40cd2SJorge Ramirez-Ortiz #define PM_FEATURE_CHECK		63
8440e40cd2SJorge Ramirez-Ortiz 
8540e40cd2SJorge Ramirez-Ortiz /* Loader API id */
8640e40cd2SJorge Ramirez-Ortiz #define PM_LOAD_PDI			0x701
8740e40cd2SJorge Ramirez-Ortiz 
8840e40cd2SJorge Ramirez-Ortiz /* PDI sources */
8940e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_JTAG		0x0
9040e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI24		0x1
9140e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI32		0x2
9240e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD0		0x3
9340e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC0		0x4
9440e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1		0x5
9540e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC1		0x6
9640e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_USB		0x7
9740e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_OSPI		0x8
9840e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SBI		0x9
9940e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SMAP		0xA
10040e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_PCIE		0xB
10140e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1_LS		0xE
10240e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_DDR		0xF
10340e40cd2SJorge Ramirez-Ortiz 
10440e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload {
10540e40cd2SJorge Ramirez-Ortiz 	uint32_t data[PAYLOAD_ARG_CNT];
10640e40cd2SJorge Ramirez-Ortiz };
10740e40cd2SJorge Ramirez-Ortiz 
versal_sip_call(uint32_t smc_fid,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,struct versal_sip_payload * payload)10840e40cd2SJorge Ramirez-Ortiz static uint32_t versal_sip_call(uint32_t smc_fid, uint32_t arg0, uint32_t arg1,
10940e40cd2SJorge Ramirez-Ortiz 				uint32_t arg2, uint32_t arg3,
11040e40cd2SJorge Ramirez-Ortiz 				struct versal_sip_payload *payload)
11140e40cd2SJorge Ramirez-Ortiz {
11240e40cd2SJorge Ramirez-Ortiz 	struct thread_smc_args args = {
11340e40cd2SJorge Ramirez-Ortiz 		.a0 = smc_fid,
11440e40cd2SJorge Ramirez-Ortiz 		.a1 = reg_pair_to_64(arg1, arg0),
11540e40cd2SJorge Ramirez-Ortiz 		.a2 = reg_pair_to_64(arg3, arg2),
11640e40cd2SJorge Ramirez-Ortiz 	};
11740e40cd2SJorge Ramirez-Ortiz 
11840e40cd2SJorge Ramirez-Ortiz 	thread_smccc(&args);
11940e40cd2SJorge Ramirez-Ortiz 
12040e40cd2SJorge Ramirez-Ortiz 	if (payload) {
12140e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a0, &payload->data[1], &payload->data[0]);
12240e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a1, &payload->data[3], &payload->data[2]);
12340e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a2, &payload->data[5], &payload->data[4]);
12440e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a3, &payload->data[7], &payload->data[6]);
12540e40cd2SJorge Ramirez-Ortiz 	}
12640e40cd2SJorge Ramirez-Ortiz 
12740e40cd2SJorge Ramirez-Ortiz 	/* allow the PLM to output its debug information */
12840e40cd2SJorge Ramirez-Ortiz 	if (IS_ENABLED(CFG_VERSAL_TRACE_PLM))
12940e40cd2SJorge Ramirez-Ortiz 		mdelay(500);
13040e40cd2SJorge Ramirez-Ortiz 
13140e40cd2SJorge Ramirez-Ortiz 	return args.a0;
13240e40cd2SJorge Ramirez-Ortiz }
13340e40cd2SJorge Ramirez-Ortiz 
13440e40cd2SJorge Ramirez-Ortiz /* SIP call to program the FPGA has been obsoleted, use the PLM */
versal_write_fpga(paddr_t pa)13540e40cd2SJorge Ramirez-Ortiz TEE_Result versal_write_fpga(paddr_t pa)
13640e40cd2SJorge Ramirez-Ortiz {
137*e4c76cc2SJorge Ramirez-Ortiz 	struct versal_ipi_cmd cmd = { };
13840e40cd2SJorge Ramirez-Ortiz 
13940e40cd2SJorge Ramirez-Ortiz 	cmd.data[0] = PM_LOAD_PDI;
14040e40cd2SJorge Ramirez-Ortiz 	cmd.data[1] = PDI_SRC_DDR;
14140e40cd2SJorge Ramirez-Ortiz 	reg_pair_from_64(pa, &cmd.data[2], &cmd.data[3]);
14240e40cd2SJorge Ramirez-Ortiz 
14340e40cd2SJorge Ramirez-Ortiz 	if (versal_mbox_notify(&cmd, NULL, NULL))
14440e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
14540e40cd2SJorge Ramirez-Ortiz 
14640e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
14740e40cd2SJorge Ramirez-Ortiz }
14840e40cd2SJorge Ramirez-Ortiz 
versal_soc_version(uint8_t * version)14940e40cd2SJorge Ramirez-Ortiz TEE_Result versal_soc_version(uint8_t *version)
15040e40cd2SJorge Ramirez-Ortiz {
15140e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
15240e40cd2SJorge Ramirez-Ortiz 	const uint32_t version_shift = 12;
15340e40cd2SJorge Ramirez-Ortiz 
15440e40cd2SJorge Ramirez-Ortiz 	if (!version)
15540e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
15640e40cd2SJorge Ramirez-Ortiz 
15740e40cd2SJorge Ramirez-Ortiz 	if (versal_sip_call(VERSAL_SIP_SVC | PM_GET_CHIPID, 0, 0, 0, 0, &p))
15840e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
15940e40cd2SJorge Ramirez-Ortiz 
16040e40cd2SJorge Ramirez-Ortiz 	*version = p.data[2] >> version_shift;
16140e40cd2SJorge Ramirez-Ortiz 
16240e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
16340e40cd2SJorge Ramirez-Ortiz }
16440e40cd2SJorge Ramirez-Ortiz 
uuid_is_versal_pm(void)16540e40cd2SJorge Ramirez-Ortiz static bool uuid_is_versal_pm(void)
16640e40cd2SJorge Ramirez-Ortiz {
16740e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
16840e40cd2SJorge Ramirez-Ortiz 
16940e40cd2SJorge Ramirez-Ortiz 	versal_sip_call(VERSAL_SIP_SVC_UID, 0, 0, 0, 0, &p);
17040e40cd2SJorge Ramirez-Ortiz 
17140e40cd2SJorge Ramirez-Ortiz 	if (p.data[0] == VERSAL_SIP_UID_0 && p.data[2] == VERSAL_SIP_UID_1 &&
17240e40cd2SJorge Ramirez-Ortiz 	    p.data[4] == VERSAL_SIP_UID_2 && p.data[6] == VERSAL_SIP_UID_3)
17340e40cd2SJorge Ramirez-Ortiz 		return true;
17440e40cd2SJorge Ramirez-Ortiz 
17540e40cd2SJorge Ramirez-Ortiz 	return false;
17640e40cd2SJorge Ramirez-Ortiz }
17740e40cd2SJorge Ramirez-Ortiz 
versal_check_pm_abi(void)17840e40cd2SJorge Ramirez-Ortiz static TEE_Result versal_check_pm_abi(void)
17940e40cd2SJorge Ramirez-Ortiz {
18040e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
181*e4c76cc2SJorge Ramirez-Ortiz 	struct versal_ipi_cmd cmd = { };
182*e4c76cc2SJorge Ramirez-Ortiz 	struct versal_ipi_cmd rsp = { };
18340e40cd2SJorge Ramirez-Ortiz 	unsigned int major = 0;
18440e40cd2SJorge Ramirez-Ortiz 	unsigned int minor = 0;
18540e40cd2SJorge Ramirez-Ortiz 
18640e40cd2SJorge Ramirez-Ortiz 	if (!uuid_is_versal_pm()) {
18740e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid SiP Service");
18840e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
18940e40cd2SJorge Ramirez-Ortiz 	}
19040e40cd2SJorge Ramirez-Ortiz 
19140e40cd2SJorge Ramirez-Ortiz 	if (versal_sip_call(VERSAL_SIP_SVC_VERSION, 0, 0, 0, 0, &p))
19240e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
19340e40cd2SJorge Ramirez-Ortiz 
19440e40cd2SJorge Ramirez-Ortiz 	major = p.data[0];
19540e40cd2SJorge Ramirez-Ortiz 	minor = p.data[2];
19640e40cd2SJorge Ramirez-Ortiz 	if (major != VERSAL_SIP_MAJOR || minor < VERSAL_SIP_MINOR) {
19740e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid SiP version: Major %d, Minor %d", major, minor);
19840e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
19940e40cd2SJorge Ramirez-Ortiz 	}
20040e40cd2SJorge Ramirez-Ortiz 
20140e40cd2SJorge Ramirez-Ortiz 	cmd.data[0] = PM_API_ID(PM_GET_API_VERSION);
20240e40cd2SJorge Ramirez-Ortiz 	if (versal_mbox_notify(&cmd, &rsp, NULL))
20340e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
20440e40cd2SJorge Ramirez-Ortiz 
20540e40cd2SJorge Ramirez-Ortiz 	major = rsp.data[1] & 0xFFFF;
20640e40cd2SJorge Ramirez-Ortiz 	minor = rsp.data[1] >> 16;
20740e40cd2SJorge Ramirez-Ortiz 	if (major != VERSAL_PM_MAJOR || minor < VERSAL_PM_MINOR) {
20840e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid PM version: Major %d, Minor %d", major, minor);
20940e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
21040e40cd2SJorge Ramirez-Ortiz 	}
21140e40cd2SJorge Ramirez-Ortiz 
21240e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
21340e40cd2SJorge Ramirez-Ortiz }
21440e40cd2SJorge Ramirez-Ortiz 
21540e40cd2SJorge Ramirez-Ortiz early_init_late(versal_check_pm_abi);
216