1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 /*
4 * Crypto driver for NVIDIA Security Engine in Tegra Chips
5 */
6
7 #include <linux/clk.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11
12 #include <crypto/engine.h>
13
14 #include "tegra-se.h"
15
tegra_se_cmdbuf_get(struct host1x_bo * host_bo)16 static struct host1x_bo *tegra_se_cmdbuf_get(struct host1x_bo *host_bo)
17 {
18 struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
19
20 kref_get(&cmdbuf->ref);
21
22 return host_bo;
23 }
24
tegra_se_cmdbuf_release(struct kref * ref)25 static void tegra_se_cmdbuf_release(struct kref *ref)
26 {
27 struct tegra_se_cmdbuf *cmdbuf = container_of(ref, struct tegra_se_cmdbuf, ref);
28
29 dma_free_attrs(cmdbuf->dev, cmdbuf->size, cmdbuf->addr,
30 cmdbuf->iova, 0);
31
32 kfree(cmdbuf);
33 }
34
tegra_se_cmdbuf_put(struct host1x_bo * host_bo)35 static void tegra_se_cmdbuf_put(struct host1x_bo *host_bo)
36 {
37 struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
38
39 kref_put(&cmdbuf->ref, tegra_se_cmdbuf_release);
40 }
41
42 static struct host1x_bo_mapping *
tegra_se_cmdbuf_pin(struct device * dev,struct host1x_bo * bo,enum dma_data_direction direction)43 tegra_se_cmdbuf_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction direction)
44 {
45 struct tegra_se_cmdbuf *cmdbuf = container_of(bo, struct tegra_se_cmdbuf, bo);
46 struct host1x_bo_mapping *map;
47 int err;
48
49 map = kzalloc_obj(*map);
50 if (!map)
51 return ERR_PTR(-ENOMEM);
52
53 kref_init(&map->ref);
54 map->bo = bo;
55 map->direction = direction;
56 map->dev = dev;
57
58 map->sgt = kzalloc_obj(*map->sgt);
59 if (!map->sgt) {
60 err = -ENOMEM;
61 goto free;
62 }
63
64 err = dma_get_sgtable(dev, map->sgt, cmdbuf->addr,
65 cmdbuf->iova, cmdbuf->words * 4);
66 if (err)
67 goto free_sgt;
68
69 err = dma_map_sgtable(dev, map->sgt, direction, 0);
70 if (err)
71 goto free_sgt;
72
73 map->phys = sg_dma_address(map->sgt->sgl);
74 map->size = cmdbuf->words * 4;
75 map->chunks = err;
76
77 return map;
78
79 free_sgt:
80 sg_free_table(map->sgt);
81 kfree(map->sgt);
82 free:
83 kfree(map);
84 return ERR_PTR(err);
85 }
86
tegra_se_cmdbuf_unpin(struct host1x_bo_mapping * map)87 static void tegra_se_cmdbuf_unpin(struct host1x_bo_mapping *map)
88 {
89 if (!map)
90 return;
91
92 dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0);
93 sg_free_table(map->sgt);
94 kfree(map->sgt);
95
96 kfree(map);
97 }
98
tegra_se_cmdbuf_mmap(struct host1x_bo * host_bo)99 static void *tegra_se_cmdbuf_mmap(struct host1x_bo *host_bo)
100 {
101 struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
102
103 return cmdbuf->addr;
104 }
105
tegra_se_cmdbuf_munmap(struct host1x_bo * host_bo,void * addr)106 static void tegra_se_cmdbuf_munmap(struct host1x_bo *host_bo, void *addr)
107 {
108 }
109
110 static const struct host1x_bo_ops tegra_se_cmdbuf_ops = {
111 .get = tegra_se_cmdbuf_get,
112 .put = tegra_se_cmdbuf_put,
113 .pin = tegra_se_cmdbuf_pin,
114 .unpin = tegra_se_cmdbuf_unpin,
115 .mmap = tegra_se_cmdbuf_mmap,
116 .munmap = tegra_se_cmdbuf_munmap,
117 };
118
tegra_se_host1x_bo_alloc(struct tegra_se * se,ssize_t size)119 static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssize_t size)
120 {
121 struct tegra_se_cmdbuf *cmdbuf;
122 struct device *dev = se->dev->parent;
123
124 cmdbuf = kzalloc_obj(*cmdbuf);
125 if (!cmdbuf)
126 return NULL;
127
128 cmdbuf->addr = dma_alloc_attrs(dev, size, &cmdbuf->iova,
129 GFP_KERNEL, 0);
130 if (!cmdbuf->addr)
131 return NULL;
132
133 cmdbuf->size = size;
134 cmdbuf->dev = dev;
135
136 host1x_bo_init(&cmdbuf->bo, &tegra_se_cmdbuf_ops);
137 kref_init(&cmdbuf->ref);
138
139 return cmdbuf;
140 }
141
tegra_se_host1x_submit(struct tegra_se * se,struct tegra_se_cmdbuf * cmdbuf,u32 size)142 int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
143 {
144 struct host1x_job *job;
145 int ret;
146
147 job = host1x_job_alloc(se->channel, 1, 0, true);
148 if (!job) {
149 dev_err(se->dev, "failed to allocate host1x job\n");
150 return -ENOMEM;
151 }
152
153 job->syncpt = host1x_syncpt_get(se->syncpt);
154 job->syncpt_incrs = 1;
155 job->client = &se->client;
156 job->class = se->client.class;
157 job->serialize = true;
158 job->engine_fallback_streamid = se->stream_id;
159 job->engine_streamid_offset = SE_STREAM_ID;
160
161 cmdbuf->words = size;
162
163 host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
164
165 ret = host1x_job_pin(job, se->dev);
166 if (ret) {
167 dev_err(se->dev, "failed to pin host1x job\n");
168 goto job_put;
169 }
170
171 ret = host1x_job_submit(job);
172 if (ret) {
173 dev_err(se->dev, "failed to submit host1x job\n");
174 goto job_unpin;
175 }
176
177 ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
178 MAX_SCHEDULE_TIMEOUT, NULL);
179 if (ret) {
180 dev_err(se->dev, "host1x job timed out\n");
181 goto job_put;
182 }
183
184 host1x_job_put(job);
185 return 0;
186
187 job_unpin:
188 host1x_job_unpin(job);
189 job_put:
190 host1x_job_put(job);
191
192 return ret;
193 }
194
tegra_se_client_init(struct host1x_client * client)195 static int tegra_se_client_init(struct host1x_client *client)
196 {
197 struct tegra_se *se = container_of(client, struct tegra_se, client);
198 int ret;
199
200 se->channel = host1x_channel_request(&se->client);
201 if (!se->channel) {
202 dev_err(se->dev, "host1x channel map failed\n");
203 return -ENODEV;
204 }
205
206 se->syncpt = host1x_syncpt_request(&se->client, 0);
207 if (!se->syncpt) {
208 dev_err(se->dev, "host1x syncpt allocation failed\n");
209 ret = -EINVAL;
210 goto channel_put;
211 }
212
213 se->syncpt_id = host1x_syncpt_id(se->syncpt);
214
215 se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
216 if (!se->cmdbuf) {
217 ret = -ENOMEM;
218 goto syncpt_put;
219 }
220
221 se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
222 if (!se->keybuf) {
223 ret = -ENOMEM;
224 goto cmdbuf_put;
225 }
226
227 ret = se->hw->init_alg(se);
228 if (ret) {
229 dev_err(se->dev, "failed to register algorithms\n");
230 goto keybuf_put;
231 }
232
233 return 0;
234
235 keybuf_put:
236 tegra_se_cmdbuf_put(&se->keybuf->bo);
237 cmdbuf_put:
238 tegra_se_cmdbuf_put(&se->cmdbuf->bo);
239 syncpt_put:
240 host1x_syncpt_put(se->syncpt);
241 channel_put:
242 host1x_channel_put(se->channel);
243
244 return ret;
245 }
246
tegra_se_client_deinit(struct host1x_client * client)247 static int tegra_se_client_deinit(struct host1x_client *client)
248 {
249 struct tegra_se *se = container_of(client, struct tegra_se, client);
250
251 se->hw->deinit_alg(se);
252 tegra_se_cmdbuf_put(&se->cmdbuf->bo);
253 host1x_syncpt_put(se->syncpt);
254 host1x_channel_put(se->channel);
255
256 return 0;
257 }
258
259 static const struct host1x_client_ops tegra_se_client_ops = {
260 .init = tegra_se_client_init,
261 .exit = tegra_se_client_deinit,
262 };
263
tegra_se_host1x_register(struct tegra_se * se)264 static int tegra_se_host1x_register(struct tegra_se *se)
265 {
266 INIT_LIST_HEAD(&se->client.list);
267 se->client.dev = se->dev;
268 se->client.ops = &tegra_se_client_ops;
269 se->client.class = se->hw->host1x_class;
270 se->client.num_syncpts = 1;
271
272 host1x_client_register(&se->client);
273
274 return 0;
275 }
276
tegra_se_probe(struct platform_device * pdev)277 static int tegra_se_probe(struct platform_device *pdev)
278 {
279 struct device *dev = &pdev->dev;
280 struct tegra_se *se;
281 int ret;
282
283 se = devm_kzalloc(dev, sizeof(*se), GFP_KERNEL);
284 if (!se)
285 return -ENOMEM;
286
287 se->dev = dev;
288 se->owner = TEGRA_GPSE_ID;
289 se->hw = device_get_match_data(&pdev->dev);
290
291 se->base = devm_platform_ioremap_resource(pdev, 0);
292 if (IS_ERR(se->base))
293 return PTR_ERR(se->base);
294
295 dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
296 platform_set_drvdata(pdev, se);
297
298 se->clk = devm_clk_get_enabled(se->dev, NULL);
299 if (IS_ERR(se->clk))
300 return dev_err_probe(dev, PTR_ERR(se->clk),
301 "failed to enable clocks\n");
302
303 if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
304 return dev_err_probe(dev, -ENODEV,
305 "failed to get IOMMU stream ID\n");
306
307 writel(se->stream_id, se->base + SE_STREAM_ID);
308
309 se->engine = crypto_engine_alloc_init(dev, 0);
310 if (!se->engine)
311 return -ENOMEM;
312
313 ret = crypto_engine_start(se->engine);
314 if (ret) {
315 crypto_engine_exit(se->engine);
316 return dev_err_probe(dev, ret, "failed to start crypto engine\n");
317 }
318
319 ret = tegra_se_host1x_register(se);
320 if (ret) {
321 crypto_engine_exit(se->engine);
322 return dev_err_probe(dev, ret, "failed to init host1x params\n");
323 }
324
325 return 0;
326 }
327
tegra_se_remove(struct platform_device * pdev)328 static void tegra_se_remove(struct platform_device *pdev)
329 {
330 struct tegra_se *se = platform_get_drvdata(pdev);
331
332 crypto_engine_exit(se->engine);
333 host1x_client_unregister(&se->client);
334 }
335
336 static const struct tegra_se_regs tegra234_aes1_regs = {
337 .config = SE_AES1_CFG,
338 .op = SE_AES1_OPERATION,
339 .last_blk = SE_AES1_LAST_BLOCK,
340 .linear_ctr = SE_AES1_LINEAR_CTR,
341 .aad_len = SE_AES1_AAD_LEN,
342 .cryp_msg_len = SE_AES1_CRYPTO_MSG_LEN,
343 .manifest = SE_AES1_KEYMANIFEST,
344 .key_addr = SE_AES1_KEY_ADDR,
345 .key_data = SE_AES1_KEY_DATA,
346 .key_dst = SE_AES1_KEY_DST,
347 .result = SE_AES1_CMAC_RESULT,
348 };
349
350 static const struct tegra_se_regs tegra234_hash_regs = {
351 .config = SE_SHA_CFG,
352 .op = SE_SHA_OPERATION,
353 .manifest = SE_SHA_KEYMANIFEST,
354 .key_addr = SE_SHA_KEY_ADDR,
355 .key_data = SE_SHA_KEY_DATA,
356 .key_dst = SE_SHA_KEY_DST,
357 .result = SE_SHA_HASH_RESULT,
358 };
359
360 static const struct tegra_se_hw tegra234_aes_hw = {
361 .regs = &tegra234_aes1_regs,
362 .kac_ver = 1,
363 .host1x_class = 0x3b,
364 .init_alg = tegra_init_aes,
365 .deinit_alg = tegra_deinit_aes,
366 };
367
368 static const struct tegra_se_hw tegra234_hash_hw = {
369 .regs = &tegra234_hash_regs,
370 .kac_ver = 1,
371 .host1x_class = 0x3d,
372 .init_alg = tegra_init_hash,
373 .deinit_alg = tegra_deinit_hash,
374 };
375
376 static const struct of_device_id tegra_se_of_match[] = {
377 {
378 .compatible = "nvidia,tegra234-se-aes",
379 .data = &tegra234_aes_hw
380 }, {
381 .compatible = "nvidia,tegra234-se-hash",
382 .data = &tegra234_hash_hw,
383 },
384 { },
385 };
386 MODULE_DEVICE_TABLE(of, tegra_se_of_match);
387
388 static struct platform_driver tegra_se_driver = {
389 .driver = {
390 .name = "tegra-se",
391 .of_match_table = tegra_se_of_match,
392 },
393 .probe = tegra_se_probe,
394 .remove = tegra_se_remove,
395 };
396
tegra_se_host1x_probe(struct host1x_device * dev)397 static int tegra_se_host1x_probe(struct host1x_device *dev)
398 {
399 return host1x_device_init(dev);
400 }
401
tegra_se_host1x_remove(struct host1x_device * dev)402 static void tegra_se_host1x_remove(struct host1x_device *dev)
403 {
404 host1x_device_exit(dev);
405 }
406
407 static struct host1x_driver tegra_se_host1x_driver = {
408 .driver = {
409 .name = "tegra-se-host1x",
410 },
411 .probe = tegra_se_host1x_probe,
412 .remove = tegra_se_host1x_remove,
413 .subdevs = tegra_se_of_match,
414 };
415
tegra_se_module_init(void)416 static int __init tegra_se_module_init(void)
417 {
418 int ret;
419
420 ret = host1x_driver_register(&tegra_se_host1x_driver);
421 if (ret)
422 return ret;
423
424 return platform_driver_register(&tegra_se_driver);
425 }
426
tegra_se_module_exit(void)427 static void __exit tegra_se_module_exit(void)
428 {
429 host1x_driver_unregister(&tegra_se_host1x_driver);
430 platform_driver_unregister(&tegra_se_driver);
431 }
432
433 module_init(tegra_se_module_init);
434 module_exit(tegra_se_module_exit);
435
436 MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
437 MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
438 MODULE_LICENSE("GPL");
439