Merge tag 'u-boot-at91-2022.04-a' of https://source.denx.de/u-boot/custodians/u-boot...
[platform/kernel/u-boot.git] / drivers / firmware / scmi / optee_agent.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020-2021 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  */
32 struct scmi_optee_channel {
33         unsigned int channel_id;
34         struct scmi_smt smt;
35         bool dyn_shm;
36 };
37
38 /**
39  * struct channel_session - Aggreates SCMI service session context references
40  * @tee:                OP-TEE device to invoke
41  * @tee_session:        OP-TEE session identifier
42  * @tee_shm:            Dynamically allocated OP-TEE shared memory, or NULL
43  * @channel_hdl:        Channel handle provided by OP-TEE SCMI service
44  */
45 struct channel_session {
46         struct udevice *tee;
47         u32 tee_session;
48         struct tee_shm *tee_shm;
49         u32 channel_hdl;
50 };
51
52 #define TA_SCMI_UUID { 0xa8cfe406, 0xd4f5, 0x4a2e, \
53                       { 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99 } }
54
55 enum optee_smci_pta_cmd {
56         /*
57          * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities
58          *
59          * [out]    value[0].a: Capability bit mask (enum pta_scmi_caps)
60          * [out]    value[0].b: Extended capabilities or 0
61          */
62         PTA_SCMI_CMD_CAPABILITIES = 0,
63
64         /*
65          * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer
66          *
67          * [in]     value[0].a: Channel handle
68          *
69          * Shared memory used for SCMI message/response exhange is expected
70          * already identified and bound to channel handle in both SCMI agent
71          * and SCMI server (OP-TEE) parts.
72          * The memory uses SMT header to carry SCMI meta-data (protocol ID and
73          * protocol message ID).
74          */
75         PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,
76
77         /*
78          * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message
79          *
80          * [in]     value[0].a: Channel handle
81          * [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)
82          *
83          * Shared memory used for SCMI message/response is a SMT buffer
84          * referenced by param[1]. It shall be 128 bytes large to fit response
85          * payload whatever message playload size.
86          * The memory uses SMT header to carry SCMI meta-data (protocol ID and
87          * protocol message ID).
88          */
89         PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,
90
91         /*
92          * PTA_SCMI_CMD_GET_CHANNEL - Get channel handle
93          *
94          * SCMI shm information are 0 if agent expects to use OP-TEE regular SHM
95          *
96          * [in]     value[0].a: Channel identifier
97          * [out]    value[0].a: Returned channel handle
98          * [in]     value[0].b: Requested capabilities mask (enum pta_scmi_caps)
99          */
100         PTA_SCMI_CMD_GET_CHANNEL = 3,
101 };
102
103 /*
104  * OP-TEE SCMI service capabilities bit flags (32bit)
105  *
106  * PTA_SCMI_CAPS_SMT_HEADER
107  * When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in
108  * shared memory buffers to carry SCMI protocol synchronisation information.
109  */
110 #define PTA_SCMI_CAPS_NONE              0
111 #define PTA_SCMI_CAPS_SMT_HEADER        BIT(0)
112
113 static int open_channel(struct udevice *dev, struct channel_session *sess)
114 {
115         const struct tee_optee_ta_uuid uuid = TA_SCMI_UUID;
116         struct scmi_optee_channel *chan = dev_get_plat(dev);
117         struct tee_open_session_arg sess_arg = { };
118         struct tee_invoke_arg cmd_arg = { };
119         struct tee_param param[1] = { };
120         int ret;
121
122         memset(sess, 0, sizeof(sess));
123
124         sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
125         if (!sess->tee)
126                 return -ENODEV;
127
128         sess_arg.clnt_login = TEE_LOGIN_REE_KERNEL;
129         tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid);
130
131         ret = tee_open_session(sess->tee, &sess_arg, 0, NULL);
132         if (ret) {
133                 dev_err(dev, "can't open session: %d\n", ret);
134                 return ret;
135         }
136
137         cmd_arg.func = PTA_SCMI_CMD_GET_CHANNEL;
138         cmd_arg.session = sess_arg.session;
139
140         param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT;
141         param[0].u.value.a = chan->channel_id;
142         param[0].u.value.b = PTA_SCMI_CAPS_SMT_HEADER;
143
144         ret = tee_invoke_func(sess->tee, &cmd_arg, ARRAY_SIZE(param), param);
145         if (ret || cmd_arg.ret) {
146                 dev_err(dev, "Invoke failed: %d, 0x%x\n", ret, cmd_arg.ret);
147                 if (!ret)
148                         ret = -EPROTO;
149
150                 tee_close_session(sess->tee, sess_arg.session);
151                 return ret;
152         }
153
154         sess->tee_session = sess_arg.session;
155         sess->channel_hdl = param[0].u.value.a;
156
157         return 0;
158 }
159
160 static void close_channel(struct channel_session *sess)
161 {
162         tee_close_session(sess->tee, sess->tee_session);
163 }
164
165 static int invoke_cmd(struct udevice *dev, struct channel_session *sess,
166                       struct scmi_msg *msg)
167 {
168         struct scmi_optee_channel *chan = dev_get_plat(dev);
169         struct tee_invoke_arg arg = { };
170         struct tee_param param[2] = { };
171         int ret;
172
173         scmi_write_msg_to_smt(dev, &chan->smt, msg);
174
175         arg.session = sess->tee_session;
176         param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
177         param[0].u.value.a = sess->channel_hdl;
178
179         if (chan->dyn_shm) {
180                 arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE;
181                 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
182                 param[1].u.memref.shm = sess->tee_shm;
183                 param[1].u.memref.size = SCMI_SHM_SIZE;
184         } else {
185                 arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL;
186         }
187
188         ret = tee_invoke_func(sess->tee, &arg, ARRAY_SIZE(param), param);
189         if (ret || arg.ret) {
190                 if (!ret)
191                         ret = -EPROTO;
192         } else {
193                 ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
194         }
195
196         scmi_clear_smt_channel(&chan->smt);
197
198         return ret;
199 }
200
201 static int prepare_shm(struct udevice *dev, struct channel_session *sess)
202 {
203         struct scmi_optee_channel *chan = dev_get_plat(dev);
204         int ret;
205
206         /* Static shm is already prepared by the firmware: nothing to do */
207         if (!chan->dyn_shm)
208                 return 0;
209
210         chan->smt.size = SCMI_SHM_SIZE;
211
212         ret = tee_shm_alloc(sess->tee, chan->smt.size, 0, &sess->tee_shm);
213         if (ret) {
214                 dev_err(dev, "Failed to allocated shmem: %d\n", ret);
215                 return ret;
216         }
217
218         chan->smt.buf = sess->tee_shm->addr;
219
220         /* Initialize shm buffer for message exchanges */
221         scmi_clear_smt_channel(&chan->smt);
222
223         return 0;
224 }
225
226 static void release_shm(struct udevice *dev, struct channel_session *sess)
227 {
228         struct scmi_optee_channel *chan = dev_get_plat(dev);
229
230         if (chan->dyn_shm)
231                 tee_shm_free(sess->tee_shm);
232 }
233
234 static int scmi_optee_process_msg(struct udevice *dev, struct scmi_msg *msg)
235 {
236         struct channel_session sess;
237         int ret;
238
239         ret = open_channel(dev, &sess);
240         if (ret)
241                 return ret;
242
243         ret = prepare_shm(dev, &sess);
244         if (ret)
245                 goto out;
246
247         ret = invoke_cmd(dev, &sess, msg);
248
249         release_shm(dev, &sess);
250
251 out:
252         close_channel(&sess);
253
254         return ret;
255 }
256
257 static int scmi_optee_of_to_plat(struct udevice *dev)
258 {
259         struct scmi_optee_channel *chan = dev_get_plat(dev);
260         int ret;
261
262         if (dev_read_u32(dev, "linaro,optee-channel-id", &chan->channel_id)) {
263                 dev_err(dev, "Missing property linaro,optee-channel-id\n");
264                 return -EINVAL;
265         }
266
267         if (dev_read_prop(dev, "shmem", NULL)) {
268                 ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
269                 if (ret) {
270                         dev_err(dev, "Failed to get smt resources: %d\n", ret);
271                         return ret;
272                 }
273                 chan->dyn_shm = false;
274         } else {
275                 chan->dyn_shm = true;
276         }
277
278         return 0;
279 }
280
281 static int scmi_optee_probe(struct udevice *dev)
282 {
283         struct channel_session sess;
284         int ret;
285
286         /* Check OP-TEE service acknowledges the SCMI channel */
287         ret = open_channel(dev, &sess);
288         if (!ret)
289                 close_channel(&sess);
290
291         return ret;
292 }
293
294 static const struct udevice_id scmi_optee_ids[] = {
295         { .compatible = "linaro,scmi-optee" },
296         { }
297 };
298
299 static const struct scmi_agent_ops scmi_optee_ops = {
300         .process_msg = scmi_optee_process_msg,
301 };
302
303 U_BOOT_DRIVER(scmi_optee) = {
304         .name           = "scmi-over-optee",
305         .id             = UCLASS_SCMI_AGENT,
306         .of_match       = scmi_optee_ids,
307         .plat_auto      = sizeof(struct scmi_optee_channel),
308         .of_to_plat     = scmi_optee_of_to_plat,
309         .probe          = scmi_optee_probe,
310         .flags          = DM_FLAG_OS_PREPARE,
311         .ops            = &scmi_optee_ops,
312 };