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