1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * K3 DTHE V2 crypto accelerator driver
4 *
5 * Copyright (C) Texas Instruments 2025 - https://www.ti.com
6 * Author: T Pratham <t-pratham@ti.com>
7 */
8
9 #include <crypto/aes.h>
10 #include <crypto/algapi.h>
11 #include <crypto/engine.h>
12 #include <crypto/internal/aead.h>
13 #include <crypto/internal/skcipher.h>
14
15 #include "dthev2-common.h"
16
17 #include <linux/delay.h>
18 #include <linux/dmaengine.h>
19 #include <linux/dmapool.h>
20 #include <linux/dma-mapping.h>
21 #include <linux/io.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/scatterlist.h>
26
27 #define DRIVER_NAME "dthev2"
28
29 static struct dthe_list dthe_dev_list = {
30 .dev_list = LIST_HEAD_INIT(dthe_dev_list.dev_list),
31 .lock = __SPIN_LOCK_UNLOCKED(dthe_dev_list.lock),
32 };
33
dthe_get_dev(struct dthe_tfm_ctx * ctx)34 struct dthe_data *dthe_get_dev(struct dthe_tfm_ctx *ctx)
35 {
36 struct dthe_data *dev_data;
37
38 if (ctx->dev_data)
39 return ctx->dev_data;
40
41 spin_lock_bh(&dthe_dev_list.lock);
42 dev_data = list_first_entry(&dthe_dev_list.dev_list, struct dthe_data, list);
43 if (dev_data)
44 list_move_tail(&dev_data->list, &dthe_dev_list.dev_list);
45 spin_unlock_bh(&dthe_dev_list.lock);
46
47 return dev_data;
48 }
49
dthe_copy_sg(struct scatterlist * dst,struct scatterlist * src,int buflen)50 struct scatterlist *dthe_copy_sg(struct scatterlist *dst,
51 struct scatterlist *src,
52 int buflen)
53 {
54 struct scatterlist *from_sg, *to_sg;
55 int sglen;
56
57 for (to_sg = dst, from_sg = src; buflen && from_sg; buflen -= sglen) {
58 sglen = from_sg->length;
59 if (sglen > buflen)
60 sglen = buflen;
61 sg_set_buf(to_sg, sg_virt(from_sg), sglen);
62 from_sg = sg_next(from_sg);
63 to_sg = sg_next(to_sg);
64 }
65
66 return to_sg;
67 }
68
dthe_dma_init(struct dthe_data * dev_data)69 static int dthe_dma_init(struct dthe_data *dev_data)
70 {
71 int ret;
72 struct dma_slave_config cfg;
73
74 dev_data->dma_aes_rx = NULL;
75 dev_data->dma_aes_tx = NULL;
76 dev_data->dma_sha_tx = NULL;
77
78 dev_data->dma_aes_rx = dma_request_chan(dev_data->dev, "rx");
79 if (IS_ERR(dev_data->dma_aes_rx)) {
80 return dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_aes_rx),
81 "Unable to request rx DMA channel\n");
82 }
83
84 dev_data->dma_aes_tx = dma_request_chan(dev_data->dev, "tx1");
85 if (IS_ERR(dev_data->dma_aes_tx)) {
86 ret = dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_aes_tx),
87 "Unable to request tx1 DMA channel\n");
88 goto err_dma_aes_tx;
89 }
90
91 dev_data->dma_sha_tx = dma_request_chan(dev_data->dev, "tx2");
92 if (IS_ERR(dev_data->dma_sha_tx)) {
93 ret = dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_sha_tx),
94 "Unable to request tx2 DMA channel\n");
95 goto err_dma_sha_tx;
96 }
97
98 memzero_explicit(&cfg, sizeof(cfg));
99
100 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
101 cfg.src_maxburst = 4;
102
103 ret = dmaengine_slave_config(dev_data->dma_aes_rx, &cfg);
104 if (ret) {
105 dev_err(dev_data->dev, "Can't configure IN dmaengine slave: %d\n", ret);
106 goto err_dma_config;
107 }
108
109 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
110 cfg.dst_maxburst = 4;
111
112 ret = dmaengine_slave_config(dev_data->dma_aes_tx, &cfg);
113 if (ret) {
114 dev_err(dev_data->dev, "Can't configure OUT dmaengine slave: %d\n", ret);
115 goto err_dma_config;
116 }
117
118 return 0;
119
120 err_dma_config:
121 dma_release_channel(dev_data->dma_sha_tx);
122 err_dma_sha_tx:
123 dma_release_channel(dev_data->dma_aes_tx);
124 err_dma_aes_tx:
125 dma_release_channel(dev_data->dma_aes_rx);
126
127 return ret;
128 }
129
dthe_register_algs(void)130 static int dthe_register_algs(void)
131 {
132 return dthe_register_aes_algs();
133 }
134
dthe_unregister_algs(void)135 static void dthe_unregister_algs(void)
136 {
137 dthe_unregister_aes_algs();
138 }
139
dthe_probe(struct platform_device * pdev)140 static int dthe_probe(struct platform_device *pdev)
141 {
142 struct device *dev = &pdev->dev;
143 struct dthe_data *dev_data;
144 int ret;
145
146 dev_data = devm_kzalloc(dev, sizeof(*dev_data), GFP_KERNEL);
147 if (!dev_data)
148 return -ENOMEM;
149
150 dev_data->dev = dev;
151 dev_data->regs = devm_platform_ioremap_resource(pdev, 0);
152 if (IS_ERR(dev_data->regs))
153 return PTR_ERR(dev_data->regs);
154
155 platform_set_drvdata(pdev, dev_data);
156
157 spin_lock(&dthe_dev_list.lock);
158 list_add(&dev_data->list, &dthe_dev_list.dev_list);
159 spin_unlock(&dthe_dev_list.lock);
160
161 ret = dthe_dma_init(dev_data);
162 if (ret)
163 goto probe_dma_err;
164
165 dev_data->engine = crypto_engine_alloc_init(dev, 1);
166 if (!dev_data->engine) {
167 ret = -ENOMEM;
168 goto probe_engine_err;
169 }
170
171 ret = crypto_engine_start(dev_data->engine);
172 if (ret) {
173 dev_err(dev, "Failed to start crypto engine\n");
174 goto probe_engine_start_err;
175 }
176
177 ret = dthe_register_algs();
178 if (ret) {
179 dev_err(dev, "Failed to register algs\n");
180 goto probe_engine_start_err;
181 }
182
183 return 0;
184
185 probe_engine_start_err:
186 crypto_engine_exit(dev_data->engine);
187 probe_engine_err:
188 dma_release_channel(dev_data->dma_aes_rx);
189 dma_release_channel(dev_data->dma_aes_tx);
190 dma_release_channel(dev_data->dma_sha_tx);
191 probe_dma_err:
192 spin_lock(&dthe_dev_list.lock);
193 list_del(&dev_data->list);
194 spin_unlock(&dthe_dev_list.lock);
195
196 return ret;
197 }
198
dthe_remove(struct platform_device * pdev)199 static void dthe_remove(struct platform_device *pdev)
200 {
201 struct dthe_data *dev_data = platform_get_drvdata(pdev);
202
203 spin_lock(&dthe_dev_list.lock);
204 list_del(&dev_data->list);
205 spin_unlock(&dthe_dev_list.lock);
206
207 dthe_unregister_algs();
208
209 crypto_engine_exit(dev_data->engine);
210
211 dma_release_channel(dev_data->dma_aes_rx);
212 dma_release_channel(dev_data->dma_aes_tx);
213 dma_release_channel(dev_data->dma_sha_tx);
214 }
215
216 static const struct of_device_id dthe_of_match[] = {
217 { .compatible = "ti,am62l-dthev2", },
218 {},
219 };
220 MODULE_DEVICE_TABLE(of, dthe_of_match);
221
222 static struct platform_driver dthe_driver = {
223 .probe = dthe_probe,
224 .remove = dthe_remove,
225 .driver = {
226 .name = DRIVER_NAME,
227 .of_match_table = dthe_of_match,
228 },
229 };
230
231 module_platform_driver(dthe_driver);
232
233 MODULE_AUTHOR("T Pratham <t-pratham@ti.com>");
234 MODULE_DESCRIPTION("Texas Instruments DTHE V2 driver");
235 MODULE_LICENSE("GPL");
236