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