xref: /optee_os/core/pta/scmi.c (revision 602ff4f69104a4e7ff9341cc6802cb121712ea2d)
1b0a1c250SEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
2b0a1c250SEtienne Carriere /*
3b0a1c250SEtienne Carriere  * Copyright (c) 2019-2021, Linaro Limited
4b0a1c250SEtienne Carriere  * Copyright (c) 2019-2021, STMicroelectronics
5b0a1c250SEtienne Carriere  */
6b0a1c250SEtienne Carriere #include <compiler.h>
7b0a1c250SEtienne Carriere #include <config.h>
8b0a1c250SEtienne Carriere #include <drivers/scmi-msg.h>
97ff45442SEtienne Carriere #include <scmi/scmi_server.h>
10b0a1c250SEtienne Carriere #include <kernel/pseudo_ta.h>
11b0a1c250SEtienne Carriere #include <pta_scmi_client.h>
12b0a1c250SEtienne Carriere #include <stdint.h>
13b0a1c250SEtienne Carriere #include <string.h>
14b0a1c250SEtienne Carriere 
supported_caps(void)1516a5030fSEtienne Carriere static uint32_t supported_caps(void)
1616a5030fSEtienne Carriere {
1716a5030fSEtienne Carriere 	uint32_t caps = 0;
1816a5030fSEtienne Carriere 
1916a5030fSEtienne Carriere 	if (IS_ENABLED2(_CFG_SCMI_PTA_SMT_HEADER))
2016a5030fSEtienne Carriere 		caps |= PTA_SCMI_CAPS_SMT_HEADER;
2116a5030fSEtienne Carriere 
2216a5030fSEtienne Carriere 	if (IS_ENABLED2(_CFG_SCMI_PTA_MSG_HEADER))
2316a5030fSEtienne Carriere 		caps |= PTA_SCMI_CAPS_MSG_HEADER;
2416a5030fSEtienne Carriere 
2516a5030fSEtienne Carriere 	return caps;
2616a5030fSEtienne Carriere }
2716a5030fSEtienne Carriere 
cmd_capabilities(uint32_t ptypes,TEE_Param param[TEE_NUM_PARAMS])28b0a1c250SEtienne Carriere static TEE_Result cmd_capabilities(uint32_t ptypes,
29b0a1c250SEtienne Carriere 				   TEE_Param param[TEE_NUM_PARAMS])
30b0a1c250SEtienne Carriere {
31b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
32b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
33b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
34b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
35b0a1c250SEtienne Carriere 
36b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
37b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
38b0a1c250SEtienne Carriere 
3916a5030fSEtienne Carriere 	param[0].value.a = supported_caps();
40b0a1c250SEtienne Carriere 	param[0].value.b = 0;
41b0a1c250SEtienne Carriere 
42b0a1c250SEtienne Carriere 	return TEE_SUCCESS;
43b0a1c250SEtienne Carriere }
44b0a1c250SEtienne Carriere 
cmd_process_smt_channel(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])45b0a1c250SEtienne Carriere static TEE_Result cmd_process_smt_channel(uint32_t ptypes,
46b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
47b0a1c250SEtienne Carriere {
48b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
49b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
50b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
51b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
52b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
53b0a1c250SEtienne Carriere 
54b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
55b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
56b0a1c250SEtienne Carriere 
57b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
58b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
59b0a1c250SEtienne Carriere 
60b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
61b0a1c250SEtienne Carriere 		if (!channel)
62b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
63b0a1c250SEtienne Carriere 
64b0a1c250SEtienne Carriere 		scmi_smt_threaded_entry(channel_id);
65b0a1c250SEtienne Carriere 
66b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
67b0a1c250SEtienne Carriere 	}
68b0a1c250SEtienne Carriere 
697ff45442SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_SCPFW))
707ff45442SEtienne Carriere 		return scmi_server_smt_process_thread(channel_id);
717ff45442SEtienne Carriere 
72b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
73b0a1c250SEtienne Carriere }
74b0a1c250SEtienne Carriere 
cmd_process_smt_message(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])75b0a1c250SEtienne Carriere static TEE_Result cmd_process_smt_message(uint32_t ptypes,
76b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
77b0a1c250SEtienne Carriere {
78b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
79b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_MEMREF_INOUT,
80b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
81b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
82b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
83b0a1c250SEtienne Carriere 	TEE_Param *param1 = params + 1;
84b0a1c250SEtienne Carriere 
85b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
86b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
87b0a1c250SEtienne Carriere 
88b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
89b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
90b0a1c250SEtienne Carriere 
91b0a1c250SEtienne Carriere 		if (param1->memref.size < SMT_BUF_SLOT_SIZE)
92b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
93b0a1c250SEtienne Carriere 
94b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
95b0a1c250SEtienne Carriere 		if (!channel)
96b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
97b0a1c250SEtienne Carriere 
98b0a1c250SEtienne Carriere 		/*
99b0a1c250SEtienne Carriere 		 * Caller provides the buffer, we bind channel to that buffer.
100b0a1c250SEtienne Carriere 		 * Once message is processed, unbind the buffer since it is
101b0a1c250SEtienne Carriere 		 * valid only for the current invocation.
102b0a1c250SEtienne Carriere 		 */
103b0a1c250SEtienne Carriere 		scmi_smt_set_shared_buffer(channel, param1->memref.buffer);
104b0a1c250SEtienne Carriere 		scmi_smt_threaded_entry(channel_id);
105b0a1c250SEtienne Carriere 		scmi_smt_set_shared_buffer(channel, NULL);
106b0a1c250SEtienne Carriere 
107b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
108b0a1c250SEtienne Carriere 	}
109b0a1c250SEtienne Carriere 
110b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
111b0a1c250SEtienne Carriere }
112b0a1c250SEtienne Carriere 
cmd_process_msg_channel(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])1138ea50d3bSEtienne Carriere static TEE_Result cmd_process_msg_channel(uint32_t ptypes,
1148ea50d3bSEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
1158ea50d3bSEtienne Carriere {
1168ea50d3bSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
1178ea50d3bSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1188ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_INPUT,
1198ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
1208ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
1218ea50d3bSEtienne Carriere 	unsigned int channel_id = params[0].value.a;
1228ea50d3bSEtienne Carriere 	void *in_buf = params[1].memref.buffer;
1238ea50d3bSEtienne Carriere 	size_t in_size = params[1].memref.size;
1248ea50d3bSEtienne Carriere 	void *out_buf = params[2].memref.buffer;
1258ea50d3bSEtienne Carriere 	size_t out_size = params[2].memref.size;
1268ea50d3bSEtienne Carriere 
1278ea50d3bSEtienne Carriere 	if (ptypes != exp_pt || !in_buf || !out_buf)
1288ea50d3bSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
1298ea50d3bSEtienne Carriere 
1307ff45442SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
1318ea50d3bSEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
1328ea50d3bSEtienne Carriere 
1337ff45442SEtienne Carriere 		if (!IS_ENABLED(CFG_SCMI_MSG_SHM_MSG))
1347ff45442SEtienne Carriere 			return TEE_ERROR_NOT_SUPPORTED;
1357ff45442SEtienne Carriere 
1368ea50d3bSEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
1378ea50d3bSEtienne Carriere 		if (!channel)
1388ea50d3bSEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
1398ea50d3bSEtienne Carriere 
1408ea50d3bSEtienne Carriere 		res = scmi_msg_threaded_entry(channel_id, in_buf, in_size,
1418ea50d3bSEtienne Carriere 					      out_buf, &out_size);
1428ea50d3bSEtienne Carriere 		if (!res)
1438ea50d3bSEtienne Carriere 			params[2].memref.size = out_size;
1448ea50d3bSEtienne Carriere 
1458ea50d3bSEtienne Carriere 		return res;
1468ea50d3bSEtienne Carriere 	}
1478ea50d3bSEtienne Carriere 
1487ff45442SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_SCPFW)) {
1497ff45442SEtienne Carriere 		if (!in_buf || !out_buf)
1507ff45442SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
1517ff45442SEtienne Carriere 
1527ff45442SEtienne Carriere 		res = scmi_server_msg_process_thread(channel_id, in_buf,
1537ff45442SEtienne Carriere 						     in_size, out_buf,
1547ff45442SEtienne Carriere 						     &out_size);
155*602ff4f6SEtienne Carriere 		if (!res)
1567ff45442SEtienne Carriere 			params[2].memref.size = (uint32_t)out_size;
1577ff45442SEtienne Carriere 
1587ff45442SEtienne Carriere 		return res;
1597ff45442SEtienne Carriere 	}
1607ff45442SEtienne Carriere 
1618ea50d3bSEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
1628ea50d3bSEtienne Carriere }
1638ea50d3bSEtienne Carriere 
cmd_get_channel_handle(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])164b0a1c250SEtienne Carriere static TEE_Result cmd_get_channel_handle(uint32_t ptypes,
165b0a1c250SEtienne Carriere 					 TEE_Param params[TEE_NUM_PARAMS])
166b0a1c250SEtienne Carriere {
167b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
168b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
169b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
170b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
171b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
172b0a1c250SEtienne Carriere 	unsigned int caps = params[0].value.b;
173b0a1c250SEtienne Carriere 
17416a5030fSEtienne Carriere 	if (ptypes != exp_ptypes || caps & ~PTA_SCMI_CAPS_MASK)
175b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
176b0a1c250SEtienne Carriere 
17716a5030fSEtienne Carriere 	if (!(caps & supported_caps()))
17816a5030fSEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
17916a5030fSEtienne Carriere 
180916cc52aSEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
181b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
182b0a1c250SEtienne Carriere 
183b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
184b0a1c250SEtienne Carriere 		if (!channel)
185b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
186b0a1c250SEtienne Carriere 
187d7b5407fSEtienne Carriere 		channel->threaded = true;
188b0a1c250SEtienne Carriere 		params[0].value.a = scmi_smt_channel_handle(channel_id);
189b0a1c250SEtienne Carriere 
190b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
191b0a1c250SEtienne Carriere 	}
192b0a1c250SEtienne Carriere 
1937ff45442SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_SCPFW)) {
1947ff45442SEtienne Carriere 		/* Only check the channel ID is known from SCP-firwmare */
1957ff45442SEtienne Carriere 		return scmi_server_get_channel(channel_id, NULL);
1967ff45442SEtienne Carriere 	}
1977ff45442SEtienne Carriere 
198b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
199b0a1c250SEtienne Carriere }
200b0a1c250SEtienne Carriere 
pta_scmi_open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)201b0a1c250SEtienne Carriere static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused,
202b0a1c250SEtienne Carriere 					TEE_Param par[TEE_NUM_PARAMS] __unused,
203b0a1c250SEtienne Carriere 					void **session __unused)
204b0a1c250SEtienne Carriere {
205b0a1c250SEtienne Carriere 	struct ts_session *ts = ts_get_current_session();
206b0a1c250SEtienne Carriere 	struct tee_ta_session *ta_session = to_ta_session(ts);
207b0a1c250SEtienne Carriere 
208b0a1c250SEtienne Carriere 	/* Only REE kernel is allowed to access SCMI resources */
209b0a1c250SEtienne Carriere 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) {
210b0a1c250SEtienne Carriere 		DMSG("Expecting TEE_LOGIN_REE_KERNEL");
211b0a1c250SEtienne Carriere 		return TEE_ERROR_ACCESS_DENIED;
212b0a1c250SEtienne Carriere 	}
213b0a1c250SEtienne Carriere 
2143bc3809aSEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS) || IS_ENABLED(CFG_SCMI_SCPFW))
215b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
216b0a1c250SEtienne Carriere 
217b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
218b0a1c250SEtienne Carriere }
219b0a1c250SEtienne Carriere 
pta_scmi_invoke_command(void * session __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])220b0a1c250SEtienne Carriere static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd,
221b0a1c250SEtienne Carriere 					  uint32_t ptypes,
222b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
223b0a1c250SEtienne Carriere {
224b0a1c250SEtienne Carriere 	FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes);
225b0a1c250SEtienne Carriere 
226b0a1c250SEtienne Carriere 	switch (cmd) {
227b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_CAPABILITIES:
228b0a1c250SEtienne Carriere 		return cmd_capabilities(ptypes, params);
229b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL:
230b0a1c250SEtienne Carriere 		return cmd_process_smt_channel(ptypes, params);
231b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE:
232b0a1c250SEtienne Carriere 		return cmd_process_smt_message(ptypes, params);
2338ea50d3bSEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_MSG_CHANNEL:
2348ea50d3bSEtienne Carriere 		return cmd_process_msg_channel(ptypes, params);
235b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_GET_CHANNEL_HANDLE:
236b0a1c250SEtienne Carriere 		return cmd_get_channel_handle(ptypes, params);
237b0a1c250SEtienne Carriere 	default:
238b0a1c250SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
239b0a1c250SEtienne Carriere 	}
240b0a1c250SEtienne Carriere }
241b0a1c250SEtienne Carriere 
242b0a1c250SEtienne Carriere pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME,
243b0a1c250SEtienne Carriere 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
244b0a1c250SEtienne Carriere 			    TA_FLAG_DEVICE_ENUM,
245b0a1c250SEtienne Carriere 		   .open_session_entry_point = pta_scmi_open_session,
246b0a1c250SEtienne Carriere 		   .invoke_command_entry_point = pta_scmi_invoke_command);
247