1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries.
4 */
5
6 #include <initcall.h>
7 #include <kernel/pseudo_ta.h>
8 #include <kernel/user_ta.h>
9 #include <platform_config.h>
10 #include <pta_qcom_pas.h>
11 #include <string.h>
12
13 #include "pas.h"
14
15 #define PTA_NAME "pta.qcom.pas"
16
17 #define TA_PAS_UUID { 0xcff7d191, 0x7ca0, 0x4784, \
18 { 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe} }
19
20 static struct qcom_pas_data wpss_dsp_data = {
21 .pas_id = PAS_ID_WPSS,
22 .base.pa = WPSS_BASE,
23 .size = WPSS_SIZE,
24 .clk_group = QCOM_CLKS_WPSS,
25 };
26
27 static struct qcom_pas_data turing_dsp_data = {
28 .pas_id = PAS_ID_TURING,
29 .base.pa = TURING_BASE,
30 .size = TURING_SIZE,
31 .clk_group = QCOM_CLKS_TURING,
32 };
33
34 static struct qcom_pas_data lpass_dsp_data = {
35 .pas_id = PAS_ID_QDSP6,
36 .base.pa = LPASS_BASE,
37 .size = LPASS_SIZE,
38 .clk_group = QCOM_CLKS_LPASS,
39 };
40
41 static struct qcom_pas_data venus_fw_data = {
42 .pas_id = PAS_ID_VENUS,
43 .base.pa = IRIS_BASE,
44 .size = IRIS_SIZE,
45 };
46
qcom_pas_is_supported(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])47 static TEE_Result qcom_pas_is_supported(uint32_t pt,
48 TEE_Param params[TEE_NUM_PARAMS])
49 {
50 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
51 TEE_PARAM_TYPE_NONE,
52 TEE_PARAM_TYPE_NONE,
53 TEE_PARAM_TYPE_NONE);
54
55 if (pt != exp_pt)
56 return TEE_ERROR_BAD_PARAMETERS;
57
58 DMSG("invoked with pas_id: %d", params[0].value.a);
59
60 if (params[0].value.a != PAS_ID_WPSS &&
61 params[0].value.a != PAS_ID_QDSP6 &&
62 params[0].value.a != PAS_ID_VENUS &&
63 params[0].value.a != PAS_ID_TURING)
64 return TEE_ERROR_NOT_SUPPORTED;
65
66 return TEE_SUCCESS;
67 }
68
qcom_pas_capabilities(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])69 static TEE_Result qcom_pas_capabilities(uint32_t pt,
70 TEE_Param params[TEE_NUM_PARAMS])
71 {
72 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
73 TEE_PARAM_TYPE_VALUE_OUTPUT,
74 TEE_PARAM_TYPE_NONE,
75 TEE_PARAM_TYPE_NONE);
76
77 if (pt != exp_pt)
78 return TEE_ERROR_BAD_PARAMETERS;
79
80 DMSG("invoked with pas_id: %d", params[0].value.a);
81 /* Capabilities flags reserved for future use */
82 params[1].value.a = 0;
83
84 return TEE_SUCCESS;
85 }
86
qcom_pas_init_image(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])87 static TEE_Result qcom_pas_init_image(uint32_t pt,
88 TEE_Param params[TEE_NUM_PARAMS])
89 {
90 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
91 TEE_PARAM_TYPE_MEMREF_INPUT,
92 TEE_PARAM_TYPE_NONE,
93 TEE_PARAM_TYPE_NONE);
94
95 if (pt != exp_pt)
96 return TEE_ERROR_BAD_PARAMETERS;
97
98 DMSG("invoked with pas_id: %d", params[0].value.a);
99
100 if (params[0].value.a != PAS_ID_WPSS &&
101 params[0].value.a != PAS_ID_QDSP6 &&
102 params[0].value.a != PAS_ID_VENUS &&
103 params[0].value.a != PAS_ID_TURING)
104 return TEE_ERROR_NOT_SUPPORTED;
105
106 return TEE_SUCCESS;
107 }
108
qcom_pas_mem_setup(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])109 static TEE_Result qcom_pas_mem_setup(uint32_t pt,
110 TEE_Param params[TEE_NUM_PARAMS])
111 {
112 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
113 TEE_PARAM_TYPE_VALUE_INPUT,
114 TEE_PARAM_TYPE_NONE,
115 TEE_PARAM_TYPE_NONE);
116 struct qcom_pas_data *data = NULL;
117
118 if (pt != exp_pt)
119 return TEE_ERROR_BAD_PARAMETERS;
120
121 DMSG("invoked with pas_id: %d", params[0].value.a);
122
123 switch (params[0].value.a) {
124 case PAS_ID_WPSS:
125 data = &wpss_dsp_data;
126 break;
127 case PAS_ID_TURING:
128 data = &turing_dsp_data;
129 break;
130 case PAS_ID_QDSP6:
131 data = &lpass_dsp_data;
132 break;
133 case PAS_ID_VENUS:
134 data = &venus_fw_data;
135 break;
136 default:
137 return TEE_ERROR_NOT_SUPPORTED;
138 }
139
140 data->fw_size = params[0].value.b;
141 data->fw_base = params[1].value.a;
142 data->fw_base |= SHIFT_U64(params[1].value.b, 32);
143
144 /* Map the controller */
145 if (!data->base.va) {
146 data->base.va = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_NSEC,
147 data->base.pa,
148 data->size);
149 if (!data->base.va)
150 return TEE_ERROR_GENERIC;
151 }
152
153 return TEE_SUCCESS;
154 }
155
qcom_pas_get_resource_table(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])156 static TEE_Result qcom_pas_get_resource_table(uint32_t pt,
157 TEE_Param params[TEE_NUM_PARAMS])
158 {
159 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
160 TEE_PARAM_TYPE_MEMREF_INOUT,
161 TEE_PARAM_TYPE_NONE,
162 TEE_PARAM_TYPE_NONE);
163
164 if (pt != exp_pt)
165 return TEE_ERROR_BAD_PARAMETERS;
166
167 DMSG("invoked with pas_id: %d", params[0].value.a);
168
169 if (params[0].value.a != PAS_ID_WPSS &&
170 params[0].value.a != PAS_ID_TURING &&
171 params[0].value.a != PAS_ID_QDSP6)
172 return TEE_ERROR_NOT_SUPPORTED;
173
174 return pas_get_resource_table(params[0].value.a,
175 params[1].memref.buffer,
176 ¶ms[1].memref.size);
177 }
178
179 static TEE_Result
qcom_pas_set_remote_state(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS]__maybe_unused)180 qcom_pas_set_remote_state(uint32_t pt,
181 TEE_Param params[TEE_NUM_PARAMS]__maybe_unused)
182 {
183 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
184 TEE_PARAM_TYPE_NONE,
185 TEE_PARAM_TYPE_NONE,
186 TEE_PARAM_TYPE_NONE);
187
188 if (pt != exp_pt)
189 return TEE_ERROR_BAD_PARAMETERS;
190
191 DMSG("invoked with pas_id: %d", params[0].value.a);
192
193 if (params[0].value.a == PAS_ID_VENUS)
194 return venus_fw_set_state(&venus_fw_data, params[0].value.b);
195
196 return TEE_ERROR_NOT_IMPLEMENTED;
197 }
198
qcom_pas_auth_and_reset(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])199 static TEE_Result qcom_pas_auth_and_reset(uint32_t pt,
200 TEE_Param params[TEE_NUM_PARAMS])
201 {
202 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
203 TEE_PARAM_TYPE_VALUE_INPUT,
204 TEE_PARAM_TYPE_MEMREF_INPUT,
205 TEE_PARAM_TYPE_NONE);
206 TEE_Result res = TEE_SUCCESS;
207
208 if (pt != exp_pt)
209 return TEE_ERROR_BAD_PARAMETERS;
210
211 DMSG("invoked with pas_id: %d", params[0].value.a);
212
213 switch (params[0].value.a) {
214 case PAS_ID_WPSS:
215 if (!wpss_dsp_data.fw_base)
216 return TEE_ERROR_NO_DATA;
217
218 res = qcom_clock_enable(wpss_dsp_data.clk_group);
219 if (res != TEE_SUCCESS) {
220 EMSG("Failed to enable clocks: %d", res);
221 return res;
222 }
223
224 return wpss_fw_start(&wpss_dsp_data);
225 case PAS_ID_TURING:
226 if (!turing_dsp_data.fw_base)
227 return TEE_ERROR_NO_DATA;
228
229 res = qcom_clock_enable(turing_dsp_data.clk_group);
230 if (res != TEE_SUCCESS) {
231 EMSG("Failed to enable clocks: %d", res);
232 return res;
233 }
234
235 return compute_fw_start(&turing_dsp_data);
236 case PAS_ID_QDSP6:
237 if (!lpass_dsp_data.fw_base)
238 return TEE_ERROR_NO_DATA;
239
240 res = qcom_clock_enable(lpass_dsp_data.clk_group);
241 if (res != TEE_SUCCESS) {
242 EMSG("Failed to enable clocks: %d", res);
243 return res;
244 }
245
246 return lpass_fw_start(&lpass_dsp_data);
247 case PAS_ID_VENUS:
248 if (!venus_fw_data.fw_base)
249 return TEE_ERROR_NO_DATA;
250
251 return venus_fw_start(&venus_fw_data);
252 default:
253 return TEE_ERROR_NOT_SUPPORTED;
254 }
255 }
256
257 static TEE_Result
qcom_pas_shutdown(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS]__maybe_unused)258 qcom_pas_shutdown(uint32_t pt,
259 TEE_Param params[TEE_NUM_PARAMS] __maybe_unused)
260 {
261 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
262 TEE_PARAM_TYPE_NONE,
263 TEE_PARAM_TYPE_NONE,
264 TEE_PARAM_TYPE_NONE);
265
266 if (pt != exp_pt)
267 return TEE_ERROR_BAD_PARAMETERS;
268
269 DMSG("invoked with pas_id: %d", params[0].value.a);
270
271 switch (params[0].value.a) {
272 case PAS_ID_WPSS:
273 return wpss_fw_shutdown(&wpss_dsp_data);
274 case PAS_ID_TURING:
275 return compute_fw_shutdown(&turing_dsp_data);
276 case PAS_ID_QDSP6:
277 return lpass_fw_shutdown(&lpass_dsp_data);
278 case PAS_ID_VENUS:
279 return venus_fw_shutdown(&venus_fw_data);
280 default:
281 return TEE_ERROR_NOT_SUPPORTED;
282 }
283
284 return TEE_ERROR_NOT_IMPLEMENTED;
285 }
286
pta_qcom_pas_invoke_command(void * session __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])287 static TEE_Result pta_qcom_pas_invoke_command(void *session __unused,
288 uint32_t cmd_id,
289 uint32_t param_types,
290 TEE_Param params[TEE_NUM_PARAMS])
291 {
292 switch (cmd_id) {
293 case PTA_QCOM_PAS_IS_SUPPORTED:
294 return qcom_pas_is_supported(param_types, params);
295 case PTA_QCOM_PAS_CAPABILITIES:
296 return qcom_pas_capabilities(param_types, params);
297 case PTA_QCOM_PAS_INIT_IMAGE:
298 return qcom_pas_init_image(param_types, params);
299 case PTA_QCOM_PAS_MEM_SETUP:
300 return qcom_pas_mem_setup(param_types, params);
301 case PTA_QCOM_PAS_GET_RESOURCE_TABLE:
302 return qcom_pas_get_resource_table(param_types, params);
303 case PTA_QCOM_PAS_AUTH_AND_RESET:
304 return qcom_pas_auth_and_reset(param_types, params);
305 case PTA_QCOM_PAS_SET_REMOTE_STATE:
306 return qcom_pas_set_remote_state(param_types, params);
307 case PTA_QCOM_PAS_SHUTDOWN:
308 return qcom_pas_shutdown(param_types, params);
309 default:
310 return TEE_ERROR_NOT_IMPLEMENTED;
311 }
312 }
313
314 /*
315 * Pseudo Trusted Application entry points
316 */
317 static TEE_Result
pta_qcom_pas_open_session(uint32_t pt __unused,TEE_Param params[TEE_NUM_PARAMS]__unused,void ** sess_ctx __unused)318 pta_qcom_pas_open_session(uint32_t pt __unused,
319 TEE_Param params[TEE_NUM_PARAMS] __unused,
320 void **sess_ctx __unused)
321 {
322 struct ts_session *s = ts_get_calling_session();
323 struct ts_ctx *ctx = NULL;
324 TEE_UUID ta_uuid = TA_PAS_UUID;
325
326 if (!s)
327 return TEE_ERROR_ACCESS_DENIED;
328
329 ctx = s->ctx;
330 if (memcmp(&ctx->uuid, &ta_uuid, sizeof(TEE_UUID)))
331 return TEE_ERROR_ACCESS_DENIED;
332
333 return TEE_SUCCESS;
334 }
335
336 /*
337 * TA_FLAG_CONCURRENT disabled:
338 * concurrent operation must be supported by the client.
339 */
340 pseudo_ta_register(.uuid = PTA_QCOM_PAS_UUID, .name = PTA_NAME,
341 .flags = PTA_DEFAULT_FLAGS,
342 .invoke_command_entry_point = pta_qcom_pas_invoke_command,
343 .open_session_entry_point = pta_qcom_pas_open_session);
344