linux/drivers/crypto/sunxi-ss/sun4i-ss-core.c
<<
>>
Prefs
   1/*
   2 * sun4i-ss-core.c - hardware cryptographic accelerator for Allwinner A20 SoC
   3 *
   4 * Copyright (C) 2013-2015 Corentin LABBE <clabbe.montjoie@gmail.com>
   5 *
   6 * Core file which registers crypto algorithms supported by the SS.
   7 *
   8 * You could find a link for the datasheet in Documentation/arm/sunxi/README
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 */
  15#include <linux/clk.h>
  16#include <linux/crypto.h>
  17#include <linux/io.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/platform_device.h>
  21#include <crypto/scatterwalk.h>
  22#include <linux/scatterlist.h>
  23#include <linux/interrupt.h>
  24#include <linux/delay.h>
  25#include <linux/reset.h>
  26
  27#include "sun4i-ss.h"
  28
  29static struct sun4i_ss_alg_template ss_algs[] = {
  30{       .type = CRYPTO_ALG_TYPE_AHASH,
  31        .mode = SS_OP_MD5,
  32        .alg.hash = {
  33                .init = sun4i_hash_init,
  34                .update = sun4i_hash_update,
  35                .final = sun4i_hash_final,
  36                .finup = sun4i_hash_finup,
  37                .digest = sun4i_hash_digest,
  38                .export = sun4i_hash_export_md5,
  39                .import = sun4i_hash_import_md5,
  40                .halg = {
  41                        .digestsize = MD5_DIGEST_SIZE,
  42                        .statesize = sizeof(struct md5_state),
  43                        .base = {
  44                                .cra_name = "md5",
  45                                .cra_driver_name = "md5-sun4i-ss",
  46                                .cra_priority = 300,
  47                                .cra_alignmask = 3,
  48                                .cra_flags = CRYPTO_ALG_TYPE_AHASH,
  49                                .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
  50                                .cra_ctxsize = sizeof(struct sun4i_req_ctx),
  51                                .cra_module = THIS_MODULE,
  52                                .cra_type = &crypto_ahash_type,
  53                                .cra_init = sun4i_hash_crainit
  54                        }
  55                }
  56        }
  57},
  58{       .type = CRYPTO_ALG_TYPE_AHASH,
  59        .mode = SS_OP_SHA1,
  60        .alg.hash = {
  61                .init = sun4i_hash_init,
  62                .update = sun4i_hash_update,
  63                .final = sun4i_hash_final,
  64                .finup = sun4i_hash_finup,
  65                .digest = sun4i_hash_digest,
  66                .export = sun4i_hash_export_sha1,
  67                .import = sun4i_hash_import_sha1,
  68                .halg = {
  69                        .digestsize = SHA1_DIGEST_SIZE,
  70                        .statesize = sizeof(struct sha1_state),
  71                        .base = {
  72                                .cra_name = "sha1",
  73                                .cra_driver_name = "sha1-sun4i-ss",
  74                                .cra_priority = 300,
  75                                .cra_alignmask = 3,
  76                                .cra_flags = CRYPTO_ALG_TYPE_AHASH,
  77                                .cra_blocksize = SHA1_BLOCK_SIZE,
  78                                .cra_ctxsize = sizeof(struct sun4i_req_ctx),
  79                                .cra_module = THIS_MODULE,
  80                                .cra_type = &crypto_ahash_type,
  81                                .cra_init = sun4i_hash_crainit
  82                        }
  83                }
  84        }
  85},
  86{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
  87        .alg.crypto = {
  88                .cra_name = "cbc(aes)",
  89                .cra_driver_name = "cbc-aes-sun4i-ss",
  90                .cra_priority = 300,
  91                .cra_blocksize = AES_BLOCK_SIZE,
  92                .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
  93                .cra_ctxsize = sizeof(struct sun4i_tfm_ctx),
  94                .cra_module = THIS_MODULE,
  95                .cra_alignmask = 3,
  96                .cra_type = &crypto_ablkcipher_type,
  97                .cra_init = sun4i_ss_cipher_init,
  98                .cra_ablkcipher = {
  99                        .min_keysize    = AES_MIN_KEY_SIZE,
 100                        .max_keysize    = AES_MAX_KEY_SIZE,
 101                        .ivsize         = AES_BLOCK_SIZE,
 102                        .setkey         = sun4i_ss_aes_setkey,
 103                        .encrypt        = sun4i_ss_cbc_aes_encrypt,
 104                        .decrypt        = sun4i_ss_cbc_aes_decrypt,
 105                }
 106        }
 107},
 108{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
 109        .alg.crypto = {
 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_TYPE_ABLKCIPHER,
 115                .cra_ctxsize = sizeof(struct sun4i_tfm_ctx),
 116                .cra_module = THIS_MODULE,
 117                .cra_alignmask = 3,
 118                .cra_type = &crypto_ablkcipher_type,
 119                .cra_init = sun4i_ss_cipher_init,
 120                .cra_ablkcipher = {
 121                        .min_keysize    = AES_MIN_KEY_SIZE,
 122                        .max_keysize    = AES_MAX_KEY_SIZE,
 123                        .ivsize         = AES_BLOCK_SIZE,
 124                        .setkey         = sun4i_ss_aes_setkey,
 125                        .encrypt        = sun4i_ss_ecb_aes_encrypt,
 126                        .decrypt        = sun4i_ss_ecb_aes_decrypt,
 127                }
 128        }
 129},
 130{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
 131        .alg.crypto = {
 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_TYPE_ABLKCIPHER,
 137                .cra_ctxsize = sizeof(struct sun4i_req_ctx),
 138                .cra_module = THIS_MODULE,
 139                .cra_alignmask = 3,
 140                .cra_type = &crypto_ablkcipher_type,
 141                .cra_init = sun4i_ss_cipher_init,
 142                .cra_u.ablkcipher = {
 143                        .min_keysize    = DES_KEY_SIZE,
 144                        .max_keysize    = DES_KEY_SIZE,
 145                        .ivsize         = DES_BLOCK_SIZE,
 146                        .setkey         = sun4i_ss_des_setkey,
 147                        .encrypt        = sun4i_ss_cbc_des_encrypt,
 148                        .decrypt        = sun4i_ss_cbc_des_decrypt,
 149                }
 150        }
 151},
 152{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
 153        .alg.crypto = {
 154                .cra_name = "ecb(des)",
 155                .cra_driver_name = "ecb-des-sun4i-ss",
 156                .cra_priority = 300,
 157                .cra_blocksize = DES_BLOCK_SIZE,
 158                .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
 159                .cra_ctxsize = sizeof(struct sun4i_req_ctx),
 160                .cra_module = THIS_MODULE,
 161                .cra_alignmask = 3,
 162                .cra_type = &crypto_ablkcipher_type,
 163                .cra_init = sun4i_ss_cipher_init,
 164                .cra_u.ablkcipher = {
 165                        .min_keysize    = DES_KEY_SIZE,
 166                        .max_keysize    = DES_KEY_SIZE,
 167                        .setkey         = sun4i_ss_des_setkey,
 168                        .encrypt        = sun4i_ss_ecb_des_encrypt,
 169                        .decrypt        = sun4i_ss_ecb_des_decrypt,
 170                }
 171        }
 172},
 173{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
 174        .alg.crypto = {
 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_TYPE_ABLKCIPHER,
 180                        .cra_ctxsize = sizeof(struct sun4i_req_ctx),
 181                        .cra_module = THIS_MODULE,
 182                        .cra_alignmask = 3,
 183                        .cra_type = &crypto_ablkcipher_type,
 184                        .cra_init = sun4i_ss_cipher_init,
 185                        .cra_u.ablkcipher = {
 186                                .min_keysize    = DES3_EDE_KEY_SIZE,
 187                                .max_keysize    = DES3_EDE_KEY_SIZE,
 188                                .ivsize         = DES3_EDE_BLOCK_SIZE,
 189                                .setkey         = sun4i_ss_des3_setkey,
 190                                .encrypt        = sun4i_ss_cbc_des3_encrypt,
 191                                .decrypt        = sun4i_ss_cbc_des3_decrypt,
 192                }
 193        }
 194},
 195{       .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
 196        .alg.crypto = {
 197                        .cra_name = "ecb(des3_ede)",
 198                        .cra_driver_name = "ecb-des3-sun4i-ss",
 199                        .cra_priority = 300,
 200                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
 201                        .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
 202                        .cra_ctxsize = sizeof(struct sun4i_req_ctx),
 203                        .cra_module = THIS_MODULE,
 204                        .cra_alignmask = 3,
 205                        .cra_type = &crypto_ablkcipher_type,
 206                        .cra_init = sun4i_ss_cipher_init,
 207                        .cra_u.ablkcipher = {
 208                                .min_keysize    = DES3_EDE_KEY_SIZE,
 209                                .max_keysize    = DES3_EDE_KEY_SIZE,
 210                                .ivsize         = DES3_EDE_BLOCK_SIZE,
 211                                .setkey         = sun4i_ss_des3_setkey,
 212                                .encrypt        = sun4i_ss_ecb_des3_encrypt,
 213                                .decrypt        = sun4i_ss_ecb_des3_decrypt,
 214                }
 215        }
 216},
 217};
 218
 219static int sun4i_ss_probe(struct platform_device *pdev)
 220{
 221        struct resource *res;
 222        u32 v;
 223        int err, i;
 224        unsigned long cr;
 225        const unsigned long cr_ahb = 24 * 1000 * 1000;
 226        const unsigned long cr_mod = 150 * 1000 * 1000;
 227        struct sun4i_ss_ctx *ss;
 228
 229        if (!pdev->dev.of_node)
 230                return -ENODEV;
 231
 232        ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);
 233        if (!ss)
 234                return -ENOMEM;
 235
 236        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 237        ss->base = devm_ioremap_resource(&pdev->dev, res);
 238        if (IS_ERR(ss->base)) {
 239                dev_err(&pdev->dev, "Cannot request MMIO\n");
 240                return PTR_ERR(ss->base);
 241        }
 242
 243        ss->ssclk = devm_clk_get(&pdev->dev, "mod");
 244        if (IS_ERR(ss->ssclk)) {
 245                err = PTR_ERR(ss->ssclk);
 246                dev_err(&pdev->dev, "Cannot get SS clock err=%d\n", err);
 247                return err;
 248        }
 249        dev_dbg(&pdev->dev, "clock ss acquired\n");
 250
 251        ss->busclk = devm_clk_get(&pdev->dev, "ahb");
 252        if (IS_ERR(ss->busclk)) {
 253                err = PTR_ERR(ss->busclk);
 254                dev_err(&pdev->dev, "Cannot get AHB SS clock err=%d\n", err);
 255                return err;
 256        }
 257        dev_dbg(&pdev->dev, "clock ahb_ss acquired\n");
 258
 259        ss->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");
 260        if (IS_ERR(ss->reset)) {
 261                if (PTR_ERR(ss->reset) == -EPROBE_DEFER)
 262                        return PTR_ERR(ss->reset);
 263                dev_info(&pdev->dev, "no reset control found\n");
 264                ss->reset = NULL;
 265        }
 266
 267        /* Enable both clocks */
 268        err = clk_prepare_enable(ss->busclk);
 269        if (err != 0) {
 270                dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
 271                return err;
 272        }
 273        err = clk_prepare_enable(ss->ssclk);
 274        if (err != 0) {
 275                dev_err(&pdev->dev, "Cannot prepare_enable ssclk\n");
 276                goto error_ssclk;
 277        }
 278
 279        /*
 280         * Check that clock have the correct rates given in the datasheet
 281         * Try to set the clock to the maximum allowed
 282         */
 283        err = clk_set_rate(ss->ssclk, cr_mod);
 284        if (err != 0) {
 285                dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n");
 286                goto error_clk;
 287        }
 288
 289        /* Deassert reset if we have a reset control */
 290        if (ss->reset) {
 291                err = reset_control_deassert(ss->reset);
 292                if (err) {
 293                        dev_err(&pdev->dev, "Cannot deassert reset control\n");
 294                        goto error_clk;
 295                }
 296        }
 297
 298        /*
 299         * The only impact on clocks below requirement are bad performance,
 300         * so do not print "errors"
 301         * warn on Overclocked clocks
 302         */
 303        cr = clk_get_rate(ss->busclk);
 304        if (cr >= cr_ahb)
 305                dev_dbg(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
 306                        cr, cr / 1000000, cr_ahb);
 307        else
 308                dev_warn(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
 309                         cr, cr / 1000000, cr_ahb);
 310
 311        cr = clk_get_rate(ss->ssclk);
 312        if (cr <= cr_mod)
 313                if (cr < cr_mod)
 314                        dev_warn(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",
 315                                 cr, cr / 1000000, cr_mod);
 316                else
 317                        dev_dbg(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",
 318                                cr, cr / 1000000, cr_mod);
 319        else
 320                dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n",
 321                         cr, cr / 1000000, cr_mod);
 322
 323        /*
 324         * Datasheet named it "Die Bonding ID"
 325         * I expect to be a sort of Security System Revision number.
 326         * Since the A80 seems to have an other version of SS
 327         * this info could be useful
 328         */
 329        writel(SS_ENABLED, ss->base + SS_CTL);
 330        v = readl(ss->base + SS_CTL);
 331        v >>= 16;
 332        v &= 0x07;
 333        dev_info(&pdev->dev, "Die ID %d\n", v);
 334        writel(0, ss->base + SS_CTL);
 335
 336        ss->dev = &pdev->dev;
 337
 338        spin_lock_init(&ss->slock);
 339
 340        for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
 341                ss_algs[i].ss = ss;
 342                switch (ss_algs[i].type) {
 343                case CRYPTO_ALG_TYPE_ABLKCIPHER:
 344                        err = crypto_register_alg(&ss_algs[i].alg.crypto);
 345                        if (err != 0) {
 346                                dev_err(ss->dev, "Fail to register %s\n",
 347                                        ss_algs[i].alg.crypto.cra_name);
 348                                goto error_alg;
 349                        }
 350                        break;
 351                case CRYPTO_ALG_TYPE_AHASH:
 352                        err = crypto_register_ahash(&ss_algs[i].alg.hash);
 353                        if (err != 0) {
 354                                dev_err(ss->dev, "Fail to register %s\n",
 355                                        ss_algs[i].alg.hash.halg.base.cra_name);
 356                                goto error_alg;
 357                        }
 358                        break;
 359                }
 360        }
 361        platform_set_drvdata(pdev, ss);
 362        return 0;
 363error_alg:
 364        i--;
 365        for (; i >= 0; i--) {
 366                switch (ss_algs[i].type) {
 367                case CRYPTO_ALG_TYPE_ABLKCIPHER:
 368                        crypto_unregister_alg(&ss_algs[i].alg.crypto);
 369                        break;
 370                case CRYPTO_ALG_TYPE_AHASH:
 371                        crypto_unregister_ahash(&ss_algs[i].alg.hash);
 372                        break;
 373                }
 374        }
 375        if (ss->reset)
 376                reset_control_assert(ss->reset);
 377error_clk:
 378        clk_disable_unprepare(ss->ssclk);
 379error_ssclk:
 380        clk_disable_unprepare(ss->busclk);
 381        return err;
 382}
 383
 384static int sun4i_ss_remove(struct platform_device *pdev)
 385{
 386        int i;
 387        struct sun4i_ss_ctx *ss = platform_get_drvdata(pdev);
 388
 389        for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
 390                switch (ss_algs[i].type) {
 391                case CRYPTO_ALG_TYPE_ABLKCIPHER:
 392                        crypto_unregister_alg(&ss_algs[i].alg.crypto);
 393                        break;
 394                case CRYPTO_ALG_TYPE_AHASH:
 395                        crypto_unregister_ahash(&ss_algs[i].alg.hash);
 396                        break;
 397                }
 398        }
 399
 400        writel(0, ss->base + SS_CTL);
 401        if (ss->reset)
 402                reset_control_assert(ss->reset);
 403        clk_disable_unprepare(ss->busclk);
 404        clk_disable_unprepare(ss->ssclk);
 405        return 0;
 406}
 407
 408static const struct of_device_id a20ss_crypto_of_match_table[] = {
 409        { .compatible = "allwinner,sun4i-a10-crypto" },
 410        {}
 411};
 412MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table);
 413
 414static struct platform_driver sun4i_ss_driver = {
 415        .probe          = sun4i_ss_probe,
 416        .remove         = sun4i_ss_remove,
 417        .driver         = {
 418                .name           = "sun4i-ss",
 419                .of_match_table = a20ss_crypto_of_match_table,
 420        },
 421};
 422
 423module_platform_driver(sun4i_ss_driver);
 424
 425MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");
 426MODULE_LICENSE("GPL");
 427MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
 428