Path: blob/master/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
26292 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* sun4i-ss-core.c - hardware cryptographic accelerator for Allwinner A20 SoC3*4* Copyright (C) 2013-2015 Corentin LABBE <[email protected]>5*6* Core file which registers crypto algorithms supported by the SS.7*8* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst9*/10#include <linux/clk.h>11#include <linux/crypto.h>12#include <linux/debugfs.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>2223#include "sun4i-ss.h"2425static const struct ss_variant ss_a10_variant = {26.sha1_in_be = false,27};2829static const struct ss_variant ss_a33_variant = {30.sha1_in_be = true,31};3233static struct sun4i_ss_alg_template ss_algs[] = {34{ .type = CRYPTO_ALG_TYPE_AHASH,35.mode = SS_OP_MD5,36.alg.hash = {37.init = sun4i_hash_init,38.update = sun4i_hash_update,39.final = sun4i_hash_final,40.finup = sun4i_hash_finup,41.digest = sun4i_hash_digest,42.export = sun4i_hash_export_md5,43.import = sun4i_hash_import_md5,44.halg = {45.digestsize = MD5_DIGEST_SIZE,46.statesize = sizeof(struct md5_state),47.base = {48.cra_name = "md5",49.cra_driver_name = "md5-sun4i-ss",50.cra_priority = 300,51.cra_blocksize = MD5_HMAC_BLOCK_SIZE,52.cra_ctxsize = sizeof(struct sun4i_req_ctx),53.cra_module = THIS_MODULE,54.cra_init = sun4i_hash_crainit,55.cra_exit = sun4i_hash_craexit,56}57}58}59},60{ .type = CRYPTO_ALG_TYPE_AHASH,61.mode = SS_OP_SHA1,62.alg.hash = {63.init = sun4i_hash_init,64.update = sun4i_hash_update,65.final = sun4i_hash_final,66.finup = sun4i_hash_finup,67.digest = sun4i_hash_digest,68.export = sun4i_hash_export_sha1,69.import = sun4i_hash_import_sha1,70.halg = {71.digestsize = SHA1_DIGEST_SIZE,72.statesize = sizeof(struct sha1_state),73.base = {74.cra_name = "sha1",75.cra_driver_name = "sha1-sun4i-ss",76.cra_priority = 300,77.cra_blocksize = SHA1_BLOCK_SIZE,78.cra_ctxsize = sizeof(struct sun4i_req_ctx),79.cra_module = THIS_MODULE,80.cra_init = sun4i_hash_crainit,81.cra_exit = sun4i_hash_craexit,82}83}84}85},86{ .type = CRYPTO_ALG_TYPE_SKCIPHER,87.alg.crypto = {88.setkey = sun4i_ss_aes_setkey,89.encrypt = sun4i_ss_cbc_aes_encrypt,90.decrypt = sun4i_ss_cbc_aes_decrypt,91.min_keysize = AES_MIN_KEY_SIZE,92.max_keysize = AES_MAX_KEY_SIZE,93.ivsize = AES_BLOCK_SIZE,94.base = {95.cra_name = "cbc(aes)",96.cra_driver_name = "cbc-aes-sun4i-ss",97.cra_priority = 300,98.cra_blocksize = AES_BLOCK_SIZE,99.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,100.cra_ctxsize = sizeof(struct sun4i_tfm_ctx),101.cra_module = THIS_MODULE,102.cra_alignmask = 3,103.cra_init = sun4i_ss_cipher_init,104.cra_exit = sun4i_ss_cipher_exit,105}106}107},108{ .type = CRYPTO_ALG_TYPE_SKCIPHER,109.alg.crypto = {110.setkey = sun4i_ss_aes_setkey,111.encrypt = sun4i_ss_ecb_aes_encrypt,112.decrypt = sun4i_ss_ecb_aes_decrypt,113.min_keysize = AES_MIN_KEY_SIZE,114.max_keysize = AES_MAX_KEY_SIZE,115.base = {116.cra_name = "ecb(aes)",117.cra_driver_name = "ecb-aes-sun4i-ss",118.cra_priority = 300,119.cra_blocksize = AES_BLOCK_SIZE,120.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,121.cra_ctxsize = sizeof(struct sun4i_tfm_ctx),122.cra_module = THIS_MODULE,123.cra_alignmask = 3,124.cra_init = sun4i_ss_cipher_init,125.cra_exit = sun4i_ss_cipher_exit,126}127}128},129{ .type = CRYPTO_ALG_TYPE_SKCIPHER,130.alg.crypto = {131.setkey = sun4i_ss_des_setkey,132.encrypt = sun4i_ss_cbc_des_encrypt,133.decrypt = sun4i_ss_cbc_des_decrypt,134.min_keysize = DES_KEY_SIZE,135.max_keysize = DES_KEY_SIZE,136.ivsize = DES_BLOCK_SIZE,137.base = {138.cra_name = "cbc(des)",139.cra_driver_name = "cbc-des-sun4i-ss",140.cra_priority = 300,141.cra_blocksize = DES_BLOCK_SIZE,142.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,143.cra_ctxsize = sizeof(struct sun4i_req_ctx),144.cra_module = THIS_MODULE,145.cra_alignmask = 3,146.cra_init = sun4i_ss_cipher_init,147.cra_exit = sun4i_ss_cipher_exit,148}149}150},151{ .type = CRYPTO_ALG_TYPE_SKCIPHER,152.alg.crypto = {153.setkey = sun4i_ss_des_setkey,154.encrypt = sun4i_ss_ecb_des_encrypt,155.decrypt = sun4i_ss_ecb_des_decrypt,156.min_keysize = DES_KEY_SIZE,157.max_keysize = DES_KEY_SIZE,158.base = {159.cra_name = "ecb(des)",160.cra_driver_name = "ecb-des-sun4i-ss",161.cra_priority = 300,162.cra_blocksize = DES_BLOCK_SIZE,163.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,164.cra_ctxsize = sizeof(struct sun4i_req_ctx),165.cra_module = THIS_MODULE,166.cra_alignmask = 3,167.cra_init = sun4i_ss_cipher_init,168.cra_exit = sun4i_ss_cipher_exit,169}170}171},172{ .type = CRYPTO_ALG_TYPE_SKCIPHER,173.alg.crypto = {174.setkey = sun4i_ss_des3_setkey,175.encrypt = sun4i_ss_cbc_des3_encrypt,176.decrypt = sun4i_ss_cbc_des3_decrypt,177.min_keysize = DES3_EDE_KEY_SIZE,178.max_keysize = DES3_EDE_KEY_SIZE,179.ivsize = DES3_EDE_BLOCK_SIZE,180.base = {181.cra_name = "cbc(des3_ede)",182.cra_driver_name = "cbc-des3-sun4i-ss",183.cra_priority = 300,184.cra_blocksize = DES3_EDE_BLOCK_SIZE,185.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,186.cra_ctxsize = sizeof(struct sun4i_req_ctx),187.cra_module = THIS_MODULE,188.cra_alignmask = 3,189.cra_init = sun4i_ss_cipher_init,190.cra_exit = sun4i_ss_cipher_exit,191}192}193},194{ .type = CRYPTO_ALG_TYPE_SKCIPHER,195.alg.crypto = {196.setkey = sun4i_ss_des3_setkey,197.encrypt = sun4i_ss_ecb_des3_encrypt,198.decrypt = sun4i_ss_ecb_des3_decrypt,199.min_keysize = DES3_EDE_KEY_SIZE,200.max_keysize = DES3_EDE_KEY_SIZE,201.base = {202.cra_name = "ecb(des3_ede)",203.cra_driver_name = "ecb-des3-sun4i-ss",204.cra_priority = 300,205.cra_blocksize = DES3_EDE_BLOCK_SIZE,206.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK,207.cra_ctxsize = sizeof(struct sun4i_req_ctx),208.cra_module = THIS_MODULE,209.cra_alignmask = 3,210.cra_init = sun4i_ss_cipher_init,211.cra_exit = sun4i_ss_cipher_exit,212}213}214},215#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG216{217.type = CRYPTO_ALG_TYPE_RNG,218.alg.rng = {219.base = {220.cra_name = "stdrng",221.cra_driver_name = "sun4i_ss_rng",222.cra_priority = 300,223.cra_ctxsize = 0,224.cra_module = THIS_MODULE,225},226.generate = sun4i_ss_prng_generate,227.seed = sun4i_ss_prng_seed,228.seedsize = SS_SEED_LEN / BITS_PER_BYTE,229}230},231#endif232};233234static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)235{236unsigned int i;237238for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {239if (!ss_algs[i].ss)240continue;241switch (ss_algs[i].type) {242case CRYPTO_ALG_TYPE_SKCIPHER:243seq_printf(seq, "%s %s reqs=%lu opti=%lu fallback=%lu tsize=%lu\n",244ss_algs[i].alg.crypto.base.cra_driver_name,245ss_algs[i].alg.crypto.base.cra_name,246ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,247ss_algs[i].stat_bytes);248break;249case CRYPTO_ALG_TYPE_RNG:250seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",251ss_algs[i].alg.rng.base.cra_driver_name,252ss_algs[i].alg.rng.base.cra_name,253ss_algs[i].stat_req, ss_algs[i].stat_bytes);254break;255case CRYPTO_ALG_TYPE_AHASH:256seq_printf(seq, "%s %s reqs=%lu\n",257ss_algs[i].alg.hash.halg.base.cra_driver_name,258ss_algs[i].alg.hash.halg.base.cra_name,259ss_algs[i].stat_req);260break;261}262}263return 0;264}265DEFINE_SHOW_ATTRIBUTE(sun4i_ss_debugfs);266267/*268* Power management strategy: The device is suspended unless a TFM exists for269* one of the algorithms proposed by this driver.270*/271static int sun4i_ss_pm_suspend(struct device *dev)272{273struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);274275reset_control_assert(ss->reset);276277clk_disable_unprepare(ss->ssclk);278clk_disable_unprepare(ss->busclk);279return 0;280}281282static int sun4i_ss_pm_resume(struct device *dev)283{284struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);285286int err;287288err = clk_prepare_enable(ss->busclk);289if (err) {290dev_err(ss->dev, "Cannot prepare_enable busclk\n");291goto err_enable;292}293294err = clk_prepare_enable(ss->ssclk);295if (err) {296dev_err(ss->dev, "Cannot prepare_enable ssclk\n");297goto err_enable;298}299300err = reset_control_deassert(ss->reset);301if (err) {302dev_err(ss->dev, "Cannot deassert reset control\n");303goto err_enable;304}305306return err;307err_enable:308sun4i_ss_pm_suspend(dev);309return err;310}311312static const struct dev_pm_ops sun4i_ss_pm_ops = {313SET_RUNTIME_PM_OPS(sun4i_ss_pm_suspend, sun4i_ss_pm_resume, NULL)314};315316/*317* When power management is enabled, this function enables the PM and set the318* device as suspended319* When power management is disabled, this function just enables the device320*/321static int sun4i_ss_pm_init(struct sun4i_ss_ctx *ss)322{323int err;324325pm_runtime_use_autosuspend(ss->dev);326pm_runtime_set_autosuspend_delay(ss->dev, 2000);327328err = pm_runtime_set_suspended(ss->dev);329if (err)330return err;331pm_runtime_enable(ss->dev);332return err;333}334335static void sun4i_ss_pm_exit(struct sun4i_ss_ctx *ss)336{337pm_runtime_disable(ss->dev);338}339340static int sun4i_ss_probe(struct platform_device *pdev)341{342u32 v;343int err, i;344unsigned long cr;345const unsigned long cr_ahb = 24 * 1000 * 1000;346const unsigned long cr_mod = 150 * 1000 * 1000;347struct sun4i_ss_ctx *ss;348349if (!pdev->dev.of_node)350return -ENODEV;351352ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);353if (!ss)354return -ENOMEM;355356ss->base = devm_platform_ioremap_resource(pdev, 0);357if (IS_ERR(ss->base)) {358dev_err(&pdev->dev, "Cannot request MMIO\n");359return PTR_ERR(ss->base);360}361362ss->variant = of_device_get_match_data(&pdev->dev);363if (!ss->variant) {364dev_err(&pdev->dev, "Missing Security System variant\n");365return -EINVAL;366}367368ss->ssclk = devm_clk_get(&pdev->dev, "mod");369if (IS_ERR(ss->ssclk)) {370err = PTR_ERR(ss->ssclk);371dev_err(&pdev->dev, "Cannot get SS clock err=%d\n", err);372return err;373}374dev_dbg(&pdev->dev, "clock ss acquired\n");375376ss->busclk = devm_clk_get(&pdev->dev, "ahb");377if (IS_ERR(ss->busclk)) {378err = PTR_ERR(ss->busclk);379dev_err(&pdev->dev, "Cannot get AHB SS clock err=%d\n", err);380return err;381}382dev_dbg(&pdev->dev, "clock ahb_ss acquired\n");383384ss->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");385if (IS_ERR(ss->reset))386return PTR_ERR(ss->reset);387if (!ss->reset)388dev_info(&pdev->dev, "no reset control found\n");389390/*391* Check that clock have the correct rates given in the datasheet392* Try to set the clock to the maximum allowed393*/394err = clk_set_rate(ss->ssclk, cr_mod);395if (err) {396dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n");397return err;398}399400/*401* The only impact on clocks below requirement are bad performance,402* so do not print "errors"403* warn on Overclocked clocks404*/405cr = clk_get_rate(ss->busclk);406if (cr >= cr_ahb)407dev_dbg(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",408cr, cr / 1000000, cr_ahb);409else410dev_warn(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",411cr, cr / 1000000, cr_ahb);412413cr = clk_get_rate(ss->ssclk);414if (cr <= cr_mod)415if (cr < cr_mod)416dev_warn(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",417cr, cr / 1000000, cr_mod);418else419dev_dbg(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",420cr, cr / 1000000, cr_mod);421else422dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n",423cr, cr / 1000000, cr_mod);424425ss->dev = &pdev->dev;426platform_set_drvdata(pdev, ss);427428spin_lock_init(&ss->slock);429430err = sun4i_ss_pm_init(ss);431if (err)432return err;433434/*435* Datasheet named it "Die Bonding ID"436* I expect to be a sort of Security System Revision number.437* Since the A80 seems to have an other version of SS438* this info could be useful439*/440441err = pm_runtime_resume_and_get(ss->dev);442if (err < 0)443goto error_pm;444445writel(SS_ENABLED, ss->base + SS_CTL);446v = readl(ss->base + SS_CTL);447v >>= 16;448v &= 0x07;449dev_info(&pdev->dev, "Die ID %d\n", v);450writel(0, ss->base + SS_CTL);451452pm_runtime_put_sync(ss->dev);453454for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {455ss_algs[i].ss = ss;456switch (ss_algs[i].type) {457case CRYPTO_ALG_TYPE_SKCIPHER:458err = crypto_register_skcipher(&ss_algs[i].alg.crypto);459if (err) {460dev_err(ss->dev, "Fail to register %s\n",461ss_algs[i].alg.crypto.base.cra_name);462goto error_alg;463}464break;465case CRYPTO_ALG_TYPE_AHASH:466err = crypto_register_ahash(&ss_algs[i].alg.hash);467if (err) {468dev_err(ss->dev, "Fail to register %s\n",469ss_algs[i].alg.hash.halg.base.cra_name);470goto error_alg;471}472break;473case CRYPTO_ALG_TYPE_RNG:474err = crypto_register_rng(&ss_algs[i].alg.rng);475if (err) {476dev_err(ss->dev, "Fail to register %s\n",477ss_algs[i].alg.rng.base.cra_name);478}479break;480}481}482483/* Ignore error of debugfs */484ss->dbgfs_dir = debugfs_create_dir("sun4i-ss", NULL);485ss->dbgfs_stats = debugfs_create_file("stats", 0444, ss->dbgfs_dir, ss,486&sun4i_ss_debugfs_fops);487488return 0;489error_alg:490i--;491for (; i >= 0; i--) {492switch (ss_algs[i].type) {493case CRYPTO_ALG_TYPE_SKCIPHER:494crypto_unregister_skcipher(&ss_algs[i].alg.crypto);495break;496case CRYPTO_ALG_TYPE_AHASH:497crypto_unregister_ahash(&ss_algs[i].alg.hash);498break;499case CRYPTO_ALG_TYPE_RNG:500crypto_unregister_rng(&ss_algs[i].alg.rng);501break;502}503}504error_pm:505sun4i_ss_pm_exit(ss);506return err;507}508509static void sun4i_ss_remove(struct platform_device *pdev)510{511int i;512struct sun4i_ss_ctx *ss = platform_get_drvdata(pdev);513514for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {515switch (ss_algs[i].type) {516case CRYPTO_ALG_TYPE_SKCIPHER:517crypto_unregister_skcipher(&ss_algs[i].alg.crypto);518break;519case CRYPTO_ALG_TYPE_AHASH:520crypto_unregister_ahash(&ss_algs[i].alg.hash);521break;522case CRYPTO_ALG_TYPE_RNG:523crypto_unregister_rng(&ss_algs[i].alg.rng);524break;525}526}527528sun4i_ss_pm_exit(ss);529}530531static const struct of_device_id a20ss_crypto_of_match_table[] = {532{ .compatible = "allwinner,sun4i-a10-crypto",533.data = &ss_a10_variant534},535{ .compatible = "allwinner,sun8i-a33-crypto",536.data = &ss_a33_variant537},538{}539};540MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table);541542static struct platform_driver sun4i_ss_driver = {543.probe = sun4i_ss_probe,544.remove = sun4i_ss_remove,545.driver = {546.name = "sun4i-ss",547.pm = &sun4i_ss_pm_ops,548.of_match_table = a20ss_crypto_of_match_table,549},550};551552module_platform_driver(sun4i_ss_driver);553554MODULE_ALIAS("platform:sun4i-ss");555MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");556MODULE_LICENSE("GPL");557MODULE_AUTHOR("Corentin LABBE <[email protected]>");558559560