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