1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Crypto acceleration support for Rockchip RK3288
4  *
5  * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
6  *
7  * Author: Zain Wang <zain.wang@rock-chips.com>
8  *
9  * Some ideas are from marvell-cesa.c and s5p-sss.c driver.
10  */
11 
12 #include "rk3288_crypto.h"
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/of.h>
16 #include <linux/clk.h>
17 #include <linux/crypto.h>
18 #include <linux/reset.h>
19 
20 static int rk_crypto_enable_clk(struct rk_crypto_info *dev)
21 {
22 	int err;
23 
24 	err = clk_prepare_enable(dev->sclk);
25 	if (err) {
26 		dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n",
27 			__func__, __LINE__);
28 		goto err_return;
29 	}
30 	err = clk_prepare_enable(dev->aclk);
31 	if (err) {
32 		dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n",
33 			__func__, __LINE__);
34 		goto err_aclk;
35 	}
36 	err = clk_prepare_enable(dev->hclk);
37 	if (err) {
38 		dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n",
39 			__func__, __LINE__);
40 		goto err_hclk;
41 	}
42 	err = clk_prepare_enable(dev->dmaclk);
43 	if (err) {
44 		dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n",
45 			__func__, __LINE__);
46 		goto err_dmaclk;
47 	}
48 	return err;
49 err_dmaclk:
50 	clk_disable_unprepare(dev->hclk);
51 err_hclk:
52 	clk_disable_unprepare(dev->aclk);
53 err_aclk:
54 	clk_disable_unprepare(dev->sclk);
55 err_return:
56 	return err;
57 }
58 
59 static void rk_crypto_disable_clk(struct rk_crypto_info *dev)
60 {
61 	clk_disable_unprepare(dev->dmaclk);
62 	clk_disable_unprepare(dev->hclk);
63 	clk_disable_unprepare(dev->aclk);
64 	clk_disable_unprepare(dev->sclk);
65 }
66 
67 static int check_alignment(struct scatterlist *sg_src,
68 			   struct scatterlist *sg_dst,
69 			   int align_mask)
70 {
71 	int in, out, align;
72 
73 	in = IS_ALIGNED((uint32_t)sg_src->offset, 4) &&
74 	     IS_ALIGNED((uint32_t)sg_src->length, align_mask);
75 	if (!sg_dst)
76 		return in;
77 	out = IS_ALIGNED((uint32_t)sg_dst->offset, 4) &&
78 	      IS_ALIGNED((uint32_t)sg_dst->length, align_mask);
79 	align = in && out;
80 
81 	return (align && (sg_src->length == sg_dst->length));
82 }
83 
84 static int rk_load_data(struct rk_crypto_info *dev,
85 			struct scatterlist *sg_src,
86 			struct scatterlist *sg_dst)
87 {
88 	unsigned int count;
89 
90 	dev->aligned = dev->aligned ?
91 		check_alignment(sg_src, sg_dst, dev->align_size) :
92 		dev->aligned;
93 	if (dev->aligned) {
94 		count = min(dev->left_bytes, sg_src->length);
95 		dev->left_bytes -= count;
96 
97 		if (!dma_map_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE)) {
98 			dev_err(dev->dev, "[%s:%d] dma_map_sg(src)  error\n",
99 				__func__, __LINE__);
100 			return -EINVAL;
101 		}
102 		dev->addr_in = sg_dma_address(sg_src);
103 
104 		if (sg_dst) {
105 			if (!dma_map_sg(dev->dev, sg_dst, 1, DMA_FROM_DEVICE)) {
106 				dev_err(dev->dev,
107 					"[%s:%d] dma_map_sg(dst)  error\n",
108 					__func__, __LINE__);
109 				dma_unmap_sg(dev->dev, sg_src, 1,
110 					     DMA_TO_DEVICE);
111 				return -EINVAL;
112 			}
113 			dev->addr_out = sg_dma_address(sg_dst);
114 		}
115 	} else {
116 		count = (dev->left_bytes > PAGE_SIZE) ?
117 			PAGE_SIZE : dev->left_bytes;
118 
119 		if (!sg_pcopy_to_buffer(dev->first, dev->src_nents,
120 					dev->addr_vir, count,
121 					dev->total - dev->left_bytes)) {
122 			dev_err(dev->dev, "[%s:%d] pcopy err\n",
123 				__func__, __LINE__);
124 			return -EINVAL;
125 		}
126 		dev->left_bytes -= count;
127 		sg_init_one(&dev->sg_tmp, dev->addr_vir, count);
128 		if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, DMA_TO_DEVICE)) {
129 			dev_err(dev->dev, "[%s:%d] dma_map_sg(sg_tmp)  error\n",
130 				__func__, __LINE__);
131 			return -ENOMEM;
132 		}
133 		dev->addr_in = sg_dma_address(&dev->sg_tmp);
134 
135 		if (sg_dst) {
136 			if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1,
137 					DMA_FROM_DEVICE)) {
138 				dev_err(dev->dev,
139 					"[%s:%d] dma_map_sg(sg_tmp)  error\n",
140 					__func__, __LINE__);
141 				dma_unmap_sg(dev->dev, &dev->sg_tmp, 1,
142 					     DMA_TO_DEVICE);
143 				return -ENOMEM;
144 			}
145 			dev->addr_out = sg_dma_address(&dev->sg_tmp);
146 		}
147 	}
148 	dev->count = count;
149 	return 0;
150 }
151 
152 static void rk_unload_data(struct rk_crypto_info *dev)
153 {
154 	struct scatterlist *sg_in, *sg_out;
155 
156 	sg_in = dev->aligned ? dev->sg_src : &dev->sg_tmp;
157 	dma_unmap_sg(dev->dev, sg_in, 1, DMA_TO_DEVICE);
158 
159 	if (dev->sg_dst) {
160 		sg_out = dev->aligned ? dev->sg_dst : &dev->sg_tmp;
161 		dma_unmap_sg(dev->dev, sg_out, 1, DMA_FROM_DEVICE);
162 	}
163 }
164 
165 static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id)
166 {
167 	struct rk_crypto_info *dev  = platform_get_drvdata(dev_id);
168 	u32 interrupt_status;
169 
170 	spin_lock(&dev->lock);
171 	interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS);
172 	CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status);
173 
174 	if (interrupt_status & 0x0a) {
175 		dev_warn(dev->dev, "DMA Error\n");
176 		dev->err = -EFAULT;
177 	}
178 	tasklet_schedule(&dev->done_task);
179 
180 	spin_unlock(&dev->lock);
181 	return IRQ_HANDLED;
182 }
183 
184 static int rk_crypto_enqueue(struct rk_crypto_info *dev,
185 			      struct crypto_async_request *async_req)
186 {
187 	unsigned long flags;
188 	int ret;
189 
190 	spin_lock_irqsave(&dev->lock, flags);
191 	ret = crypto_enqueue_request(&dev->queue, async_req);
192 	if (dev->busy) {
193 		spin_unlock_irqrestore(&dev->lock, flags);
194 		return ret;
195 	}
196 	dev->busy = true;
197 	spin_unlock_irqrestore(&dev->lock, flags);
198 	tasklet_schedule(&dev->queue_task);
199 
200 	return ret;
201 }
202 
203 static void rk_crypto_queue_task_cb(unsigned long data)
204 {
205 	struct rk_crypto_info *dev = (struct rk_crypto_info *)data;
206 	struct crypto_async_request *async_req, *backlog;
207 	unsigned long flags;
208 	int err = 0;
209 
210 	dev->err = 0;
211 	spin_lock_irqsave(&dev->lock, flags);
212 	backlog   = crypto_get_backlog(&dev->queue);
213 	async_req = crypto_dequeue_request(&dev->queue);
214 
215 	if (!async_req) {
216 		dev->busy = false;
217 		spin_unlock_irqrestore(&dev->lock, flags);
218 		return;
219 	}
220 	spin_unlock_irqrestore(&dev->lock, flags);
221 
222 	if (backlog) {
223 		backlog->complete(backlog, -EINPROGRESS);
224 		backlog = NULL;
225 	}
226 
227 	dev->async_req = async_req;
228 	err = dev->start(dev);
229 	if (err)
230 		dev->complete(dev->async_req, err);
231 }
232 
233 static void rk_crypto_done_task_cb(unsigned long data)
234 {
235 	struct rk_crypto_info *dev = (struct rk_crypto_info *)data;
236 
237 	if (dev->err) {
238 		dev->complete(dev->async_req, dev->err);
239 		return;
240 	}
241 
242 	dev->err = dev->update(dev);
243 	if (dev->err)
244 		dev->complete(dev->async_req, dev->err);
245 }
246 
247 static struct rk_crypto_tmp *rk_cipher_algs[] = {
248 	&rk_ecb_aes_alg,
249 	&rk_cbc_aes_alg,
250 	&rk_ecb_des_alg,
251 	&rk_cbc_des_alg,
252 	&rk_ecb_des3_ede_alg,
253 	&rk_cbc_des3_ede_alg,
254 	&rk_ahash_sha1,
255 	&rk_ahash_sha256,
256 	&rk_ahash_md5,
257 };
258 
259 static int rk_crypto_register(struct rk_crypto_info *crypto_info)
260 {
261 	unsigned int i, k;
262 	int err = 0;
263 
264 	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
265 		rk_cipher_algs[i]->dev = crypto_info;
266 		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
267 			err = crypto_register_skcipher(
268 					&rk_cipher_algs[i]->alg.skcipher);
269 		else
270 			err = crypto_register_ahash(
271 					&rk_cipher_algs[i]->alg.hash);
272 		if (err)
273 			goto err_cipher_algs;
274 	}
275 	return 0;
276 
277 err_cipher_algs:
278 	for (k = 0; k < i; k++) {
279 		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
280 			crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
281 		else
282 			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
283 	}
284 	return err;
285 }
286 
287 static void rk_crypto_unregister(void)
288 {
289 	unsigned int i;
290 
291 	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
292 		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
293 			crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
294 		else
295 			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
296 	}
297 }
298 
299 static void rk_crypto_action(void *data)
300 {
301 	struct rk_crypto_info *crypto_info = data;
302 
303 	reset_control_assert(crypto_info->rst);
304 }
305 
306 static const struct of_device_id crypto_of_id_table[] = {
307 	{ .compatible = "rockchip,rk3288-crypto" },
308 	{}
309 };
310 MODULE_DEVICE_TABLE(of, crypto_of_id_table);
311 
312 static int rk_crypto_probe(struct platform_device *pdev)
313 {
314 	struct device *dev = &pdev->dev;
315 	struct rk_crypto_info *crypto_info;
316 	int err = 0;
317 
318 	crypto_info = devm_kzalloc(&pdev->dev,
319 				   sizeof(*crypto_info), GFP_KERNEL);
320 	if (!crypto_info) {
321 		err = -ENOMEM;
322 		goto err_crypto;
323 	}
324 
325 	crypto_info->rst = devm_reset_control_get(dev, "crypto-rst");
326 	if (IS_ERR(crypto_info->rst)) {
327 		err = PTR_ERR(crypto_info->rst);
328 		goto err_crypto;
329 	}
330 
331 	reset_control_assert(crypto_info->rst);
332 	usleep_range(10, 20);
333 	reset_control_deassert(crypto_info->rst);
334 
335 	err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info);
336 	if (err)
337 		goto err_crypto;
338 
339 	spin_lock_init(&crypto_info->lock);
340 
341 	crypto_info->reg = devm_platform_ioremap_resource(pdev, 0);
342 	if (IS_ERR(crypto_info->reg)) {
343 		err = PTR_ERR(crypto_info->reg);
344 		goto err_crypto;
345 	}
346 
347 	crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk");
348 	if (IS_ERR(crypto_info->aclk)) {
349 		err = PTR_ERR(crypto_info->aclk);
350 		goto err_crypto;
351 	}
352 
353 	crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk");
354 	if (IS_ERR(crypto_info->hclk)) {
355 		err = PTR_ERR(crypto_info->hclk);
356 		goto err_crypto;
357 	}
358 
359 	crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk");
360 	if (IS_ERR(crypto_info->sclk)) {
361 		err = PTR_ERR(crypto_info->sclk);
362 		goto err_crypto;
363 	}
364 
365 	crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk");
366 	if (IS_ERR(crypto_info->dmaclk)) {
367 		err = PTR_ERR(crypto_info->dmaclk);
368 		goto err_crypto;
369 	}
370 
371 	crypto_info->irq = platform_get_irq(pdev, 0);
372 	if (crypto_info->irq < 0) {
373 		dev_warn(crypto_info->dev,
374 			 "control Interrupt is not available.\n");
375 		err = crypto_info->irq;
376 		goto err_crypto;
377 	}
378 
379 	err = devm_request_irq(&pdev->dev, crypto_info->irq,
380 			       rk_crypto_irq_handle, IRQF_SHARED,
381 			       "rk-crypto", pdev);
382 
383 	if (err) {
384 		dev_err(crypto_info->dev, "irq request failed.\n");
385 		goto err_crypto;
386 	}
387 
388 	crypto_info->dev = &pdev->dev;
389 	platform_set_drvdata(pdev, crypto_info);
390 
391 	tasklet_init(&crypto_info->queue_task,
392 		     rk_crypto_queue_task_cb, (unsigned long)crypto_info);
393 	tasklet_init(&crypto_info->done_task,
394 		     rk_crypto_done_task_cb, (unsigned long)crypto_info);
395 	crypto_init_queue(&crypto_info->queue, 50);
396 
397 	crypto_info->enable_clk = rk_crypto_enable_clk;
398 	crypto_info->disable_clk = rk_crypto_disable_clk;
399 	crypto_info->load_data = rk_load_data;
400 	crypto_info->unload_data = rk_unload_data;
401 	crypto_info->enqueue = rk_crypto_enqueue;
402 	crypto_info->busy = false;
403 
404 	err = rk_crypto_register(crypto_info);
405 	if (err) {
406 		dev_err(dev, "err in register alg");
407 		goto err_register_alg;
408 	}
409 
410 	dev_info(dev, "Crypto Accelerator successfully registered\n");
411 	return 0;
412 
413 err_register_alg:
414 	tasklet_kill(&crypto_info->queue_task);
415 	tasklet_kill(&crypto_info->done_task);
416 err_crypto:
417 	return err;
418 }
419 
420 static int rk_crypto_remove(struct platform_device *pdev)
421 {
422 	struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev);
423 
424 	rk_crypto_unregister();
425 	tasklet_kill(&crypto_tmp->done_task);
426 	tasklet_kill(&crypto_tmp->queue_task);
427 	return 0;
428 }
429 
430 static struct platform_driver crypto_driver = {
431 	.probe		= rk_crypto_probe,
432 	.remove		= rk_crypto_remove,
433 	.driver		= {
434 		.name	= "rk3288-crypto",
435 		.of_match_table	= crypto_of_id_table,
436 	},
437 };
438 
439 module_platform_driver(crypto_driver);
440 
441 MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>");
442 MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine");
443 MODULE_LICENSE("GPL");
444