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> 9*7ff45442SEtienne 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 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 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 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 69*7ff45442SEtienne Carriere if (IS_ENABLED(CFG_SCMI_SCPFW)) 70*7ff45442SEtienne Carriere return scmi_server_smt_process_thread(channel_id); 71*7ff45442SEtienne Carriere 72b0a1c250SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 73b0a1c250SEtienne Carriere } 74b0a1c250SEtienne Carriere 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 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 130*7ff45442SEtienne Carriere if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) { 1318ea50d3bSEtienne Carriere struct scmi_msg_channel *channel = NULL; 1328ea50d3bSEtienne Carriere 133*7ff45442SEtienne Carriere if (!IS_ENABLED(CFG_SCMI_MSG_SHM_MSG)) 134*7ff45442SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 135*7ff45442SEtienne 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 148*7ff45442SEtienne Carriere if (IS_ENABLED(CFG_SCMI_SCPFW)) { 149*7ff45442SEtienne Carriere if (!in_buf || !out_buf) 150*7ff45442SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 151*7ff45442SEtienne Carriere 152*7ff45442SEtienne Carriere res = scmi_server_msg_process_thread(channel_id, in_buf, 153*7ff45442SEtienne Carriere in_size, out_buf, 154*7ff45442SEtienne Carriere &out_size); 155*7ff45442SEtienne Carriere if (!res) { 156*7ff45442SEtienne Carriere params[2].memref.size = (uint32_t)out_size; 157*7ff45442SEtienne Carriere IMSG("scmi optee shm: out %zu", out_size); 158*7ff45442SEtienne Carriere } 159*7ff45442SEtienne Carriere 160*7ff45442SEtienne Carriere return res; 161*7ff45442SEtienne Carriere } 162*7ff45442SEtienne Carriere 1638ea50d3bSEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 1648ea50d3bSEtienne Carriere } 1658ea50d3bSEtienne Carriere 166b0a1c250SEtienne Carriere static TEE_Result cmd_get_channel_handle(uint32_t ptypes, 167b0a1c250SEtienne Carriere TEE_Param params[TEE_NUM_PARAMS]) 168b0a1c250SEtienne Carriere { 169b0a1c250SEtienne Carriere const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, 170b0a1c250SEtienne Carriere TEE_PARAM_TYPE_NONE, 171b0a1c250SEtienne Carriere TEE_PARAM_TYPE_NONE, 172b0a1c250SEtienne Carriere TEE_PARAM_TYPE_NONE); 173b0a1c250SEtienne Carriere unsigned int channel_id = params[0].value.a; 174b0a1c250SEtienne Carriere unsigned int caps = params[0].value.b; 175b0a1c250SEtienne Carriere 17616a5030fSEtienne Carriere if (ptypes != exp_ptypes || caps & ~PTA_SCMI_CAPS_MASK) 177b0a1c250SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 178b0a1c250SEtienne Carriere 17916a5030fSEtienne Carriere if (!(caps & supported_caps())) 18016a5030fSEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 18116a5030fSEtienne Carriere 182916cc52aSEtienne Carriere if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) { 183b0a1c250SEtienne Carriere struct scmi_msg_channel *channel = NULL; 184b0a1c250SEtienne Carriere 185b0a1c250SEtienne Carriere channel = plat_scmi_get_channel(channel_id); 186b0a1c250SEtienne Carriere if (!channel) 187b0a1c250SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 188b0a1c250SEtienne Carriere 189d7b5407fSEtienne Carriere channel->threaded = true; 190b0a1c250SEtienne Carriere params[0].value.a = scmi_smt_channel_handle(channel_id); 191b0a1c250SEtienne Carriere 192b0a1c250SEtienne Carriere return TEE_SUCCESS; 193b0a1c250SEtienne Carriere } 194b0a1c250SEtienne Carriere 195*7ff45442SEtienne Carriere if (IS_ENABLED(CFG_SCMI_SCPFW)) { 196*7ff45442SEtienne Carriere /* Only check the channel ID is known from SCP-firwmare */ 197*7ff45442SEtienne Carriere return scmi_server_get_channel(channel_id, NULL); 198*7ff45442SEtienne Carriere } 199*7ff45442SEtienne Carriere 200b0a1c250SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 201b0a1c250SEtienne Carriere } 202b0a1c250SEtienne Carriere 203b0a1c250SEtienne Carriere static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused, 204b0a1c250SEtienne Carriere TEE_Param par[TEE_NUM_PARAMS] __unused, 205b0a1c250SEtienne Carriere void **session __unused) 206b0a1c250SEtienne Carriere { 207b0a1c250SEtienne Carriere struct ts_session *ts = ts_get_current_session(); 208b0a1c250SEtienne Carriere struct tee_ta_session *ta_session = to_ta_session(ts); 209b0a1c250SEtienne Carriere 210b0a1c250SEtienne Carriere /* Only REE kernel is allowed to access SCMI resources */ 211b0a1c250SEtienne Carriere if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) { 212b0a1c250SEtienne Carriere DMSG("Expecting TEE_LOGIN_REE_KERNEL"); 213b0a1c250SEtienne Carriere return TEE_ERROR_ACCESS_DENIED; 214b0a1c250SEtienne Carriere } 215b0a1c250SEtienne Carriere 216*7ff45442SEtienne Carriere if (IS_ENABLED(CFG_SCMI_MSG_DRVIERS) || IS_ENABLED(CFG_SCMI_SCPFW)) 217b0a1c250SEtienne Carriere return TEE_SUCCESS; 218b0a1c250SEtienne Carriere 219b0a1c250SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 220b0a1c250SEtienne Carriere } 221b0a1c250SEtienne Carriere 222b0a1c250SEtienne Carriere static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd, 223b0a1c250SEtienne Carriere uint32_t ptypes, 224b0a1c250SEtienne Carriere TEE_Param params[TEE_NUM_PARAMS]) 225b0a1c250SEtienne Carriere { 226b0a1c250SEtienne Carriere FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes); 227b0a1c250SEtienne Carriere 228b0a1c250SEtienne Carriere switch (cmd) { 229b0a1c250SEtienne Carriere case PTA_SCMI_CMD_CAPABILITIES: 230b0a1c250SEtienne Carriere return cmd_capabilities(ptypes, params); 231b0a1c250SEtienne Carriere case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL: 232b0a1c250SEtienne Carriere return cmd_process_smt_channel(ptypes, params); 233b0a1c250SEtienne Carriere case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE: 234b0a1c250SEtienne Carriere return cmd_process_smt_message(ptypes, params); 2358ea50d3bSEtienne Carriere case PTA_SCMI_CMD_PROCESS_MSG_CHANNEL: 2368ea50d3bSEtienne Carriere return cmd_process_msg_channel(ptypes, params); 237b0a1c250SEtienne Carriere case PTA_SCMI_CMD_GET_CHANNEL_HANDLE: 238b0a1c250SEtienne Carriere return cmd_get_channel_handle(ptypes, params); 239b0a1c250SEtienne Carriere default: 240b0a1c250SEtienne Carriere return TEE_ERROR_NOT_SUPPORTED; 241b0a1c250SEtienne Carriere } 242b0a1c250SEtienne Carriere } 243b0a1c250SEtienne Carriere 244b0a1c250SEtienne Carriere pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME, 245b0a1c250SEtienne Carriere .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT | 246b0a1c250SEtienne Carriere TA_FLAG_DEVICE_ENUM, 247b0a1c250SEtienne Carriere .open_session_entry_point = pta_scmi_open_session, 248b0a1c250SEtienne Carriere .invoke_command_entry_point = pta_scmi_invoke_command); 249