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