1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cryptographic API.
4  *
5  * Support for StarFive hardware cryptographic engine.
6  * Copyright (c) 2022 StarFive Technology
7  *
8  */
9 
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/interrupt.h>
13 #include <linux/iopoll.h>
14 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/reset.h>
19 
20 #include "jh7110-cryp.h"
21 
22 #define DRIVER_NAME             "jh7110-crypto"
23 
24 struct starfive_dev_list {
25 	struct list_head        dev_list;
26 	spinlock_t              lock; /* protect dev_list */
27 };
28 
29 static struct starfive_dev_list dev_list = {
30 	.dev_list = LIST_HEAD_INIT(dev_list.dev_list),
31 	.lock     = __SPIN_LOCK_UNLOCKED(dev_list.lock),
32 };
33 
34 struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx)
35 {
36 	struct starfive_cryp_dev *cryp = NULL, *tmp;
37 
38 	spin_lock_bh(&dev_list.lock);
39 	if (!ctx->cryp) {
40 		list_for_each_entry(tmp, &dev_list.dev_list, list) {
41 			cryp = tmp;
42 			break;
43 		}
44 		ctx->cryp = cryp;
45 	} else {
46 		cryp = ctx->cryp;
47 	}
48 
49 	spin_unlock_bh(&dev_list.lock);
50 
51 	return cryp;
52 }
53 
54 static int starfive_dma_init(struct starfive_cryp_dev *cryp)
55 {
56 	dma_cap_mask_t mask;
57 
58 	dma_cap_zero(mask);
59 	dma_cap_set(DMA_SLAVE, mask);
60 
61 	cryp->tx = dma_request_chan(cryp->dev, "tx");
62 	if (IS_ERR(cryp->tx))
63 		return dev_err_probe(cryp->dev, PTR_ERR(cryp->tx),
64 				     "Error requesting tx dma channel.\n");
65 
66 	cryp->rx = dma_request_chan(cryp->dev, "rx");
67 	if (IS_ERR(cryp->rx)) {
68 		dma_release_channel(cryp->tx);
69 		return dev_err_probe(cryp->dev, PTR_ERR(cryp->rx),
70 				     "Error requesting rx dma channel.\n");
71 	}
72 
73 	return 0;
74 }
75 
76 static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp)
77 {
78 	dma_release_channel(cryp->tx);
79 	dma_release_channel(cryp->rx);
80 }
81 
82 static irqreturn_t starfive_cryp_irq(int irq, void *priv)
83 {
84 	u32 status;
85 	struct starfive_cryp_dev *cryp = (struct starfive_cryp_dev *)priv;
86 
87 	status = readl(cryp->base + STARFIVE_IE_FLAG_OFFSET);
88 	if (status & STARFIVE_IE_FLAG_HASH_DONE) {
89 		status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
90 		status |= STARFIVE_IE_MASK_HASH_DONE;
91 		writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET);
92 		tasklet_schedule(&cryp->hash_done);
93 	}
94 
95 	if (status & STARFIVE_IE_FLAG_PKA_DONE) {
96 		status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
97 		status |= STARFIVE_IE_MASK_PKA_DONE;
98 		writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET);
99 		complete(&cryp->pka_done);
100 	}
101 
102 	return IRQ_HANDLED;
103 }
104 
105 static int starfive_cryp_probe(struct platform_device *pdev)
106 {
107 	struct starfive_cryp_dev *cryp;
108 	struct resource *res;
109 	int irq;
110 	int ret;
111 
112 	cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL);
113 	if (!cryp)
114 		return -ENOMEM;
115 
116 	platform_set_drvdata(pdev, cryp);
117 	cryp->dev = &pdev->dev;
118 
119 	cryp->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
120 	if (IS_ERR(cryp->base))
121 		return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base),
122 				     "Error remapping memory for platform device\n");
123 
124 	tasklet_init(&cryp->hash_done, starfive_hash_done_task, (unsigned long)cryp);
125 
126 	cryp->phys_base = res->start;
127 	cryp->dma_maxburst = 32;
128 
129 	cryp->hclk = devm_clk_get(&pdev->dev, "hclk");
130 	if (IS_ERR(cryp->hclk))
131 		return dev_err_probe(&pdev->dev, PTR_ERR(cryp->hclk),
132 				     "Error getting hardware reference clock\n");
133 
134 	cryp->ahb = devm_clk_get(&pdev->dev, "ahb");
135 	if (IS_ERR(cryp->ahb))
136 		return dev_err_probe(&pdev->dev, PTR_ERR(cryp->ahb),
137 				     "Error getting ahb reference clock\n");
138 
139 	cryp->rst = devm_reset_control_get_shared(cryp->dev, NULL);
140 	if (IS_ERR(cryp->rst))
141 		return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst),
142 				     "Error getting hardware reset line\n");
143 
144 	init_completion(&cryp->pka_done);
145 
146 	irq = platform_get_irq(pdev, 0);
147 	if (irq < 0)
148 		return irq;
149 
150 	ret = devm_request_irq(&pdev->dev, irq, starfive_cryp_irq, 0, pdev->name,
151 			       (void *)cryp);
152 	if (ret)
153 		return dev_err_probe(&pdev->dev, irq,
154 				     "Failed to register interrupt handler\n");
155 
156 	clk_prepare_enable(cryp->hclk);
157 	clk_prepare_enable(cryp->ahb);
158 	reset_control_deassert(cryp->rst);
159 
160 	spin_lock(&dev_list.lock);
161 	list_add(&cryp->list, &dev_list.dev_list);
162 	spin_unlock(&dev_list.lock);
163 
164 	ret = starfive_dma_init(cryp);
165 	if (ret) {
166 		if (ret == -EPROBE_DEFER)
167 			goto err_probe_defer;
168 		else
169 			goto err_dma_init;
170 	}
171 
172 	/* Initialize crypto engine */
173 	cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1);
174 	if (!cryp->engine) {
175 		ret = -ENOMEM;
176 		goto err_engine;
177 	}
178 
179 	ret = crypto_engine_start(cryp->engine);
180 	if (ret)
181 		goto err_engine_start;
182 
183 	ret = starfive_hash_register_algs();
184 	if (ret)
185 		goto err_algs_hash;
186 
187 	ret = starfive_rsa_register_algs();
188 	if (ret)
189 		goto err_algs_rsa;
190 
191 	return 0;
192 
193 err_algs_rsa:
194 	starfive_hash_unregister_algs();
195 err_algs_hash:
196 	crypto_engine_stop(cryp->engine);
197 err_engine_start:
198 	crypto_engine_exit(cryp->engine);
199 err_engine:
200 	starfive_dma_cleanup(cryp);
201 err_dma_init:
202 	spin_lock(&dev_list.lock);
203 	list_del(&cryp->list);
204 	spin_unlock(&dev_list.lock);
205 
206 	clk_disable_unprepare(cryp->hclk);
207 	clk_disable_unprepare(cryp->ahb);
208 	reset_control_assert(cryp->rst);
209 
210 	tasklet_kill(&cryp->hash_done);
211 err_probe_defer:
212 	return ret;
213 }
214 
215 static int starfive_cryp_remove(struct platform_device *pdev)
216 {
217 	struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev);
218 
219 	starfive_hash_unregister_algs();
220 	starfive_rsa_unregister_algs();
221 
222 	tasklet_kill(&cryp->hash_done);
223 
224 	crypto_engine_stop(cryp->engine);
225 	crypto_engine_exit(cryp->engine);
226 
227 	starfive_dma_cleanup(cryp);
228 
229 	spin_lock(&dev_list.lock);
230 	list_del(&cryp->list);
231 	spin_unlock(&dev_list.lock);
232 
233 	clk_disable_unprepare(cryp->hclk);
234 	clk_disable_unprepare(cryp->ahb);
235 	reset_control_assert(cryp->rst);
236 
237 	return 0;
238 }
239 
240 static const struct of_device_id starfive_dt_ids[] __maybe_unused = {
241 	{ .compatible = "starfive,jh7110-crypto", .data = NULL},
242 	{},
243 };
244 MODULE_DEVICE_TABLE(of, starfive_dt_ids);
245 
246 static struct platform_driver starfive_cryp_driver = {
247 	.probe  = starfive_cryp_probe,
248 	.remove = starfive_cryp_remove,
249 	.driver = {
250 		.name           = DRIVER_NAME,
251 		.of_match_table = starfive_dt_ids,
252 	},
253 };
254 
255 module_platform_driver(starfive_cryp_driver);
256 
257 MODULE_LICENSE("GPL");
258 MODULE_DESCRIPTION("StarFive JH7110 Cryptographic Module");
259