xref: /optee_os/core/drivers/versal_pm.c (revision 40e40cd24dd2a67544abbe8d0401b939dc7aa01a)
1*40e40cd2SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
2*40e40cd2SJorge Ramirez-Ortiz /*
3*40e40cd2SJorge Ramirez-Ortiz  * Copyright (C) 2022 Foundries.io Ltd
4*40e40cd2SJorge Ramirez-Ortiz  * Jorge Ramirez-Ortiz <jorge@foundries.io>
5*40e40cd2SJorge Ramirez-Ortiz  */
6*40e40cd2SJorge Ramirez-Ortiz 
7*40e40cd2SJorge Ramirez-Ortiz #include <arm.h>
8*40e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_mbox.h>
9*40e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_pm.h>
10*40e40cd2SJorge Ramirez-Ortiz #include <initcall.h>
11*40e40cd2SJorge Ramirez-Ortiz #include <kernel/cache_helpers.h>
12*40e40cd2SJorge Ramirez-Ortiz #include <kernel/delay.h>
13*40e40cd2SJorge Ramirez-Ortiz #include <kernel/panic.h>
14*40e40cd2SJorge Ramirez-Ortiz #include <kernel/thread.h>
15*40e40cd2SJorge Ramirez-Ortiz #include <mm/core_memprot.h>
16*40e40cd2SJorge Ramirez-Ortiz #include <string.h>
17*40e40cd2SJorge Ramirez-Ortiz #include <tee/cache.h>
18*40e40cd2SJorge Ramirez-Ortiz #include <tee_api_types.h>
19*40e40cd2SJorge Ramirez-Ortiz #include <utee_defines.h>
20*40e40cd2SJorge Ramirez-Ortiz 
21*40e40cd2SJorge Ramirez-Ortiz /* VERSAL_SIP_UID: 2ab9e4ec-93b9-11e7-a019dfe0dbad0ae0 */
22*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_0 U(0xece4b92a)
23*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_1 U(0xe711b993)
24*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_2 U(0xe0df19a0)
25*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_3 U(0xe00aaddb)
26*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MAJOR  0
27*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MINOR  1
28*40e40cd2SJorge Ramirez-Ortiz 
29*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_VERSION		0x8200ff03
30*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_UID		0x8200ff01
31*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC			0xc2000000
32*40e40cd2SJorge Ramirez-Ortiz 
33*40e40cd2SJorge Ramirez-Ortiz #define PAYLOAD_ARG_CNT		8
34*40e40cd2SJorge Ramirez-Ortiz 
35*40e40cd2SJorge Ramirez-Ortiz /* MBOX IPI */
36*40e40cd2SJorge Ramirez-Ortiz #define PM_MODULE_SHIFT		8
37*40e40cd2SJorge Ramirez-Ortiz #define PM_MODULE		2
38*40e40cd2SJorge Ramirez-Ortiz #define PM_API_ID(x)		((PM_MODULE << PM_MODULE_SHIFT) | (x))
39*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MAJOR		0
40*40e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MINOR		1
41*40e40cd2SJorge Ramirez-Ortiz 
42*40e40cd2SJorge Ramirez-Ortiz /* PM API ids */
43*40e40cd2SJorge Ramirez-Ortiz #define PM_GET_API_VERSION		1
44*40e40cd2SJorge Ramirez-Ortiz #define PM_GET_DEVICE_STATUS		3
45*40e40cd2SJorge Ramirez-Ortiz #define PM_GET_OP_CHARACTERISTIC	4
46*40e40cd2SJorge Ramirez-Ortiz #define PM_REGISTER_NOTIFIER		5
47*40e40cd2SJorge Ramirez-Ortiz #define PM_REQ_SUSPEND			6
48*40e40cd2SJorge Ramirez-Ortiz #define PM_SELF_SUSPEND			7
49*40e40cd2SJorge Ramirez-Ortiz #define PM_FORCE_POWERDOWN		8
50*40e40cd2SJorge Ramirez-Ortiz #define PM_ABORT_SUSPEND		9
51*40e40cd2SJorge Ramirez-Ortiz #define PM_REQ_WAKEUP			10
52*40e40cd2SJorge Ramirez-Ortiz #define PM_SET_WAKEUP_SOURCE		11
53*40e40cd2SJorge Ramirez-Ortiz #define PM_SYSTEM_SHUTDOWN		12
54*40e40cd2SJorge Ramirez-Ortiz #define PM_REQUEST_DEVICE		13
55*40e40cd2SJorge Ramirez-Ortiz #define PM_RELEASE_DEVICE		14
56*40e40cd2SJorge Ramirez-Ortiz #define PM_SET_REQUIREMENT		15
57*40e40cd2SJorge Ramirez-Ortiz #define PM_SET_MAX_LATENCY		16
58*40e40cd2SJorge Ramirez-Ortiz #define PM_RESET_ASSERT			17
59*40e40cd2SJorge Ramirez-Ortiz #define PM_RESET_GET_STATUS		18
60*40e40cd2SJorge Ramirez-Ortiz #define PM_INIT_FINALIZE		21
61*40e40cd2SJorge Ramirez-Ortiz #define PM_GET_CHIPID			24
62*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_REQUEST		28
63*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_RELEASE		29
64*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_GET_FUNCTION		30
65*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_SET_FUNCTION		31
66*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_CONFIG_PARAM_GET	32
67*40e40cd2SJorge Ramirez-Ortiz #define	PM_PINCTRL_CONFIG_PARAM_SET	33
68*40e40cd2SJorge Ramirez-Ortiz #define PM_IOCTL			34
69*40e40cd2SJorge Ramirez-Ortiz #define PM_QUERY_DATA			35
70*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_ENABLE			36
71*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_DISABLE		37
72*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETSTATE		38
73*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETDIVIDER		39
74*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETDIVIDER		40
75*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETRATE		41
76*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETRATE		42
77*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETPARENT		43
78*40e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETPARENT		44
79*40e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_PARAMETER		48
80*40e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_PARAMETER		49
81*40e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_MODE			50
82*40e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_MODE			51
83*40e40cd2SJorge Ramirez-Ortiz #define PM_FEATURE_CHECK		63
84*40e40cd2SJorge Ramirez-Ortiz 
85*40e40cd2SJorge Ramirez-Ortiz /* Loader API id */
86*40e40cd2SJorge Ramirez-Ortiz #define PM_LOAD_PDI			0x701
87*40e40cd2SJorge Ramirez-Ortiz 
88*40e40cd2SJorge Ramirez-Ortiz /* PDI sources */
89*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_JTAG		0x0
90*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI24		0x1
91*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI32		0x2
92*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD0		0x3
93*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC0		0x4
94*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1		0x5
95*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC1		0x6
96*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_USB		0x7
97*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_OSPI		0x8
98*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SBI		0x9
99*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SMAP		0xA
100*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_PCIE		0xB
101*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1_LS		0xE
102*40e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_DDR		0xF
103*40e40cd2SJorge Ramirez-Ortiz 
104*40e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload {
105*40e40cd2SJorge Ramirez-Ortiz 	uint32_t data[PAYLOAD_ARG_CNT];
106*40e40cd2SJorge Ramirez-Ortiz };
107*40e40cd2SJorge Ramirez-Ortiz 
108*40e40cd2SJorge Ramirez-Ortiz static uint32_t versal_sip_call(uint32_t smc_fid, uint32_t arg0, uint32_t arg1,
109*40e40cd2SJorge Ramirez-Ortiz 				uint32_t arg2, uint32_t arg3,
110*40e40cd2SJorge Ramirez-Ortiz 				struct versal_sip_payload *payload)
111*40e40cd2SJorge Ramirez-Ortiz {
112*40e40cd2SJorge Ramirez-Ortiz 	struct thread_smc_args args = {
113*40e40cd2SJorge Ramirez-Ortiz 		.a0 = smc_fid,
114*40e40cd2SJorge Ramirez-Ortiz 		.a1 = reg_pair_to_64(arg1, arg0),
115*40e40cd2SJorge Ramirez-Ortiz 		.a2 = reg_pair_to_64(arg3, arg2),
116*40e40cd2SJorge Ramirez-Ortiz 	};
117*40e40cd2SJorge Ramirez-Ortiz 
118*40e40cd2SJorge Ramirez-Ortiz 	thread_smccc(&args);
119*40e40cd2SJorge Ramirez-Ortiz 
120*40e40cd2SJorge Ramirez-Ortiz 	if (payload) {
121*40e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a0, &payload->data[1], &payload->data[0]);
122*40e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a1, &payload->data[3], &payload->data[2]);
123*40e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a2, &payload->data[5], &payload->data[4]);
124*40e40cd2SJorge Ramirez-Ortiz 		reg_pair_from_64(args.a3, &payload->data[7], &payload->data[6]);
125*40e40cd2SJorge Ramirez-Ortiz 	}
126*40e40cd2SJorge Ramirez-Ortiz 
127*40e40cd2SJorge Ramirez-Ortiz 	/* allow the PLM to output its debug information */
128*40e40cd2SJorge Ramirez-Ortiz 	if (IS_ENABLED(CFG_VERSAL_TRACE_PLM))
129*40e40cd2SJorge Ramirez-Ortiz 		mdelay(500);
130*40e40cd2SJorge Ramirez-Ortiz 
131*40e40cd2SJorge Ramirez-Ortiz 	return args.a0;
132*40e40cd2SJorge Ramirez-Ortiz }
133*40e40cd2SJorge Ramirez-Ortiz 
134*40e40cd2SJorge Ramirez-Ortiz /* SIP call to program the FPGA has been obsoleted, use the PLM */
135*40e40cd2SJorge Ramirez-Ortiz TEE_Result versal_write_fpga(paddr_t pa)
136*40e40cd2SJorge Ramirez-Ortiz {
137*40e40cd2SJorge Ramirez-Ortiz 	struct ipi_cmd cmd = { };
138*40e40cd2SJorge Ramirez-Ortiz 
139*40e40cd2SJorge Ramirez-Ortiz 	cmd.data[0] = PM_LOAD_PDI;
140*40e40cd2SJorge Ramirez-Ortiz 	cmd.data[1] = PDI_SRC_DDR;
141*40e40cd2SJorge Ramirez-Ortiz 	reg_pair_from_64(pa, &cmd.data[2], &cmd.data[3]);
142*40e40cd2SJorge Ramirez-Ortiz 
143*40e40cd2SJorge Ramirez-Ortiz 	if (versal_mbox_notify(&cmd, NULL, NULL))
144*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
145*40e40cd2SJorge Ramirez-Ortiz 
146*40e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
147*40e40cd2SJorge Ramirez-Ortiz }
148*40e40cd2SJorge Ramirez-Ortiz 
149*40e40cd2SJorge Ramirez-Ortiz TEE_Result versal_soc_version(uint8_t *version)
150*40e40cd2SJorge Ramirez-Ortiz {
151*40e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
152*40e40cd2SJorge Ramirez-Ortiz 	const uint32_t version_shift = 12;
153*40e40cd2SJorge Ramirez-Ortiz 
154*40e40cd2SJorge Ramirez-Ortiz 	if (!version)
155*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
156*40e40cd2SJorge Ramirez-Ortiz 
157*40e40cd2SJorge Ramirez-Ortiz 	if (versal_sip_call(VERSAL_SIP_SVC | PM_GET_CHIPID, 0, 0, 0, 0, &p))
158*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
159*40e40cd2SJorge Ramirez-Ortiz 
160*40e40cd2SJorge Ramirez-Ortiz 	*version = p.data[2] >> version_shift;
161*40e40cd2SJorge Ramirez-Ortiz 
162*40e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
163*40e40cd2SJorge Ramirez-Ortiz }
164*40e40cd2SJorge Ramirez-Ortiz 
165*40e40cd2SJorge Ramirez-Ortiz static bool uuid_is_versal_pm(void)
166*40e40cd2SJorge Ramirez-Ortiz {
167*40e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
168*40e40cd2SJorge Ramirez-Ortiz 
169*40e40cd2SJorge Ramirez-Ortiz 	versal_sip_call(VERSAL_SIP_SVC_UID, 0, 0, 0, 0, &p);
170*40e40cd2SJorge Ramirez-Ortiz 
171*40e40cd2SJorge Ramirez-Ortiz 	if (p.data[0] == VERSAL_SIP_UID_0 && p.data[2] == VERSAL_SIP_UID_1 &&
172*40e40cd2SJorge Ramirez-Ortiz 	    p.data[4] == VERSAL_SIP_UID_2 && p.data[6] == VERSAL_SIP_UID_3)
173*40e40cd2SJorge Ramirez-Ortiz 		return true;
174*40e40cd2SJorge Ramirez-Ortiz 
175*40e40cd2SJorge Ramirez-Ortiz 	return false;
176*40e40cd2SJorge Ramirez-Ortiz }
177*40e40cd2SJorge Ramirez-Ortiz 
178*40e40cd2SJorge Ramirez-Ortiz static TEE_Result versal_check_pm_abi(void)
179*40e40cd2SJorge Ramirez-Ortiz {
180*40e40cd2SJorge Ramirez-Ortiz 	struct versal_sip_payload p = { };
181*40e40cd2SJorge Ramirez-Ortiz 	struct ipi_cmd cmd = { };
182*40e40cd2SJorge Ramirez-Ortiz 	struct ipi_cmd rsp = { };
183*40e40cd2SJorge Ramirez-Ortiz 	unsigned int major = 0;
184*40e40cd2SJorge Ramirez-Ortiz 	unsigned int minor = 0;
185*40e40cd2SJorge Ramirez-Ortiz 
186*40e40cd2SJorge Ramirez-Ortiz 	if (!uuid_is_versal_pm()) {
187*40e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid SiP Service");
188*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
189*40e40cd2SJorge Ramirez-Ortiz 	}
190*40e40cd2SJorge Ramirez-Ortiz 
191*40e40cd2SJorge Ramirez-Ortiz 	if (versal_sip_call(VERSAL_SIP_SVC_VERSION, 0, 0, 0, 0, &p))
192*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
193*40e40cd2SJorge Ramirez-Ortiz 
194*40e40cd2SJorge Ramirez-Ortiz 	major = p.data[0];
195*40e40cd2SJorge Ramirez-Ortiz 	minor = p.data[2];
196*40e40cd2SJorge Ramirez-Ortiz 	if (major != VERSAL_SIP_MAJOR || minor < VERSAL_SIP_MINOR) {
197*40e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid SiP version: Major %d, Minor %d", major, minor);
198*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
199*40e40cd2SJorge Ramirez-Ortiz 	}
200*40e40cd2SJorge Ramirez-Ortiz 
201*40e40cd2SJorge Ramirez-Ortiz 	cmd.data[0] = PM_API_ID(PM_GET_API_VERSION);
202*40e40cd2SJorge Ramirez-Ortiz 	if (versal_mbox_notify(&cmd, &rsp, NULL))
203*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
204*40e40cd2SJorge Ramirez-Ortiz 
205*40e40cd2SJorge Ramirez-Ortiz 	major = rsp.data[1] & 0xFFFF;
206*40e40cd2SJorge Ramirez-Ortiz 	minor = rsp.data[1] >> 16;
207*40e40cd2SJorge Ramirez-Ortiz 	if (major != VERSAL_PM_MAJOR || minor < VERSAL_PM_MINOR) {
208*40e40cd2SJorge Ramirez-Ortiz 		EMSG("Invalid PM version: Major %d, Minor %d", major, minor);
209*40e40cd2SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
210*40e40cd2SJorge Ramirez-Ortiz 	}
211*40e40cd2SJorge Ramirez-Ortiz 
212*40e40cd2SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
213*40e40cd2SJorge Ramirez-Ortiz }
214*40e40cd2SJorge Ramirez-Ortiz 
215*40e40cd2SJorge Ramirez-Ortiz early_init_late(versal_check_pm_abi);
216