1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * sun4i-ss-core.c - hardware cryptographic accelerator for Allwinner A20 SoC
4  *
5  * Copyright (C) 2013-2015 Corentin LABBE <clabbe.montjoie@gmail.com>
6  *
7  * Core file which registers crypto algorithms supported by the SS.
8  *
9  * You could find a link for the datasheet in Documentation/arm/sunxi.rst
10  */
11 #include <linux/clk.h>
12 #include <linux/crypto.h>
13 #include <linux/io.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <crypto/scatterwalk.h>
18 #include <linux/scatterlist.h>
19 #include <linux/interrupt.h>
20 #include <linux/delay.h>
21 #include <linux/reset.h>
22 
23 #include "sun4i-ss.h"
24 
25 static struct sun4i_ss_alg_template ss_algs[] = {
26 {       .type = CRYPTO_ALG_TYPE_AHASH,
27 	.mode = SS_OP_MD5,
28 	.alg.hash = {
29 		.init = sun4i_hash_init,
30 		.update = sun4i_hash_update,
31 		.final = sun4i_hash_final,
32 		.finup = sun4i_hash_finup,
33 		.digest = sun4i_hash_digest,
34 		.export = sun4i_hash_export_md5,
35 		.import = sun4i_hash_import_md5,
36 		.halg = {
37 			.digestsize = MD5_DIGEST_SIZE,
38 			.statesize = sizeof(struct md5_state),
39 			.base = {
40 				.cra_name = "md5",
41 				.cra_driver_name = "md5-sun4i-ss",
42 				.cra_priority = 300,
43 				.cra_alignmask = 3,
44 				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
45 				.cra_ctxsize = sizeof(struct sun4i_req_ctx),
46 				.cra_module = THIS_MODULE,
47 				.cra_init = sun4i_hash_crainit,
48 				.cra_exit = sun4i_hash_craexit,
49 			}
50 		}
51 	}
52 },
53 {       .type = CRYPTO_ALG_TYPE_AHASH,
54 	.mode = SS_OP_SHA1,
55 	.alg.hash = {
56 		.init = sun4i_hash_init,
57 		.update = sun4i_hash_update,
58 		.final = sun4i_hash_final,
59 		.finup = sun4i_hash_finup,
60 		.digest = sun4i_hash_digest,
61 		.export = sun4i_hash_export_sha1,
62 		.import = sun4i_hash_import_sha1,
63 		.halg = {
64 			.digestsize = SHA1_DIGEST_SIZE,
65 			.statesize = sizeof(struct sha1_state),
66 			.base = {
67 				.cra_name = "sha1",
68 				.cra_driver_name = "sha1-sun4i-ss",
69 				.cra_priority = 300,
70 				.cra_alignmask = 3,
71 				.cra_blocksize = SHA1_BLOCK_SIZE,
72 				.cra_ctxsize = sizeof(struct sun4i_req_ctx),
73 				.cra_module = THIS_MODULE,
74 				.cra_init = sun4i_hash_crainit,
75 				.cra_exit = sun4i_hash_craexit,
76 			}
77 		}
78 	}
79 },
80 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
81 	.alg.crypto = {
82 		.setkey         = sun4i_ss_aes_setkey,
83 		.encrypt        = sun4i_ss_cbc_aes_encrypt,
84 		.decrypt        = sun4i_ss_cbc_aes_decrypt,
85 		.min_keysize	= AES_MIN_KEY_SIZE,
86 		.max_keysize	= AES_MAX_KEY_SIZE,
87 		.ivsize		= AES_BLOCK_SIZE,
88 		.base = {
89 			.cra_name = "cbc(aes)",
90 			.cra_driver_name = "cbc-aes-sun4i-ss",
91 			.cra_priority = 300,
92 			.cra_blocksize = AES_BLOCK_SIZE,
93 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
94 			.cra_ctxsize = sizeof(struct sun4i_tfm_ctx),
95 			.cra_module = THIS_MODULE,
96 			.cra_alignmask = 3,
97 			.cra_init = sun4i_ss_cipher_init,
98 			.cra_exit = sun4i_ss_cipher_exit,
99 		}
100 	}
101 },
102 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
103 	.alg.crypto = {
104 		.setkey         = sun4i_ss_aes_setkey,
105 		.encrypt        = sun4i_ss_ecb_aes_encrypt,
106 		.decrypt        = sun4i_ss_ecb_aes_decrypt,
107 		.min_keysize	= AES_MIN_KEY_SIZE,
108 		.max_keysize	= AES_MAX_KEY_SIZE,
109 		.base = {
110 			.cra_name = "ecb(aes)",
111 			.cra_driver_name = "ecb-aes-sun4i-ss",
112 			.cra_priority = 300,
113 			.cra_blocksize = AES_BLOCK_SIZE,
114 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
115 			.cra_ctxsize = sizeof(struct sun4i_tfm_ctx),
116 			.cra_module = THIS_MODULE,
117 			.cra_alignmask = 3,
118 			.cra_init = sun4i_ss_cipher_init,
119 			.cra_exit = sun4i_ss_cipher_exit,
120 		}
121 	}
122 },
123 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
124 	.alg.crypto = {
125 		.setkey         = sun4i_ss_des_setkey,
126 		.encrypt        = sun4i_ss_cbc_des_encrypt,
127 		.decrypt        = sun4i_ss_cbc_des_decrypt,
128 		.min_keysize    = DES_KEY_SIZE,
129 		.max_keysize    = DES_KEY_SIZE,
130 		.ivsize         = DES_BLOCK_SIZE,
131 		.base = {
132 			.cra_name = "cbc(des)",
133 			.cra_driver_name = "cbc-des-sun4i-ss",
134 			.cra_priority = 300,
135 			.cra_blocksize = DES_BLOCK_SIZE,
136 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
137 			.cra_ctxsize = sizeof(struct sun4i_req_ctx),
138 			.cra_module = THIS_MODULE,
139 			.cra_alignmask = 3,
140 			.cra_init = sun4i_ss_cipher_init,
141 			.cra_exit = sun4i_ss_cipher_exit,
142 		}
143 	}
144 },
145 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
146 	.alg.crypto = {
147 		.setkey         = sun4i_ss_des_setkey,
148 		.encrypt        = sun4i_ss_ecb_des_encrypt,
149 		.decrypt        = sun4i_ss_ecb_des_decrypt,
150 		.min_keysize    = DES_KEY_SIZE,
151 		.max_keysize    = DES_KEY_SIZE,
152 		.base = {
153 			.cra_name = "ecb(des)",
154 			.cra_driver_name = "ecb-des-sun4i-ss",
155 			.cra_priority = 300,
156 			.cra_blocksize = DES_BLOCK_SIZE,
157 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
158 			.cra_ctxsize = sizeof(struct sun4i_req_ctx),
159 			.cra_module = THIS_MODULE,
160 			.cra_alignmask = 3,
161 			.cra_init = sun4i_ss_cipher_init,
162 			.cra_exit = sun4i_ss_cipher_exit,
163 		}
164 	}
165 },
166 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
167 	.alg.crypto = {
168 		.setkey         = sun4i_ss_des3_setkey,
169 		.encrypt        = sun4i_ss_cbc_des3_encrypt,
170 		.decrypt        = sun4i_ss_cbc_des3_decrypt,
171 		.min_keysize    = DES3_EDE_KEY_SIZE,
172 		.max_keysize    = DES3_EDE_KEY_SIZE,
173 		.ivsize         = DES3_EDE_BLOCK_SIZE,
174 		.base = {
175 			.cra_name = "cbc(des3_ede)",
176 			.cra_driver_name = "cbc-des3-sun4i-ss",
177 			.cra_priority = 300,
178 			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
179 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
180 			.cra_ctxsize = sizeof(struct sun4i_req_ctx),
181 			.cra_module = THIS_MODULE,
182 			.cra_alignmask = 3,
183 			.cra_init = sun4i_ss_cipher_init,
184 			.cra_exit = sun4i_ss_cipher_exit,
185 		}
186 	}
187 },
188 {       .type = CRYPTO_ALG_TYPE_SKCIPHER,
189 	.alg.crypto = {
190 		.setkey         = sun4i_ss_des3_setkey,
191 		.encrypt        = sun4i_ss_ecb_des3_encrypt,
192 		.decrypt        = sun4i_ss_ecb_des3_decrypt,
193 		.min_keysize    = DES3_EDE_KEY_SIZE,
194 		.max_keysize    = DES3_EDE_KEY_SIZE,
195 		.base = {
196 			.cra_name = "ecb(des3_ede)",
197 			.cra_driver_name = "ecb-des3-sun4i-ss",
198 			.cra_priority = 300,
199 			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
200 			.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,
201 			.cra_ctxsize = sizeof(struct sun4i_req_ctx),
202 			.cra_module = THIS_MODULE,
203 			.cra_alignmask = 3,
204 			.cra_init = sun4i_ss_cipher_init,
205 			.cra_exit = sun4i_ss_cipher_exit,
206 		}
207 	}
208 },
209 #ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
210 {
211 	.type = CRYPTO_ALG_TYPE_RNG,
212 	.alg.rng = {
213 		.base = {
214 			.cra_name		= "stdrng",
215 			.cra_driver_name	= "sun4i_ss_rng",
216 			.cra_priority		= 300,
217 			.cra_ctxsize		= 0,
218 			.cra_module		= THIS_MODULE,
219 		},
220 		.generate               = sun4i_ss_prng_generate,
221 		.seed                   = sun4i_ss_prng_seed,
222 		.seedsize               = SS_SEED_LEN / BITS_PER_BYTE,
223 	}
224 },
225 #endif
226 };
227 
228 /*
229  * Power management strategy: The device is suspended unless a TFM exists for
230  * one of the algorithms proposed by this driver.
231  */
232 static int sun4i_ss_pm_suspend(struct device *dev)
233 {
234 	struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);
235 
236 	if (ss->reset)
237 		reset_control_assert(ss->reset);
238 
239 	clk_disable_unprepare(ss->ssclk);
240 	clk_disable_unprepare(ss->busclk);
241 	return 0;
242 }
243 
244 static int sun4i_ss_pm_resume(struct device *dev)
245 {
246 	struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);
247 
248 	int err;
249 
250 	err = clk_prepare_enable(ss->busclk);
251 	if (err) {
252 		dev_err(ss->dev, "Cannot prepare_enable busclk\n");
253 		goto err_enable;
254 	}
255 
256 	err = clk_prepare_enable(ss->ssclk);
257 	if (err) {
258 		dev_err(ss->dev, "Cannot prepare_enable ssclk\n");
259 		goto err_enable;
260 	}
261 
262 	if (ss->reset) {
263 		err = reset_control_deassert(ss->reset);
264 		if (err) {
265 			dev_err(ss->dev, "Cannot deassert reset control\n");
266 			goto err_enable;
267 		}
268 	}
269 
270 	return err;
271 err_enable:
272 	sun4i_ss_pm_suspend(dev);
273 	return err;
274 }
275 
276 const struct dev_pm_ops sun4i_ss_pm_ops = {
277 	SET_RUNTIME_PM_OPS(sun4i_ss_pm_suspend, sun4i_ss_pm_resume, NULL)
278 };
279 
280 /*
281  * When power management is enabled, this function enables the PM and set the
282  * device as suspended
283  * When power management is disabled, this function just enables the device
284  */
285 static int sun4i_ss_pm_init(struct sun4i_ss_ctx *ss)
286 {
287 	int err;
288 
289 	pm_runtime_use_autosuspend(ss->dev);
290 	pm_runtime_set_autosuspend_delay(ss->dev, 2000);
291 
292 	err = pm_runtime_set_suspended(ss->dev);
293 	if (err)
294 		return err;
295 	pm_runtime_enable(ss->dev);
296 	return err;
297 }
298 
299 static void sun4i_ss_pm_exit(struct sun4i_ss_ctx *ss)
300 {
301 	pm_runtime_disable(ss->dev);
302 }
303 
304 static int sun4i_ss_probe(struct platform_device *pdev)
305 {
306 	u32 v;
307 	int err, i;
308 	unsigned long cr;
309 	const unsigned long cr_ahb = 24 * 1000 * 1000;
310 	const unsigned long cr_mod = 150 * 1000 * 1000;
311 	struct sun4i_ss_ctx *ss;
312 
313 	if (!pdev->dev.of_node)
314 		return -ENODEV;
315 
316 	ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);
317 	if (!ss)
318 		return -ENOMEM;
319 
320 	ss->base = devm_platform_ioremap_resource(pdev, 0);
321 	if (IS_ERR(ss->base)) {
322 		dev_err(&pdev->dev, "Cannot request MMIO\n");
323 		return PTR_ERR(ss->base);
324 	}
325 
326 	ss->ssclk = devm_clk_get(&pdev->dev, "mod");
327 	if (IS_ERR(ss->ssclk)) {
328 		err = PTR_ERR(ss->ssclk);
329 		dev_err(&pdev->dev, "Cannot get SS clock err=%d\n", err);
330 		return err;
331 	}
332 	dev_dbg(&pdev->dev, "clock ss acquired\n");
333 
334 	ss->busclk = devm_clk_get(&pdev->dev, "ahb");
335 	if (IS_ERR(ss->busclk)) {
336 		err = PTR_ERR(ss->busclk);
337 		dev_err(&pdev->dev, "Cannot get AHB SS clock err=%d\n", err);
338 		return err;
339 	}
340 	dev_dbg(&pdev->dev, "clock ahb_ss acquired\n");
341 
342 	ss->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");
343 	if (IS_ERR(ss->reset)) {
344 		if (PTR_ERR(ss->reset) == -EPROBE_DEFER)
345 			return PTR_ERR(ss->reset);
346 		dev_info(&pdev->dev, "no reset control found\n");
347 		ss->reset = NULL;
348 	}
349 
350 	/*
351 	 * Check that clock have the correct rates given in the datasheet
352 	 * Try to set the clock to the maximum allowed
353 	 */
354 	err = clk_set_rate(ss->ssclk, cr_mod);
355 	if (err) {
356 		dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n");
357 		return err;
358 	}
359 
360 	/*
361 	 * The only impact on clocks below requirement are bad performance,
362 	 * so do not print "errors"
363 	 * warn on Overclocked clocks
364 	 */
365 	cr = clk_get_rate(ss->busclk);
366 	if (cr >= cr_ahb)
367 		dev_dbg(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
368 			cr, cr / 1000000, cr_ahb);
369 	else
370 		dev_warn(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
371 			 cr, cr / 1000000, cr_ahb);
372 
373 	cr = clk_get_rate(ss->ssclk);
374 	if (cr <= cr_mod)
375 		if (cr < cr_mod)
376 			dev_warn(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",
377 				 cr, cr / 1000000, cr_mod);
378 		else
379 			dev_dbg(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",
380 				cr, cr / 1000000, cr_mod);
381 	else
382 		dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n",
383 			 cr, cr / 1000000, cr_mod);
384 
385 	ss->dev = &pdev->dev;
386 	platform_set_drvdata(pdev, ss);
387 
388 	spin_lock_init(&ss->slock);
389 
390 	err = sun4i_ss_pm_init(ss);
391 	if (err)
392 		return err;
393 
394 	/*
395 	 * Datasheet named it "Die Bonding ID"
396 	 * I expect to be a sort of Security System Revision number.
397 	 * Since the A80 seems to have an other version of SS
398 	 * this info could be useful
399 	 */
400 
401 	err = pm_runtime_get_sync(ss->dev);
402 	if (err < 0)
403 		goto error_pm;
404 
405 	writel(SS_ENABLED, ss->base + SS_CTL);
406 	v = readl(ss->base + SS_CTL);
407 	v >>= 16;
408 	v &= 0x07;
409 	dev_info(&pdev->dev, "Die ID %d\n", v);
410 	writel(0, ss->base + SS_CTL);
411 
412 	pm_runtime_put_sync(ss->dev);
413 
414 	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
415 		ss_algs[i].ss = ss;
416 		switch (ss_algs[i].type) {
417 		case CRYPTO_ALG_TYPE_SKCIPHER:
418 			err = crypto_register_skcipher(&ss_algs[i].alg.crypto);
419 			if (err) {
420 				dev_err(ss->dev, "Fail to register %s\n",
421 					ss_algs[i].alg.crypto.base.cra_name);
422 				goto error_alg;
423 			}
424 			break;
425 		case CRYPTO_ALG_TYPE_AHASH:
426 			err = crypto_register_ahash(&ss_algs[i].alg.hash);
427 			if (err) {
428 				dev_err(ss->dev, "Fail to register %s\n",
429 					ss_algs[i].alg.hash.halg.base.cra_name);
430 				goto error_alg;
431 			}
432 			break;
433 		case CRYPTO_ALG_TYPE_RNG:
434 			err = crypto_register_rng(&ss_algs[i].alg.rng);
435 			if (err) {
436 				dev_err(ss->dev, "Fail to register %s\n",
437 					ss_algs[i].alg.rng.base.cra_name);
438 			}
439 			break;
440 		}
441 	}
442 	return 0;
443 error_alg:
444 	i--;
445 	for (; i >= 0; i--) {
446 		switch (ss_algs[i].type) {
447 		case CRYPTO_ALG_TYPE_SKCIPHER:
448 			crypto_unregister_skcipher(&ss_algs[i].alg.crypto);
449 			break;
450 		case CRYPTO_ALG_TYPE_AHASH:
451 			crypto_unregister_ahash(&ss_algs[i].alg.hash);
452 			break;
453 		case CRYPTO_ALG_TYPE_RNG:
454 			crypto_unregister_rng(&ss_algs[i].alg.rng);
455 			break;
456 		}
457 	}
458 error_pm:
459 	sun4i_ss_pm_exit(ss);
460 	return err;
461 }
462 
463 static int sun4i_ss_remove(struct platform_device *pdev)
464 {
465 	int i;
466 	struct sun4i_ss_ctx *ss = platform_get_drvdata(pdev);
467 
468 	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
469 		switch (ss_algs[i].type) {
470 		case CRYPTO_ALG_TYPE_SKCIPHER:
471 			crypto_unregister_skcipher(&ss_algs[i].alg.crypto);
472 			break;
473 		case CRYPTO_ALG_TYPE_AHASH:
474 			crypto_unregister_ahash(&ss_algs[i].alg.hash);
475 			break;
476 		case CRYPTO_ALG_TYPE_RNG:
477 			crypto_unregister_rng(&ss_algs[i].alg.rng);
478 			break;
479 		}
480 	}
481 
482 	sun4i_ss_pm_exit(ss);
483 	return 0;
484 }
485 
486 static const struct of_device_id a20ss_crypto_of_match_table[] = {
487 	{ .compatible = "allwinner,sun4i-a10-crypto" },
488 	{}
489 };
490 MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table);
491 
492 static struct platform_driver sun4i_ss_driver = {
493 	.probe          = sun4i_ss_probe,
494 	.remove         = sun4i_ss_remove,
495 	.driver         = {
496 		.name           = "sun4i-ss",
497 		.pm		= &sun4i_ss_pm_ops,
498 		.of_match_table	= a20ss_crypto_of_match_table,
499 	},
500 };
501 
502 module_platform_driver(sun4i_ss_driver);
503 
504 MODULE_ALIAS("platform:sun4i-ss");
505 MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");
506 MODULE_LICENSE("GPL");
507 MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
508