xref: /linux/drivers/crypto/ti/dthev2-common.c (revision a50eba1e778ad4da5b6f9ddbbf57dabbea59bc05)
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 
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 
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 
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 
130 static int dthe_register_algs(void)
131 {
132 	return dthe_register_aes_algs();
133 }
134 
135 static void dthe_unregister_algs(void)
136 {
137 	dthe_unregister_aes_algs();
138 }
139 
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 
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