Merge tag 'regulator-fix-v6.6-merge-window' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / drivers / nvmem / stm32-bsec-optee-ta.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver
4  *
5  * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
6  */
7
8 #include <linux/tee_drv.h>
9
10 #include "stm32-bsec-optee-ta.h"
11
12 /*
13  * Read OTP memory
14  *
15  * [in]         value[0].a              OTP start offset in byte
16  * [in]         value[0].b              Access type (0:shadow, 1:fuse, 2:lock)
17  * [out]        memref[1].buffer        Output buffer to store read values
18  * [out]        memref[1].size          Size of OTP to be read
19  *
20  * Return codes:
21  * TEE_SUCCESS - Invoke command success
22  * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
23  * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
24  */
25 #define PTA_BSEC_READ_MEM               0x0
26
27 /*
28  * Write OTP memory
29  *
30  * [in]         value[0].a              OTP start offset in byte
31  * [in]         value[0].b              Access type (0:shadow, 1:fuse, 2:lock)
32  * [in]         memref[1].buffer        Input buffer to read values
33  * [in]         memref[1].size          Size of OTP to be written
34  *
35  * Return codes:
36  * TEE_SUCCESS - Invoke command success
37  * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
38  * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
39  */
40 #define PTA_BSEC_WRITE_MEM              0x1
41
42 /* value of PTA_BSEC access type = value[in] b */
43 #define SHADOW_ACCESS   0
44 #define FUSE_ACCESS     1
45 #define LOCK_ACCESS     2
46
47 /* Bitfield definition for LOCK status */
48 #define LOCK_PERM                       BIT(30)
49
50 /* OP-TEE STM32MP BSEC TA UUID */
51 static const uuid_t stm32mp_bsec_ta_uuid =
52         UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
53                   0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03);
54
55 /*
56  * Check whether this driver supports the BSEC TA in the TEE instance
57  * represented by the params (ver/data) to this function.
58  */
59 static int stm32_bsec_optee_ta_match(struct tee_ioctl_version_data *ver,
60                                      const void *data)
61 {
62         /* Currently this driver only supports GP compliant, OP-TEE based TA */
63         if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
64                 (ver->gen_caps & TEE_GEN_CAP_GP))
65                 return 1;
66         else
67                 return 0;
68 }
69
70 /* Open a session to OP-TEE for STM32MP BSEC TA */
71 static int stm32_bsec_ta_open_session(struct tee_context *ctx, u32 *id)
72 {
73         struct tee_ioctl_open_session_arg sess_arg;
74         int rc;
75
76         memset(&sess_arg, 0, sizeof(sess_arg));
77         export_uuid(sess_arg.uuid, &stm32mp_bsec_ta_uuid);
78         sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
79         sess_arg.num_params = 0;
80
81         rc = tee_client_open_session(ctx, &sess_arg, NULL);
82         if ((rc < 0) || (sess_arg.ret != 0)) {
83                 pr_err("%s: tee_client_open_session failed err:%#x, ret:%#x\n",
84                        __func__, sess_arg.ret, rc);
85                 if (!rc)
86                         rc = -EINVAL;
87         } else {
88                 *id = sess_arg.session;
89         }
90
91         return rc;
92 }
93
94 /* close a session to OP-TEE for STM32MP BSEC TA */
95 static void stm32_bsec_ta_close_session(void *ctx, u32 id)
96 {
97         tee_client_close_session(ctx, id);
98 }
99
100 /* stm32_bsec_optee_ta_open() - initialize the STM32MP BSEC TA */
101 int stm32_bsec_optee_ta_open(struct tee_context **ctx)
102 {
103         struct tee_context *tee_ctx;
104         u32 session_id;
105         int rc;
106
107         /* Open context with TEE driver */
108         tee_ctx = tee_client_open_context(NULL, stm32_bsec_optee_ta_match, NULL, NULL);
109         if (IS_ERR(tee_ctx)) {
110                 rc = PTR_ERR(tee_ctx);
111                 if (rc == -ENOENT)
112                         return -EPROBE_DEFER;
113                 pr_err("%s: tee_client_open_context failed (%d)\n", __func__, rc);
114
115                 return rc;
116         }
117
118         /* Check STM32MP BSEC TA presence */
119         rc = stm32_bsec_ta_open_session(tee_ctx, &session_id);
120         if (rc) {
121                 tee_client_close_context(tee_ctx);
122                 return rc;
123         }
124
125         stm32_bsec_ta_close_session(tee_ctx, session_id);
126
127         *ctx = tee_ctx;
128
129         return 0;
130 }
131
132 /* stm32_bsec_optee_ta_open() - release the PTA STM32MP BSEC TA */
133 void stm32_bsec_optee_ta_close(void *ctx)
134 {
135         tee_client_close_context(ctx);
136 }
137
138 /* stm32_bsec_optee_ta_read() - nvmem read access using PTA client driver */
139 int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
140                              void *buf, size_t bytes)
141 {
142         struct tee_shm *shm;
143         struct tee_ioctl_invoke_arg arg;
144         struct tee_param param[2];
145         u8 *shm_buf;
146         u32 start, num_bytes;
147         int ret;
148         u32 session_id;
149
150         ret = stm32_bsec_ta_open_session(ctx, &session_id);
151         if (ret)
152                 return ret;
153
154         memset(&arg, 0, sizeof(arg));
155         memset(&param, 0, sizeof(param));
156
157         arg.func = PTA_BSEC_READ_MEM;
158         arg.session = session_id;
159         arg.num_params = 2;
160
161         /* align access on 32bits */
162         start = ALIGN_DOWN(offset, 4);
163         num_bytes = round_up(offset + bytes - start, 4);
164         param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
165         param[0].u.value.a = start;
166         param[0].u.value.b = SHADOW_ACCESS;
167
168         shm = tee_shm_alloc_kernel_buf(ctx, num_bytes);
169         if (IS_ERR(shm)) {
170                 ret = PTR_ERR(shm);
171                 goto out_tee_session;
172         }
173
174         param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
175         param[1].u.memref.shm = shm;
176         param[1].u.memref.size = num_bytes;
177
178         ret = tee_client_invoke_func(ctx, &arg, param);
179         if (ret < 0 || arg.ret != 0) {
180                 pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n",
181                         arg.ret, ret);
182                 if (!ret)
183                         ret = -EIO;
184         }
185         if (!ret) {
186                 shm_buf = tee_shm_get_va(shm, 0);
187                 if (IS_ERR(shm_buf)) {
188                         ret = PTR_ERR(shm_buf);
189                         pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
190                 } else {
191                         /* read data from 32 bits aligned buffer */
192                         memcpy(buf, &shm_buf[offset % 4], bytes);
193                 }
194         }
195
196         tee_shm_free(shm);
197
198 out_tee_session:
199         stm32_bsec_ta_close_session(ctx, session_id);
200
201         return ret;
202 }
203
204 /* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */
205 int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
206                               unsigned int offset, void *buf, size_t bytes)
207 {       struct tee_shm *shm;
208         struct tee_ioctl_invoke_arg arg;
209         struct tee_param param[2];
210         u8 *shm_buf;
211         int ret;
212         u32 session_id;
213
214         ret = stm32_bsec_ta_open_session(ctx, &session_id);
215         if (ret)
216                 return ret;
217
218         /* Allow only writing complete 32-bits aligned words */
219         if ((bytes % 4) || (offset % 4))
220                 return -EINVAL;
221
222         memset(&arg, 0, sizeof(arg));
223         memset(&param, 0, sizeof(param));
224
225         arg.func = PTA_BSEC_WRITE_MEM;
226         arg.session = session_id;
227         arg.num_params = 2;
228
229         param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
230         param[0].u.value.a = offset;
231         param[0].u.value.b = FUSE_ACCESS;
232
233         shm = tee_shm_alloc_kernel_buf(ctx, bytes);
234         if (IS_ERR(shm)) {
235                 ret = PTR_ERR(shm);
236                 goto out_tee_session;
237         }
238
239         param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
240         param[1].u.memref.shm = shm;
241         param[1].u.memref.size = bytes;
242
243         shm_buf = tee_shm_get_va(shm, 0);
244         if (IS_ERR(shm_buf)) {
245                 ret = PTR_ERR(shm_buf);
246                 pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
247                 tee_shm_free(shm);
248
249                 goto out_tee_session;
250         }
251
252         memcpy(shm_buf, buf, bytes);
253
254         ret = tee_client_invoke_func(ctx, &arg, param);
255         if (ret < 0 || arg.ret != 0) {
256                 pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
257                 if (!ret)
258                         ret = -EIO;
259         }
260         pr_debug("Write OTPs %d to %zu, ret=%d\n", offset / 4, (offset + bytes) / 4, ret);
261
262         /* Lock the upper OTPs with ECC protection, word programming only */
263         if (!ret && ((offset + bytes) >= (lower * 4))) {
264                 u32 start, nb_lock;
265                 u32 *lock = (u32 *)shm_buf;
266                 int i;
267
268                 /*
269                  * don't lock the lower OTPs, no ECC protection and incremental
270                  * bit programming, a second write is allowed
271                  */
272                 start = max_t(u32, offset, lower * 4);
273                 nb_lock = (offset + bytes - start) / 4;
274
275                 param[0].u.value.a = start;
276                 param[0].u.value.b = LOCK_ACCESS;
277                 param[1].u.memref.size = nb_lock * 4;
278
279                 for (i = 0; i < nb_lock; i++)
280                         lock[i] = LOCK_PERM;
281
282                 ret = tee_client_invoke_func(ctx, &arg, param);
283                 if (ret < 0 || arg.ret != 0) {
284                         pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
285                         if (!ret)
286                                 ret = -EIO;
287                 }
288                 pr_debug("Lock upper OTPs %d to %d, ret=%d\n",
289                          start / 4, start / 4 + nb_lock, ret);
290         }
291
292         tee_shm_free(shm);
293
294 out_tee_session:
295         stm32_bsec_ta_close_session(ctx, session_id);
296
297         return ret;
298 }