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