xref: /OK3568_Linux_fs/kernel/drivers/nvmem/rockchip-secure-otp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Rockchip Secure OTP Driver
4  *
5  * Copyright (c) 2023 Rockchip Electronics Co. Ltd.
6  * Author: Hisping <hisping.lin@rock-chips.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/io.h>
13 #include <linux/iopoll.h>
14 #include <linux/module.h>
15 #include <linux/nvmem-provider.h>
16 #include <linux/reset.h>
17 #include <linux/rockchip/cpu.h>
18 #include <linux/slab.h>
19 #include <linux/of.h>
20 #include <linux/of_platform.h>
21 #include <linux/platform_device.h>
22 #include <linux/tee_drv.h>
23 #include <linux/uuid.h>
24 
25 static DEFINE_MUTEX(nvmem_mutex);
26 
27 struct rockchip_data;
28 
29 struct rockchip_otp {
30 	struct device *dev;
31 	struct nvmem_config *config;
32 	const struct rockchip_data *data;
33 };
34 
35 struct rockchip_data {
36 	int size;
37 	int (*reg_read)(unsigned int offset, void *val, size_t bytes);
38 	int (*reg_write)(unsigned int offset, void *val, size_t bytes);
39 	int (*init)(struct rockchip_otp *otp);
40 };
41 
optee_ctx_match(struct tee_ioctl_version_data * ver,const void * data)42 static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
43 {
44 	if (ver->impl_id == TEE_IMPL_ID_OPTEE)
45 		return 1;
46 	else
47 		return 0;
48 }
49 
50 /*
51  * func: read data from non-protected oem zone in secure otp
52  */
53 #define STORAGE_CMD_READ_OEM_NS_OTP		13
rockchip_read_oem_non_protected_otp(unsigned int byte_off,void * byte_buf,size_t byte_len)54 int rockchip_read_oem_non_protected_otp(unsigned int byte_off,
55 				void *byte_buf, size_t byte_len)
56 {
57 	const uuid_t pta_uuid =
58 		UUID_INIT(0x2d26d8a8, 0x5134, 0x4dd8,
59 			  0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71);
60 	struct tee_ioctl_open_session_arg sess_arg;
61 	struct tee_shm *device_shm = NULL;
62 	struct tee_context *ctx = NULL;
63 	u32 shm_size = 0;
64 	int rc;
65 	struct tee_ioctl_invoke_arg inv_arg;
66 	struct tee_param param[4];
67 	u8 *read_data = NULL;
68 
69 	if (!byte_buf) {
70 		pr_err("buf is null\n");
71 		return -EINVAL;
72 	}
73 
74 	memset(&sess_arg, 0, sizeof(sess_arg));
75 
76 	mutex_lock(&nvmem_mutex);
77 
78 	/* Open context with OP-TEE driver */
79 	ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
80 	if (IS_ERR(ctx)) {
81 		pr_err("tee_client_open_context failed\n");
82 		rc = -ENODEV;
83 		goto out_exit;
84 	}
85 
86 	/* Open session */
87 	memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
88 	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
89 	sess_arg.num_params = 0;
90 
91 	rc = tee_client_open_session(ctx, &sess_arg, NULL);
92 	if ((rc < 0) || (sess_arg.ret != 0)) {
93 		pr_err("tee_client_open_session failed, err: %x\n",
94 			sess_arg.ret);
95 		rc = -EINVAL;
96 		goto out_ctx;
97 	}
98 
99 	/* Alloc share memory */
100 	shm_size = byte_len;
101 	device_shm = tee_shm_alloc(ctx, shm_size,
102 				   TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
103 	if (IS_ERR(device_shm)) {
104 		pr_err("tee_shm_alloc failed\n");
105 		rc = PTR_ERR(device_shm);
106 		goto out_sess;
107 	}
108 
109 	/* Invoke func */
110 	memset(&inv_arg, 0, sizeof(inv_arg));
111 	memset(&param, 0, sizeof(param));
112 
113 	inv_arg.func = STORAGE_CMD_READ_OEM_NS_OTP;
114 	inv_arg.session =  sess_arg.session;
115 	inv_arg.num_params = 4;
116 
117 	/* Fill invoke cmd params */
118 	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
119 	param[0].u.value.a = byte_off;
120 
121 	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
122 	param[1].u.memref.shm = device_shm;
123 	param[1].u.memref.size = shm_size;
124 	param[1].u.memref.shm_offs = 0;
125 
126 	rc = tee_client_invoke_func(ctx, &inv_arg, param);
127 	if ((rc < 0) || (inv_arg.ret != 0)) {
128 		pr_err("invoke function err: %x\n", inv_arg.ret);
129 		rc = -EINVAL;
130 		goto out_shm;
131 	}
132 
133 	read_data = tee_shm_get_va(device_shm, 0);
134 	if (IS_ERR(read_data)) {
135 		pr_err("tee_shm_get_va failed\n");
136 		rc = -EINVAL;
137 		goto out_shm;
138 	}
139 	memcpy(byte_buf, read_data, byte_len);
140 
141 out_shm:
142 	tee_shm_free(device_shm);
143 out_sess:
144 	tee_client_close_session(ctx, sess_arg.session);
145 out_ctx:
146 	tee_client_close_context(ctx);
147 out_exit:
148 	mutex_unlock(&nvmem_mutex);
149 	return rc;
150 }
151 EXPORT_SYMBOL_GPL(rockchip_read_oem_non_protected_otp);
152 
153 /*
154  * func: write data to non-protected oem zone in secure otp
155  */
156 #define STORAGE_CMD_WRITE_OEM_NS_OTP		12
rockchip_write_oem_non_protected_otp(unsigned int byte_off,void * byte_buf,size_t byte_len)157 int rockchip_write_oem_non_protected_otp(unsigned int byte_off,
158 				void *byte_buf, size_t byte_len)
159 {
160 	const uuid_t pta_uuid =
161 		UUID_INIT(0x2d26d8a8, 0x5134, 0x4dd8,
162 			  0xb3, 0x2f, 0xb3, 0x4b, 0xce, 0xeb, 0xc4, 0x71);
163 	struct tee_ioctl_open_session_arg sess_arg;
164 	struct tee_shm *device_shm = NULL;
165 	struct tee_context *ctx = NULL;
166 	u32 shm_size = 0;
167 	int rc;
168 	struct tee_ioctl_invoke_arg inv_arg;
169 	struct tee_param param[4];
170 	u8 *write_data = NULL;
171 
172 	if (!byte_buf) {
173 		pr_err("buf is null\n");
174 		return -EINVAL;
175 	}
176 
177 	memset(&sess_arg, 0, sizeof(sess_arg));
178 
179 	mutex_lock(&nvmem_mutex);
180 
181 	/* Open context with OP-TEE driver */
182 	ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
183 	if (IS_ERR(ctx)) {
184 		pr_err("tee_client_open_context failed\n");
185 		rc = -ENODEV;
186 		goto out_exit;
187 	}
188 
189 	/* Open session */
190 	memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
191 	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
192 	sess_arg.num_params = 0;
193 
194 	rc = tee_client_open_session(ctx, &sess_arg, NULL);
195 	if ((rc < 0) || (sess_arg.ret != 0)) {
196 		pr_err("tee_client_open_session failed, err: %x\n",
197 			sess_arg.ret);
198 		rc = -EINVAL;
199 		goto out_ctx;
200 	}
201 
202 	/* Alloc share memory */
203 	shm_size = byte_len;
204 	device_shm = tee_shm_alloc(ctx, shm_size,
205 				   TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
206 	if (IS_ERR(device_shm)) {
207 		pr_err("tee_shm_alloc failed\n");
208 		rc = PTR_ERR(device_shm);
209 		goto out_sess;
210 	}
211 
212 	write_data = tee_shm_get_va(device_shm, 0);
213 	if (IS_ERR(write_data)) {
214 		pr_err("tee_shm_get_va failed\n");
215 		rc = -EINVAL;
216 		goto out_shm;
217 	}
218 	memcpy(write_data, byte_buf, byte_len);
219 
220 	/* Invoke func */
221 	memset(&inv_arg, 0, sizeof(inv_arg));
222 	memset(&param, 0, sizeof(param));
223 
224 	inv_arg.func = STORAGE_CMD_WRITE_OEM_NS_OTP;
225 	inv_arg.session =  sess_arg.session;
226 	inv_arg.num_params = 4;
227 
228 	/* Fill invoke cmd params */
229 	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
230 	param[0].u.value.a = byte_off;
231 
232 	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
233 	param[1].u.memref.shm = device_shm;
234 	param[1].u.memref.size = shm_size;
235 	param[1].u.memref.shm_offs = 0;
236 
237 	rc = tee_client_invoke_func(ctx, &inv_arg, param);
238 	if ((rc < 0) || (inv_arg.ret != 0)) {
239 		pr_err("invoke function err: %x\n", inv_arg.ret);
240 		rc = -EINVAL;
241 		goto out_shm;
242 	}
243 
244 out_shm:
245 	tee_shm_free(device_shm);
246 out_sess:
247 	tee_client_close_session(ctx, sess_arg.session);
248 out_ctx:
249 	tee_client_close_context(ctx);
250 out_exit:
251 	mutex_unlock(&nvmem_mutex);
252 	return rc;
253 }
254 EXPORT_SYMBOL_GPL(rockchip_write_oem_non_protected_otp);
255 
rockchip_secure_otp_read(void * context,unsigned int offset,void * val,size_t bytes)256 static int rockchip_secure_otp_read(void *context, unsigned int offset,
257 				void *val, size_t bytes)
258 {
259 	struct rockchip_otp *otp = context;
260 	int ret = -EINVAL;
261 
262 	if (otp->data && otp->data->reg_read)
263 		ret = otp->data->reg_read(offset, val, bytes);
264 
265 	return ret;
266 }
267 
rockchip_secure_otp_write(void * context,unsigned int offset,void * val,size_t bytes)268 static int rockchip_secure_otp_write(void *context, unsigned int offset,
269 				void *val, size_t bytes)
270 {
271 	struct rockchip_otp *otp = context;
272 	int ret = -EINVAL;
273 
274 	if (otp->data && otp->data->reg_write)
275 		ret = otp->data->reg_write(offset, val, bytes);
276 
277 	return ret;
278 }
279 
280 static struct nvmem_config otp_config = {
281 	.name = "rockchip-secure-otp",
282 	.owner = THIS_MODULE,
283 	.read_only = false,
284 	.reg_read = rockchip_secure_otp_read,
285 	.reg_write = rockchip_secure_otp_write,
286 	.stride = 4,
287 	.word_size = 4,
288 };
289 
290 static const struct rockchip_data secure_otp_data = {
291 	.reg_read = rockchip_read_oem_non_protected_otp,
292 	.reg_write = rockchip_write_oem_non_protected_otp,
293 };
294 
295 static const struct of_device_id rockchip_secure_otp_match[] = {
296 	{
297 		.compatible = "rockchip,secure-otp",
298 		.data = (void *)&secure_otp_data,
299 	},
300 	{ /* sentinel */ },
301 };
302 MODULE_DEVICE_TABLE(of, rockchip_secure_otp_match);
303 
rockchip_secure_otp_probe(struct platform_device * pdev)304 static int rockchip_secure_otp_probe(struct platform_device *pdev)
305 {
306 	struct device *dev = &pdev->dev;
307 	struct rockchip_otp *otp;
308 	const struct rockchip_data *data;
309 	struct nvmem_device *nvmem;
310 	u32 otp_size;
311 	int ret;
312 
313 	data = device_get_match_data(dev);
314 	if (!data) {
315 		dev_err(dev, "failed to get match data\n");
316 		return -EINVAL;
317 	}
318 
319 	ret = device_property_read_u32(dev, "rockchip,otp-size", &otp_size);
320 	if (ret) {
321 		dev_err(dev, "otp size parameter not specified\n");
322 		return -EINVAL;
323 	} else if (otp_size == 0) {
324 		dev_err(dev, "otp size must be > 0\n");
325 		return -EINVAL;
326 	}
327 
328 	otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
329 			   GFP_KERNEL);
330 	if (!otp)
331 		return -ENOMEM;
332 
333 	otp->data = data;
334 	otp->dev = dev;
335 
336 	otp->config = &otp_config;
337 	otp->config->size = otp_size;
338 	otp->config->priv = otp;
339 	otp->config->dev = dev;
340 
341 	if (data->init) {
342 		ret = data->init(otp);
343 		if (ret)
344 			return ret;
345 	}
346 
347 	nvmem = devm_nvmem_register(dev, otp->config);
348 
349 	return PTR_ERR_OR_ZERO(nvmem);
350 }
351 
352 static struct platform_driver rockchip_secure_otp_driver = {
353 	.probe = rockchip_secure_otp_probe,
354 	.driver = {
355 		.name = "rockchip-secure-otp",
356 		.of_match_table = rockchip_secure_otp_match,
357 	},
358 };
359 
rockchip_secure_otp_init(void)360 static int __init rockchip_secure_otp_init(void)
361 {
362 	int ret;
363 
364 	ret = platform_driver_register(&rockchip_secure_otp_driver);
365 	if (ret) {
366 		pr_err("failed to register secure otp driver\n");
367 		return ret;
368 	}
369 
370 	return 0;
371 }
372 
rockchip_secure_otp_exit(void)373 static void __exit rockchip_secure_otp_exit(void)
374 {
375 	return platform_driver_unregister(&rockchip_secure_otp_driver);
376 }
377 
378 subsys_initcall(rockchip_secure_otp_init);
379 module_exit(rockchip_secure_otp_exit);
380 
381 MODULE_DESCRIPTION("Rockchip Secure OTP Driver");
382 MODULE_LICENSE("GPL");
383