xref: /linux/drivers/crypto/rockchip/rk3288_crypto.c (revision e65e90101329de0fe304e2df057f68c5f0fa4748)
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/dma-mapping.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/of.h>
17 #include <linux/clk.h>
18 #include <linux/crypto.h>
19 #include <linux/reset.h>
20 
21 static int rk_crypto_enable_clk(struct rk_crypto_info *dev)
22 {
23 	int err;
24 
25 	err = clk_bulk_prepare_enable(dev->num_clks, dev->clks);
26 	if (err)
27 		dev_err(dev->dev, "Could not enable clock clks\n");
28 
29 	return err;
30 }
31 
32 static void rk_crypto_disable_clk(struct rk_crypto_info *dev)
33 {
34 	clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
35 }
36 
37 /*
38  * Power management strategy: The device is suspended unless a TFM exists for
39  * one of the algorithms proposed by this driver.
40  */
41 static int rk_crypto_pm_suspend(struct device *dev)
42 {
43 	struct rk_crypto_info *rkdev = dev_get_drvdata(dev);
44 
45 	rk_crypto_disable_clk(rkdev);
46 	reset_control_assert(rkdev->rst);
47 
48 	return 0;
49 }
50 
51 static int rk_crypto_pm_resume(struct device *dev)
52 {
53 	struct rk_crypto_info *rkdev = dev_get_drvdata(dev);
54 	int ret;
55 
56 	ret = rk_crypto_enable_clk(rkdev);
57 	if (ret)
58 		return ret;
59 
60 	reset_control_deassert(rkdev->rst);
61 	return 0;
62 
63 }
64 
65 static const struct dev_pm_ops rk_crypto_pm_ops = {
66 	SET_RUNTIME_PM_OPS(rk_crypto_pm_suspend, rk_crypto_pm_resume, NULL)
67 };
68 
69 static int rk_crypto_pm_init(struct rk_crypto_info *rkdev)
70 {
71 	int err;
72 
73 	pm_runtime_use_autosuspend(rkdev->dev);
74 	pm_runtime_set_autosuspend_delay(rkdev->dev, 2000);
75 
76 	err = pm_runtime_set_suspended(rkdev->dev);
77 	if (err)
78 		return err;
79 	pm_runtime_enable(rkdev->dev);
80 	return err;
81 }
82 
83 static void rk_crypto_pm_exit(struct rk_crypto_info *rkdev)
84 {
85 	pm_runtime_disable(rkdev->dev);
86 }
87 
88 static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id)
89 {
90 	struct rk_crypto_info *dev  = platform_get_drvdata(dev_id);
91 	u32 interrupt_status;
92 
93 	interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS);
94 	CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status);
95 
96 	dev->status = 1;
97 	if (interrupt_status & 0x0a) {
98 		dev_warn(dev->dev, "DMA Error\n");
99 		dev->status = 0;
100 	}
101 	complete(&dev->complete);
102 
103 	return IRQ_HANDLED;
104 }
105 
106 static struct rk_crypto_tmp *rk_cipher_algs[] = {
107 	&rk_ecb_aes_alg,
108 	&rk_cbc_aes_alg,
109 	&rk_ecb_des_alg,
110 	&rk_cbc_des_alg,
111 	&rk_ecb_des3_ede_alg,
112 	&rk_cbc_des3_ede_alg,
113 	&rk_ahash_sha1,
114 	&rk_ahash_sha256,
115 	&rk_ahash_md5,
116 };
117 
118 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
119 static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
120 {
121 	unsigned int i;
122 
123 	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
124 		if (!rk_cipher_algs[i]->dev)
125 			continue;
126 		switch (rk_cipher_algs[i]->type) {
127 		case CRYPTO_ALG_TYPE_SKCIPHER:
128 			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
129 				   rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name,
130 				   rk_cipher_algs[i]->alg.skcipher.base.cra_name,
131 				   rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb);
132 			seq_printf(seq, "\tfallback due to length: %lu\n",
133 				   rk_cipher_algs[i]->stat_fb_len);
134 			seq_printf(seq, "\tfallback due to alignment: %lu\n",
135 				   rk_cipher_algs[i]->stat_fb_align);
136 			seq_printf(seq, "\tfallback due to SGs: %lu\n",
137 				   rk_cipher_algs[i]->stat_fb_sgdiff);
138 			break;
139 		case CRYPTO_ALG_TYPE_AHASH:
140 			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
141 				   rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name,
142 				   rk_cipher_algs[i]->alg.hash.halg.base.cra_name,
143 				   rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb);
144 			break;
145 		}
146 	}
147 	return 0;
148 }
149 
150 DEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs);
151 #endif
152 
153 static int rk_crypto_register(struct rk_crypto_info *crypto_info)
154 {
155 	unsigned int i, k;
156 	int err = 0;
157 
158 	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
159 		rk_cipher_algs[i]->dev = crypto_info;
160 		switch (rk_cipher_algs[i]->type) {
161 		case CRYPTO_ALG_TYPE_SKCIPHER:
162 			dev_info(crypto_info->dev, "Register %s as %s\n",
163 				 rk_cipher_algs[i]->alg.skcipher.base.cra_name,
164 				 rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name);
165 			err = crypto_register_skcipher(&rk_cipher_algs[i]->alg.skcipher);
166 			break;
167 		case CRYPTO_ALG_TYPE_AHASH:
168 			dev_info(crypto_info->dev, "Register %s as %s\n",
169 				 rk_cipher_algs[i]->alg.hash.halg.base.cra_name,
170 				 rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name);
171 			err = crypto_register_ahash(&rk_cipher_algs[i]->alg.hash);
172 			break;
173 		default:
174 			dev_err(crypto_info->dev, "unknown algorithm\n");
175 		}
176 		if (err)
177 			goto err_cipher_algs;
178 	}
179 	return 0;
180 
181 err_cipher_algs:
182 	for (k = 0; k < i; k++) {
183 		if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER)
184 			crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
185 		else
186 			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
187 	}
188 	return err;
189 }
190 
191 static void rk_crypto_unregister(void)
192 {
193 	unsigned int i;
194 
195 	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
196 		if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER)
197 			crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
198 		else
199 			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
200 	}
201 }
202 
203 static const struct of_device_id crypto_of_id_table[] = {
204 	{ .compatible = "rockchip,rk3288-crypto" },
205 	{ .compatible = "rockchip,rk3328-crypto" },
206 	{}
207 };
208 MODULE_DEVICE_TABLE(of, crypto_of_id_table);
209 
210 static int rk_crypto_probe(struct platform_device *pdev)
211 {
212 	struct device *dev = &pdev->dev;
213 	struct rk_crypto_info *crypto_info;
214 	int err = 0;
215 
216 	crypto_info = devm_kzalloc(&pdev->dev,
217 				   sizeof(*crypto_info), GFP_KERNEL);
218 	if (!crypto_info) {
219 		err = -ENOMEM;
220 		goto err_crypto;
221 	}
222 
223 	crypto_info->rst = devm_reset_control_get(dev, "crypto-rst");
224 	if (IS_ERR(crypto_info->rst)) {
225 		err = PTR_ERR(crypto_info->rst);
226 		goto err_crypto;
227 	}
228 
229 	reset_control_assert(crypto_info->rst);
230 	usleep_range(10, 20);
231 	reset_control_deassert(crypto_info->rst);
232 
233 	crypto_info->reg = devm_platform_ioremap_resource(pdev, 0);
234 	if (IS_ERR(crypto_info->reg)) {
235 		err = PTR_ERR(crypto_info->reg);
236 		goto err_crypto;
237 	}
238 
239 	crypto_info->num_clks = devm_clk_bulk_get_all(&pdev->dev,
240 						      &crypto_info->clks);
241 	if (crypto_info->num_clks < 3) {
242 		err = -EINVAL;
243 		goto err_crypto;
244 	}
245 
246 	crypto_info->irq = platform_get_irq(pdev, 0);
247 	if (crypto_info->irq < 0) {
248 		dev_err(&pdev->dev, "control Interrupt is not available.\n");
249 		err = crypto_info->irq;
250 		goto err_crypto;
251 	}
252 
253 	err = devm_request_irq(&pdev->dev, crypto_info->irq,
254 			       rk_crypto_irq_handle, IRQF_SHARED,
255 			       "rk-crypto", pdev);
256 
257 	if (err) {
258 		dev_err(&pdev->dev, "irq request failed.\n");
259 		goto err_crypto;
260 	}
261 
262 	crypto_info->dev = &pdev->dev;
263 	platform_set_drvdata(pdev, crypto_info);
264 
265 	crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true);
266 	crypto_engine_start(crypto_info->engine);
267 	init_completion(&crypto_info->complete);
268 
269 	err = rk_crypto_pm_init(crypto_info);
270 	if (err)
271 		goto err_pm;
272 
273 	err = rk_crypto_register(crypto_info);
274 	if (err) {
275 		dev_err(dev, "err in register alg");
276 		goto err_register_alg;
277 	}
278 
279 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
280 	/* Ignore error of debugfs */
281 	crypto_info->dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL);
282 	crypto_info->dbgfs_stats = debugfs_create_file("stats", 0444,
283 						       crypto_info->dbgfs_dir,
284 						       crypto_info,
285 						       &rk_crypto_debugfs_fops);
286 #endif
287 
288 	dev_info(dev, "Crypto Accelerator successfully registered\n");
289 	return 0;
290 
291 err_register_alg:
292 	rk_crypto_pm_exit(crypto_info);
293 err_pm:
294 	crypto_engine_exit(crypto_info->engine);
295 err_crypto:
296 	dev_err(dev, "Crypto Accelerator not successfully registered\n");
297 	return err;
298 }
299 
300 static int rk_crypto_remove(struct platform_device *pdev)
301 {
302 	struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev);
303 
304 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
305 	debugfs_remove_recursive(crypto_tmp->dbgfs_dir);
306 #endif
307 	rk_crypto_unregister();
308 	rk_crypto_pm_exit(crypto_tmp);
309 	crypto_engine_exit(crypto_tmp->engine);
310 	return 0;
311 }
312 
313 static struct platform_driver crypto_driver = {
314 	.probe		= rk_crypto_probe,
315 	.remove		= rk_crypto_remove,
316 	.driver		= {
317 		.name	= "rk3288-crypto",
318 		.pm		= &rk_crypto_pm_ops,
319 		.of_match_table	= crypto_of_id_table,
320 	},
321 };
322 
323 module_platform_driver(crypto_driver);
324 
325 MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>");
326 MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine");
327 MODULE_LICENSE("GPL");
328