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