1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2020-2022 Linaro Limited. 4 */ 5 6#define LOG_CATEGORY UCLASS_SCMI_AGENT 7 8#include <common.h> 9#include <dm.h> 10#include <errno.h> 11#include <scmi_agent.h> 12#include <scmi_agent-uclass.h> 13#include <string.h> 14#include <tee.h> 15#include <asm/types.h> 16#include <dm/device_compat.h> 17#include <dm/devres.h> 18#include <linux/arm-smccc.h> 19#include <linux/bug.h> 20#include <linux/compat.h> 21 22#include "smt.h" 23 24#define SCMI_SHM_SIZE 128 25 26/** 27 * struct scmi_optee_channel - Description of an SCMI OP-TEE transport 28 * @channel_id: Channel identifier 29 * @smt: Shared memory buffer with synchronisation protocol 30 * @dyn_shm: True if using dynamically allocated shared memory 31 */ 32struct scmi_optee_channel { 33 unsigned int channel_id; 34 struct scmi_smt smt; 35 bool dyn_shm; 36}; 37 38/** 39 * struct scmi_channel - Channel instance referenced in SCMI drivers 40 * @ref: Reference to local channel instance 41 **/ 42struct scmi_channel { 43 struct scmi_optee_channel ref; 44}; 45 46/** 47 * struct channel_session - Aggreates SCMI service session context references 48 * @tee: OP-TEE device to invoke 49 * @tee_session: OP-TEE session identifier 50 * @tee_shm: Dynamically allocated OP-TEE shared memory, or NULL 51 * @channel_hdl: Channel handle provided by OP-TEE SCMI service 52 */ 53struct channel_session { 54 struct udevice *tee; 55 u32 tee_session; 56 struct tee_shm *tee_shm; 57 u32 channel_hdl; 58}; 59 60#define TA_SCMI_UUID { 0xa8cfe406, 0xd4f5, 0x4a2e, \ 61 { 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99 } } 62 63enum optee_smci_pta_cmd { 64 /* 65 * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities 66 * 67 * [out] value[0].a: Capability bit mask (enum pta_scmi_caps) 68 * [out] value[0].b: Extended capabilities or 0 69 */ 70 PTA_SCMI_CMD_CAPABILITIES = 0, 71 72 /* 73 * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer 74 * 75 * [in] value[0].a: Channel handle 76 * 77 * Shared memory used for SCMI message/response exhange is expected 78 * already identified and bound to channel handle in both SCMI agent 79 * and SCMI server (OP-TEE) parts. 80 * The memory uses SMT header to carry SCMI meta-data (protocol ID and 81 * protocol message ID). 82 */ 83 PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1, 84 85 /* 86 * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message 87 * 88 * [in] value[0].a: Channel handle 89 * [in/out] memref[1]: Message/response buffer (SMT and SCMI payload) 90 * 91 * Shared memory used for SCMI message/response is a SMT buffer 92 * referenced by param[1]. It shall be 128 bytes large to fit response 93 * payload whatever message playload size. 94 * The memory uses SMT header to carry SCMI meta-data (protocol ID and 95 * protocol message ID). 96 */ 97 PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2, 98 99 /* 100 * PTA_SCMI_CMD_GET_CHANNEL - Get channel handle 101 * 102 * [in] value[0].a: Channel identifier 103 * [out] value[0].a: Returned channel handle 104 * [in] value[0].b: Requested capabilities mask (enum pta_scmi_caps) 105 */ 106 PTA_SCMI_CMD_GET_CHANNEL = 3, 107 108 /* 109 * PTA_SCMI_CMD_PROCESS_MSG_CHANNEL - Process SCMI message in MSG 110 * buffers pointed by memref parameters 111 * 112 * [in] value[0].a: Channel handle 113 * [in] memref[1]: Message buffer (MSG header and SCMI payload) 114 * [out] memref[2]: Response buffer (MSG header and SCMI payload) 115 * 116 * Shared memories used for SCMI message/response are MSG buffers 117 * referenced by param[1] and param[2]. MSG transport protocol 118 * uses a 32bit header to carry SCMI meta-data (protocol ID and 119 * protocol message ID) followed by the effective SCMI message 120 * payload. 121 */ 122 PTA_SCMI_CMD_PROCESS_MSG_CHANNEL = 4, 123}; 124 125/* 126 * OP-TEE SCMI service capabilities bit flags (32bit) 127 * 128 * PTA_SCMI_CAPS_SMT_HEADER 129 * When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in 130 * shared memory buffers to carry SCMI protocol synchronisation information. 131 * 132 * PTA_SCMI_CAPS_MSG_HEADER 133 * When set, OP-TEE supports command using MSG header protocol in an OP-TEE 134 * shared memory to carry SCMI protocol synchronisation information and SCMI 135 * message payload. 136 */ 137#define PTA_SCMI_CAPS_NONE 0 138#define PTA_SCMI_CAPS_SMT_HEADER BIT(0) 139#define PTA_SCMI_CAPS_MSG_HEADER BIT(1) 140#define PTA_SCMI_CAPS_MASK (PTA_SCMI_CAPS_SMT_HEADER | \ 141 PTA_SCMI_CAPS_MSG_HEADER) 142 143static int open_channel(struct udevice *dev, struct scmi_optee_channel *chan, 144 struct channel_session *sess) 145{ 146 const struct tee_optee_ta_uuid uuid = TA_SCMI_UUID; 147 struct tee_open_session_arg sess_arg = { }; 148 struct tee_invoke_arg cmd_arg = { }; 149 struct tee_param param[1] = { }; 150 int ret; 151 152 memset(sess, 0, sizeof(*sess)); 153 154 sess->tee = tee_find_device(NULL, NULL, NULL, NULL); 155 if (!sess->tee) 156 return -ENODEV; 157 158 sess_arg.clnt_login = TEE_LOGIN_REE_KERNEL; 159 tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid); 160 161 ret = tee_open_session(sess->tee, &sess_arg, 0, NULL); 162 if (ret) { 163 dev_err(dev, "can't open session: %d\n", ret); 164 return ret; 165 } 166 167 cmd_arg.func = PTA_SCMI_CMD_GET_CHANNEL; 168 cmd_arg.session = sess_arg.session; 169 170 param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT; 171 param[0].u.value.a = chan->channel_id; 172 if (chan->dyn_shm) 173 param[0].u.value.b = PTA_SCMI_CAPS_MSG_HEADER; 174 else 175 param[0].u.value.b = PTA_SCMI_CAPS_SMT_HEADER; 176 177 ret = tee_invoke_func(sess->tee, &cmd_arg, ARRAY_SIZE(param), param); 178 if (ret || cmd_arg.ret) { 179 dev_err(dev, "Invoke failed: %d, 0x%x\n", ret, cmd_arg.ret); 180 if (!ret) 181 ret = -EPROTO; 182 183 tee_close_session(sess->tee, sess_arg.session); 184 return ret; 185 } 186 187 sess->tee_session = sess_arg.session; 188 sess->channel_hdl = param[0].u.value.a; 189 190 return 0; 191} 192 193static void close_channel(struct channel_session *sess) 194{ 195 tee_close_session(sess->tee, sess->tee_session); 196} 197 198static int invoke_cmd(struct udevice *dev, struct scmi_optee_channel *chan, 199 struct channel_session *sess, struct scmi_msg *msg) 200{ 201 struct tee_invoke_arg arg = { }; 202 struct tee_param param[3] = { }; 203 int ret; 204 205 arg.session = sess->tee_session; 206 param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT; 207 param[0].u.value.a = sess->channel_hdl; 208 209 if (sess->tee_shm) { 210 size_t in_size; 211 212 ret = scmi_msg_to_smt_msg(dev, &chan->smt, msg, &in_size); 213 if (ret < 0) 214 return ret; 215 216 arg.func = PTA_SCMI_CMD_PROCESS_MSG_CHANNEL; 217 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT; 218 param[1].u.memref.shm = sess->tee_shm; 219 param[1].u.memref.size = in_size; 220 param[2].attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 221 param[2].u.memref.shm = sess->tee_shm; 222 param[2].u.memref.size = sess->tee_shm->size; 223 } else { 224 arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL; 225 scmi_write_msg_to_smt(dev, &chan->smt, msg); 226 } 227 228 ret = tee_invoke_func(sess->tee, &arg, ARRAY_SIZE(param), param); 229 if (ret || arg.ret) { 230 if (!ret) 231 ret = -EPROTO; 232 233 return ret; 234 } 235 236 if (sess->tee_shm) { 237 ret = scmi_msg_from_smt_msg(dev, &chan->smt, msg, 238 param[2].u.memref.size); 239 } else { 240 ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); 241 scmi_clear_smt_channel(&chan->smt); 242 } 243 244 return ret; 245} 246 247static int prepare_shm(struct udevice *dev, struct scmi_optee_channel *chan, 248 struct channel_session *sess) 249{ 250 int ret; 251 252 /* Static shm is already prepared by the firmware: nothing to do */ 253 if (!chan->dyn_shm) 254 return 0; 255 256 chan->smt.size = SCMI_SHM_SIZE; 257 258 ret = tee_shm_alloc(sess->tee, chan->smt.size, 0, &sess->tee_shm); 259 if (ret) { 260 dev_err(dev, "Failed to allocated shmem: %d\n", ret); 261 return ret; 262 } 263 264 chan->smt.buf = sess->tee_shm->addr; 265 266 return 0; 267} 268 269static void release_shm(struct udevice *dev, struct channel_session *sess) 270{ 271 struct scmi_optee_channel *chan = dev_get_plat(dev); 272 273 if (chan->dyn_shm) 274 tee_shm_free(sess->tee_shm); 275} 276 277static int scmi_optee_process_msg(struct udevice *dev, 278 struct scmi_channel *channel, 279 struct scmi_msg *msg) 280{ 281 struct scmi_optee_channel *chan = &channel->ref; 282 struct channel_session sess = { }; 283 int ret; 284 285 ret = open_channel(dev, chan, &sess); 286 if (ret) 287 return ret; 288 289 ret = prepare_shm(dev, chan, &sess); 290 if (ret) 291 goto out; 292 293 ret = invoke_cmd(dev, chan, &sess, msg); 294 295 release_shm(dev, &sess); 296 297out: 298 close_channel(&sess); 299 300 return ret; 301} 302 303static int setup_channel(struct udevice *dev, struct scmi_optee_channel *chan) 304{ 305 int ret; 306 307 if (dev_read_u32(dev, "linaro,optee-channel-id", &chan->channel_id)) { 308 dev_err(dev, "Missing property linaro,optee-channel-id\n"); 309 return -EINVAL; 310 } 311 312 if (dev_read_prop(dev, "shmem", NULL)) { 313 ret = scmi_dt_get_smt_buffer(dev, &chan->smt); 314 if (ret) { 315 dev_err(dev, "Failed to get smt resources: %d\n", ret); 316 return ret; 317 } 318 chan->dyn_shm = false; 319 } else { 320 chan->dyn_shm = true; 321 } 322 323 return 0; 324} 325 326static int scmi_optee_get_channel(struct udevice *dev, 327 struct udevice *protocol, 328 struct scmi_channel **channel) 329{ 330 struct scmi_optee_channel *base_chan = dev_get_plat(dev); 331 struct scmi_optee_channel *chan; 332 u32 channel_id; 333 int ret; 334 335 if (dev_read_u32(protocol, "linaro,optee-channel-id", &channel_id)) { 336 /* Uses agent base channel */ 337 *channel = container_of(base_chan, struct scmi_channel, ref); 338 339 return 0; 340 } 341 342 /* Setup a dedicated channel */ 343 chan = calloc(1, sizeof(*chan)); 344 if (!chan) 345 return -ENOMEM; 346 347 ret = setup_channel(protocol, chan); 348 if (ret) { 349 free(chan); 350 return ret; 351 } 352 353 *channel = container_of(chan, struct scmi_channel, ref); 354 355 return 0; 356} 357 358static int scmi_optee_of_to_plat(struct udevice *dev) 359{ 360 struct scmi_optee_channel *chan = dev_get_plat(dev); 361 362 return setup_channel(dev, chan); 363} 364 365static int scmi_optee_probe(struct udevice *dev) 366{ 367 struct scmi_optee_channel *chan = dev_get_plat(dev); 368 struct channel_session sess; 369 int ret; 370 371 /* Check OP-TEE service acknowledges the SCMI channel */ 372 ret = open_channel(dev, chan, &sess); 373 if (!ret) 374 close_channel(&sess); 375 376 return ret; 377} 378 379static const struct udevice_id scmi_optee_ids[] = { 380 { .compatible = "linaro,scmi-optee" }, 381 { } 382}; 383 384static const struct scmi_agent_ops scmi_optee_ops = { 385 .of_get_channel = scmi_optee_get_channel, 386 .process_msg = scmi_optee_process_msg, 387}; 388 389U_BOOT_DRIVER(scmi_optee) = { 390 .name = "scmi-over-optee", 391 .id = UCLASS_SCMI_AGENT, 392 .of_match = scmi_optee_ids, 393 .plat_auto = sizeof(struct scmi_optee_channel), 394 .of_to_plat = scmi_optee_of_to_plat, 395 .probe = scmi_optee_probe, 396 .flags = DM_FLAG_OS_PREPARE, 397 .ops = &scmi_optee_ops, 398}; 399