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