xref: /optee_os/core/pta/scmi.c (revision 8ea50d3b59126bcc8567c01c12406072a4d8e47c)
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>
9b0a1c250SEtienne Carriere #include <kernel/pseudo_ta.h>
10b0a1c250SEtienne Carriere #include <pta_scmi_client.h>
11b0a1c250SEtienne Carriere #include <stdint.h>
12b0a1c250SEtienne Carriere #include <string.h>
13b0a1c250SEtienne Carriere 
14b0a1c250SEtienne Carriere static TEE_Result cmd_capabilities(uint32_t ptypes,
15b0a1c250SEtienne Carriere 				   TEE_Param param[TEE_NUM_PARAMS])
16b0a1c250SEtienne Carriere {
17b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
18b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
19b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
20b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
21b0a1c250SEtienne Carriere 	uint32_t caps = 0;
22b0a1c250SEtienne Carriere 
23b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
24b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
25b0a1c250SEtienne Carriere 
26b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT))
27b0a1c250SEtienne Carriere 		caps |= PTA_SCMI_CAPS_SMT_HEADER;
28*8ea50d3bSEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SHM_MSG))
29*8ea50d3bSEtienne Carriere 		caps |= PTA_SCMI_CAPS_MSG_HEADER;
30b0a1c250SEtienne Carriere 
31b0a1c250SEtienne Carriere 	param[0].value.a = caps;
32b0a1c250SEtienne Carriere 	param[0].value.b = 0;
33b0a1c250SEtienne Carriere 
34b0a1c250SEtienne Carriere 	return TEE_SUCCESS;
35b0a1c250SEtienne Carriere }
36b0a1c250SEtienne Carriere 
37b0a1c250SEtienne Carriere static TEE_Result cmd_process_smt_channel(uint32_t ptypes,
38b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
39b0a1c250SEtienne Carriere {
40b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
41b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
42b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
43b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
44b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
45b0a1c250SEtienne Carriere 
46b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
47b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
48b0a1c250SEtienne Carriere 
49b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
50b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
51b0a1c250SEtienne Carriere 
52b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
53b0a1c250SEtienne Carriere 		if (!channel)
54b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
55b0a1c250SEtienne Carriere 
56b0a1c250SEtienne Carriere 		scmi_smt_threaded_entry(channel_id);
57b0a1c250SEtienne Carriere 
58b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
59b0a1c250SEtienne Carriere 	}
60b0a1c250SEtienne Carriere 
61b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
62b0a1c250SEtienne Carriere }
63b0a1c250SEtienne Carriere 
64b0a1c250SEtienne Carriere static TEE_Result cmd_process_smt_message(uint32_t ptypes,
65b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
66b0a1c250SEtienne Carriere {
67b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
68b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_MEMREF_INOUT,
69b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
70b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
71b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
72b0a1c250SEtienne Carriere 	TEE_Param *param1 = params + 1;
73b0a1c250SEtienne Carriere 
74b0a1c250SEtienne Carriere 	if (ptypes != exp_ptypes)
75b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
76b0a1c250SEtienne Carriere 
77b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
78b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
79b0a1c250SEtienne Carriere 
80b0a1c250SEtienne Carriere 		if (param1->memref.size < SMT_BUF_SLOT_SIZE)
81b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
82b0a1c250SEtienne Carriere 
83b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
84b0a1c250SEtienne Carriere 		if (!channel)
85b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
86b0a1c250SEtienne Carriere 
87b0a1c250SEtienne Carriere 		/*
88b0a1c250SEtienne Carriere 		 * Caller provides the buffer, we bind channel to that buffer.
89b0a1c250SEtienne Carriere 		 * Once message is processed, unbind the buffer since it is
90b0a1c250SEtienne Carriere 		 * valid only for the current invocation.
91b0a1c250SEtienne Carriere 		 */
92b0a1c250SEtienne Carriere 		scmi_smt_set_shared_buffer(channel, param1->memref.buffer);
93b0a1c250SEtienne Carriere 		scmi_smt_threaded_entry(channel_id);
94b0a1c250SEtienne Carriere 		scmi_smt_set_shared_buffer(channel, NULL);
95b0a1c250SEtienne Carriere 
96b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
97b0a1c250SEtienne Carriere 	}
98b0a1c250SEtienne Carriere 
99b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
100b0a1c250SEtienne Carriere }
101b0a1c250SEtienne Carriere 
102*8ea50d3bSEtienne Carriere static TEE_Result cmd_process_msg_channel(uint32_t ptypes,
103*8ea50d3bSEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
104*8ea50d3bSEtienne Carriere {
105*8ea50d3bSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
106*8ea50d3bSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
107*8ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_INPUT,
108*8ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
109*8ea50d3bSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
110*8ea50d3bSEtienne Carriere 	unsigned int channel_id = params[0].value.a;
111*8ea50d3bSEtienne Carriere 	void *in_buf = params[1].memref.buffer;
112*8ea50d3bSEtienne Carriere 	size_t in_size = params[1].memref.size;
113*8ea50d3bSEtienne Carriere 	void *out_buf = params[2].memref.buffer;
114*8ea50d3bSEtienne Carriere 	size_t out_size = params[2].memref.size;
115*8ea50d3bSEtienne Carriere 
116*8ea50d3bSEtienne Carriere 	if (ptypes != exp_pt || !in_buf || !out_buf)
117*8ea50d3bSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
118*8ea50d3bSEtienne Carriere 
119*8ea50d3bSEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SHM_MSG)) {
120*8ea50d3bSEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
121*8ea50d3bSEtienne Carriere 
122*8ea50d3bSEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
123*8ea50d3bSEtienne Carriere 		if (!channel)
124*8ea50d3bSEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
125*8ea50d3bSEtienne Carriere 
126*8ea50d3bSEtienne Carriere 		res = scmi_msg_threaded_entry(channel_id, in_buf, in_size,
127*8ea50d3bSEtienne Carriere 					      out_buf, &out_size);
128*8ea50d3bSEtienne Carriere 		if (!res)
129*8ea50d3bSEtienne Carriere 			params[2].memref.size = out_size;
130*8ea50d3bSEtienne Carriere 
131*8ea50d3bSEtienne Carriere 		return res;
132*8ea50d3bSEtienne Carriere 	}
133*8ea50d3bSEtienne Carriere 
134*8ea50d3bSEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
135*8ea50d3bSEtienne Carriere }
136*8ea50d3bSEtienne Carriere 
137b0a1c250SEtienne Carriere static TEE_Result cmd_get_channel_handle(uint32_t ptypes,
138b0a1c250SEtienne Carriere 					 TEE_Param params[TEE_NUM_PARAMS])
139b0a1c250SEtienne Carriere {
140b0a1c250SEtienne Carriere 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
141b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
142b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE,
143b0a1c250SEtienne Carriere 						    TEE_PARAM_TYPE_NONE);
144b0a1c250SEtienne Carriere 	unsigned int channel_id = params[0].value.a;
145b0a1c250SEtienne Carriere 	unsigned int caps = params[0].value.b;
146*8ea50d3bSEtienne Carriere 	const unsigned int supported_caps = PTA_SCMI_CAPS_SMT_HEADER |
147*8ea50d3bSEtienne Carriere 					    PTA_SCMI_CAPS_MSG_HEADER;
148b0a1c250SEtienne Carriere 
149*8ea50d3bSEtienne Carriere 	if (ptypes != exp_ptypes || caps & ~supported_caps)
150b0a1c250SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
151b0a1c250SEtienne Carriere 
152916cc52aSEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
153b0a1c250SEtienne Carriere 		struct scmi_msg_channel *channel = NULL;
154b0a1c250SEtienne Carriere 
155916cc52aSEtienne Carriere 		if (!IS_ENABLED(CFG_SCMI_MSG_SMT) &&
156916cc52aSEtienne Carriere 		    caps & PTA_SCMI_CAPS_SMT_HEADER)
157b0a1c250SEtienne Carriere 			return TEE_ERROR_NOT_SUPPORTED;
158b0a1c250SEtienne Carriere 
159b0a1c250SEtienne Carriere 		channel = plat_scmi_get_channel(channel_id);
160b0a1c250SEtienne Carriere 		if (!channel)
161b0a1c250SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
162b0a1c250SEtienne Carriere 
163d7b5407fSEtienne Carriere 		channel->threaded = true;
164b0a1c250SEtienne Carriere 		params[0].value.a = scmi_smt_channel_handle(channel_id);
165b0a1c250SEtienne Carriere 
166b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
167b0a1c250SEtienne Carriere 	}
168b0a1c250SEtienne Carriere 
169b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
170b0a1c250SEtienne Carriere }
171b0a1c250SEtienne Carriere 
172b0a1c250SEtienne Carriere static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused,
173b0a1c250SEtienne Carriere 					TEE_Param par[TEE_NUM_PARAMS] __unused,
174b0a1c250SEtienne Carriere 					void **session __unused)
175b0a1c250SEtienne Carriere {
176b0a1c250SEtienne Carriere 	struct ts_session *ts = ts_get_current_session();
177b0a1c250SEtienne Carriere 	struct tee_ta_session *ta_session = to_ta_session(ts);
178b0a1c250SEtienne Carriere 
179b0a1c250SEtienne Carriere 	/* Only REE kernel is allowed to access SCMI resources */
180b0a1c250SEtienne Carriere 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) {
181b0a1c250SEtienne Carriere 		DMSG("Expecting TEE_LOGIN_REE_KERNEL");
182b0a1c250SEtienne Carriere 		return TEE_ERROR_ACCESS_DENIED;
183b0a1c250SEtienne Carriere 	}
184b0a1c250SEtienne Carriere 
185b0a1c250SEtienne Carriere 	if (IS_ENABLED(CFG_SCMI_MSG_SMT))
186b0a1c250SEtienne Carriere 		return TEE_SUCCESS;
187b0a1c250SEtienne Carriere 
188b0a1c250SEtienne Carriere 	return TEE_ERROR_NOT_SUPPORTED;
189b0a1c250SEtienne Carriere }
190b0a1c250SEtienne Carriere 
191b0a1c250SEtienne Carriere static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd,
192b0a1c250SEtienne Carriere 					  uint32_t ptypes,
193b0a1c250SEtienne Carriere 					  TEE_Param params[TEE_NUM_PARAMS])
194b0a1c250SEtienne Carriere {
195b0a1c250SEtienne Carriere 	FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes);
196b0a1c250SEtienne Carriere 
197b0a1c250SEtienne Carriere 	switch (cmd) {
198b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_CAPABILITIES:
199b0a1c250SEtienne Carriere 		return cmd_capabilities(ptypes, params);
200b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL:
201b0a1c250SEtienne Carriere 		return cmd_process_smt_channel(ptypes, params);
202b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE:
203b0a1c250SEtienne Carriere 		return cmd_process_smt_message(ptypes, params);
204*8ea50d3bSEtienne Carriere 	case PTA_SCMI_CMD_PROCESS_MSG_CHANNEL:
205*8ea50d3bSEtienne Carriere 		return cmd_process_msg_channel(ptypes, params);
206b0a1c250SEtienne Carriere 	case PTA_SCMI_CMD_GET_CHANNEL_HANDLE:
207b0a1c250SEtienne Carriere 		return cmd_get_channel_handle(ptypes, params);
208b0a1c250SEtienne Carriere 	default:
209b0a1c250SEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
210b0a1c250SEtienne Carriere 	}
211b0a1c250SEtienne Carriere }
212b0a1c250SEtienne Carriere 
213b0a1c250SEtienne Carriere pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME,
214b0a1c250SEtienne Carriere 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
215b0a1c250SEtienne Carriere 			    TA_FLAG_DEVICE_ENUM,
216b0a1c250SEtienne Carriere 		   .open_session_entry_point = pta_scmi_open_session,
217b0a1c250SEtienne Carriere 		   .invoke_command_entry_point = pta_scmi_invoke_command);
218