1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019-2021, Linaro Limited
4  * Copyright (c) 2019-2021, STMicroelectronics
5  */
6 #include <compiler.h>
7 #include <config.h>
8 #include <drivers/scmi-msg.h>
9 #include <kernel/pseudo_ta.h>
10 #include <pta_scmi_client.h>
11 #include <stdint.h>
12 #include <string.h>
13 
cmd_capabilities(uint32_t ptypes,TEE_Param param[TEE_NUM_PARAMS])14 static TEE_Result cmd_capabilities(uint32_t ptypes,
15 				   TEE_Param param[TEE_NUM_PARAMS])
16 {
17 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
18 						    TEE_PARAM_TYPE_NONE,
19 						    TEE_PARAM_TYPE_NONE,
20 						    TEE_PARAM_TYPE_NONE);
21 	uint32_t caps = 0;
22 
23 	if (ptypes != exp_ptypes)
24 		return TEE_ERROR_BAD_PARAMETERS;
25 
26 	if (IS_ENABLED(CFG_SCMI_MSG_SMT))
27 		caps |= PTA_SCMI_CAPS_SMT_HEADER;
28 
29 	param[0].value.a = caps;
30 	param[0].value.b = 0;
31 
32 	return TEE_SUCCESS;
33 }
34 
cmd_process_smt_channel(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])35 static TEE_Result cmd_process_smt_channel(uint32_t ptypes,
36 					  TEE_Param params[TEE_NUM_PARAMS])
37 {
38 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
39 						    TEE_PARAM_TYPE_NONE,
40 						    TEE_PARAM_TYPE_NONE,
41 						    TEE_PARAM_TYPE_NONE);
42 	unsigned int channel_id = params[0].value.a;
43 
44 	if (ptypes != exp_ptypes)
45 		return TEE_ERROR_BAD_PARAMETERS;
46 
47 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
48 		struct scmi_msg_channel *channel = NULL;
49 
50 		channel = plat_scmi_get_channel(channel_id);
51 		if (!channel)
52 			return TEE_ERROR_BAD_PARAMETERS;
53 
54 		scmi_smt_threaded_entry(channel_id);
55 
56 		return TEE_SUCCESS;
57 	}
58 
59 	return TEE_ERROR_NOT_SUPPORTED;
60 }
61 
cmd_process_smt_message(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])62 static TEE_Result cmd_process_smt_message(uint32_t ptypes,
63 					  TEE_Param params[TEE_NUM_PARAMS])
64 {
65 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
66 						    TEE_PARAM_TYPE_MEMREF_INOUT,
67 						    TEE_PARAM_TYPE_NONE,
68 						    TEE_PARAM_TYPE_NONE);
69 	unsigned int channel_id = params[0].value.a;
70 	TEE_Param *param1 = params + 1;
71 
72 	if (ptypes != exp_ptypes)
73 		return TEE_ERROR_BAD_PARAMETERS;
74 
75 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
76 		struct scmi_msg_channel *channel = NULL;
77 
78 		if (param1->memref.size < SMT_BUF_SLOT_SIZE)
79 			return TEE_ERROR_BAD_PARAMETERS;
80 
81 		channel = plat_scmi_get_channel(channel_id);
82 		if (!channel)
83 			return TEE_ERROR_BAD_PARAMETERS;
84 
85 		/*
86 		 * Caller provides the buffer, we bind channel to that buffer.
87 		 * Once message is processed, unbind the buffer since it is
88 		 * valid only for the current invocation.
89 		 */
90 		scmi_smt_set_shared_buffer(channel, param1->memref.buffer);
91 		scmi_smt_threaded_entry(channel_id);
92 		scmi_smt_set_shared_buffer(channel, NULL);
93 
94 		return TEE_SUCCESS;
95 	}
96 
97 	return TEE_ERROR_NOT_SUPPORTED;
98 }
99 
cmd_get_channel_handle(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])100 static TEE_Result cmd_get_channel_handle(uint32_t ptypes,
101 					 TEE_Param params[TEE_NUM_PARAMS])
102 {
103 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
104 						    TEE_PARAM_TYPE_NONE,
105 						    TEE_PARAM_TYPE_NONE,
106 						    TEE_PARAM_TYPE_NONE);
107 	unsigned int channel_id = params[0].value.a;
108 	unsigned int caps = params[0].value.b;
109 
110 	if (ptypes != exp_ptypes)
111 		return TEE_ERROR_BAD_PARAMETERS;
112 
113 	if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
114 		struct scmi_msg_channel *channel = NULL;
115 
116 		if (caps != PTA_SCMI_CAPS_SMT_HEADER)
117 			return TEE_ERROR_NOT_SUPPORTED;
118 
119 		channel = plat_scmi_get_channel(channel_id);
120 		if (!channel)
121 			return TEE_ERROR_BAD_PARAMETERS;
122 
123 		channel->threaded = true;
124 		params[0].value.a = scmi_smt_channel_handle(channel_id);
125 
126 		return TEE_SUCCESS;
127 	}
128 
129 	return TEE_ERROR_NOT_SUPPORTED;
130 }
131 
pta_scmi_open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)132 static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused,
133 					TEE_Param par[TEE_NUM_PARAMS] __unused,
134 					void **session __unused)
135 {
136 	struct ts_session *ts = ts_get_current_session();
137 	struct tee_ta_session *ta_session = to_ta_session(ts);
138 
139 	/* Only REE kernel is allowed to access SCMI resources */
140 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) {
141 		DMSG("Expecting TEE_LOGIN_REE_KERNEL");
142 		return TEE_ERROR_ACCESS_DENIED;
143 	}
144 
145 	if (IS_ENABLED(CFG_SCMI_MSG_SMT))
146 		return TEE_SUCCESS;
147 
148 	return TEE_ERROR_NOT_SUPPORTED;
149 }
150 
pta_scmi_invoke_command(void * session __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])151 static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd,
152 					  uint32_t ptypes,
153 					  TEE_Param params[TEE_NUM_PARAMS])
154 {
155 	FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes);
156 
157 	switch (cmd) {
158 	case PTA_SCMI_CMD_CAPABILITIES:
159 		return cmd_capabilities(ptypes, params);
160 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL:
161 		return cmd_process_smt_channel(ptypes, params);
162 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE:
163 		return cmd_process_smt_message(ptypes, params);
164 	case PTA_SCMI_CMD_GET_CHANNEL_HANDLE:
165 		return cmd_get_channel_handle(ptypes, params);
166 	default:
167 		return TEE_ERROR_NOT_SUPPORTED;
168 	}
169 }
170 
171 pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME,
172 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
173 			    TA_FLAG_DEVICE_ENUM,
174 		   .open_session_entry_point = pta_scmi_open_session,
175 		   .invoke_command_entry_point = pta_scmi_invoke_command);
176