Path: blob/master/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
26296 views
// SPDX-License-Identifier: GPL-2.01/*2* sun8i-ce-core.c - hardware cryptographic offloader for3* Allwinner H3/A64/H5/H2+/H6/R40 SoC4*5* Copyright (C) 2015-2019 Corentin Labbe <[email protected]>6*7* Core file which registers crypto algorithms supported by the CryptoEngine.8*9* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst10*/1112#include <crypto/engine.h>13#include <crypto/internal/hash.h>14#include <crypto/internal/rng.h>15#include <crypto/internal/skcipher.h>16#include <linux/clk.h>17#include <linux/delay.h>18#include <linux/dma-mapping.h>19#include <linux/err.h>20#include <linux/interrupt.h>21#include <linux/io.h>22#include <linux/irq.h>23#include <linux/kernel.h>24#include <linux/module.h>25#include <linux/of.h>26#include <linux/platform_device.h>27#include <linux/pm_runtime.h>28#include <linux/reset.h>2930#include "sun8i-ce.h"3132/*33* mod clock is lower on H3 than other SoC due to some DMA timeout occurring34* with high value.35* If you want to tune mod clock, loading driver and passing selftest is36* insufficient, you need to test with some LUKS test (mount and write to it)37*/38static const struct ce_variant ce_h3_variant = {39.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,40},41.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,42CE_ALG_SHA384, CE_ALG_SHA51243},44.op_mode = { CE_OP_ECB, CE_OP_CBC45},46.ce_clks = {47{ "bus", 0, 200000000 },48{ "mod", 50000000, 0 },49},50.esr = ESR_H3,51.prng = CE_ALG_PRNG,52.trng = CE_ID_NOTSUPP,53};5455static const struct ce_variant ce_h5_variant = {56.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,57},58.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,59CE_ID_NOTSUPP, CE_ID_NOTSUPP60},61.op_mode = { CE_OP_ECB, CE_OP_CBC62},63.ce_clks = {64{ "bus", 0, 200000000 },65{ "mod", 300000000, 0 },66},67.esr = ESR_H5,68.prng = CE_ALG_PRNG,69.trng = CE_ID_NOTSUPP,70};7172static const struct ce_variant ce_h6_variant = {73.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,74},75.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,76CE_ALG_SHA384, CE_ALG_SHA51277},78.op_mode = { CE_OP_ECB, CE_OP_CBC79},80.cipher_t_dlen_in_bytes = true,81.hash_t_dlen_in_bits = true,82.prng_t_dlen_in_bytes = true,83.trng_t_dlen_in_bytes = true,84.ce_clks = {85{ "bus", 0, 200000000 },86{ "mod", 300000000, 0 },87{ "ram", 0, 400000000 },88},89.esr = ESR_H6,90.prng = CE_ALG_PRNG_V2,91.trng = CE_ALG_TRNG_V2,92};9394static const struct ce_variant ce_h616_variant = {95.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,96},97.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,98CE_ALG_SHA384, CE_ALG_SHA51299},100.op_mode = { CE_OP_ECB, CE_OP_CBC101},102.cipher_t_dlen_in_bytes = true,103.hash_t_dlen_in_bits = true,104.prng_t_dlen_in_bytes = true,105.trng_t_dlen_in_bytes = true,106.needs_word_addresses = true,107.ce_clks = {108{ "bus", 0, 200000000 },109{ "mod", 300000000, 0 },110{ "ram", 0, 400000000 },111{ "trng", 0, 0 },112},113.esr = ESR_H6,114.prng = CE_ALG_PRNG_V2,115.trng = CE_ALG_TRNG_V2,116};117118static const struct ce_variant ce_a64_variant = {119.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,120},121.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,122CE_ID_NOTSUPP, CE_ID_NOTSUPP123},124.op_mode = { CE_OP_ECB, CE_OP_CBC125},126.ce_clks = {127{ "bus", 0, 200000000 },128{ "mod", 300000000, 0 },129},130.esr = ESR_A64,131.prng = CE_ALG_PRNG,132.trng = CE_ID_NOTSUPP,133};134135static const struct ce_variant ce_d1_variant = {136.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,137},138.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,139CE_ALG_SHA384, CE_ALG_SHA512140},141.op_mode = { CE_OP_ECB, CE_OP_CBC142},143.ce_clks = {144{ "bus", 0, 200000000 },145{ "mod", 300000000, 0 },146{ "ram", 0, 400000000 },147{ "trng", 0, 0 },148},149.esr = ESR_D1,150.prng = CE_ALG_PRNG,151.trng = CE_ALG_TRNG,152};153154static const struct ce_variant ce_r40_variant = {155.alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,156},157.alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,158CE_ID_NOTSUPP, CE_ID_NOTSUPP159},160.op_mode = { CE_OP_ECB, CE_OP_CBC161},162.ce_clks = {163{ "bus", 0, 200000000 },164{ "mod", 300000000, 0 },165},166.esr = ESR_R40,167.prng = CE_ALG_PRNG,168.trng = CE_ID_NOTSUPP,169};170171/*172* sun8i_ce_get_engine_number() get the next channel slot173* This is a simple round-robin way of getting the next channel174* The flow 3 is reserve for xRNG operations175*/176int sun8i_ce_get_engine_number(struct sun8i_ce_dev *ce)177{178return atomic_inc_return(&ce->flow) % (MAXFLOW - 1);179}180181int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)182{183u32 v;184int err = 0;185struct ce_task *cet = ce->chanlist[flow].tl;186187#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG188ce->chanlist[flow].stat_req++;189#endif190191mutex_lock(&ce->mlock);192193v = readl(ce->base + CE_ICR);194v |= 1 << flow;195writel(v, ce->base + CE_ICR);196197reinit_completion(&ce->chanlist[flow].complete);198writel(desc_addr_val(ce, ce->chanlist[flow].t_phy), ce->base + CE_TDQ);199200ce->chanlist[flow].status = 0;201/* Be sure all data is written before enabling the task */202wmb();203204/* Only H6 needs to write a part of t_common_ctl along with "1", but since it is ignored205* on older SoCs, we have no reason to complicate things.206*/207v = 1 | ((le32_to_cpu(ce->chanlist[flow].tl->t_common_ctl) & 0x7F) << 8);208writel(v, ce->base + CE_TLR);209mutex_unlock(&ce->mlock);210211wait_for_completion_interruptible_timeout(&ce->chanlist[flow].complete,212msecs_to_jiffies(ce->chanlist[flow].timeout));213214if (ce->chanlist[flow].status == 0) {215dev_err(ce->dev, "DMA timeout for %s (tm=%d) on flow %d\n", name,216ce->chanlist[flow].timeout, flow);217err = -EFAULT;218}219/* No need to lock for this read, the channel is locked so220* nothing could modify the error value for this channel221*/222v = readl(ce->base + CE_ESR);223switch (ce->variant->esr) {224case ESR_H3:225/* Sadly, the error bit is not per flow */226if (v) {227dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);228err = -EFAULT;229print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,230cet, sizeof(struct ce_task), false);231}232if (v & CE_ERR_ALGO_NOTSUP)233dev_err(ce->dev, "CE ERROR: algorithm not supported\n");234if (v & CE_ERR_DATALEN)235dev_err(ce->dev, "CE ERROR: data length error\n");236if (v & CE_ERR_KEYSRAM)237dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");238break;239case ESR_A64:240case ESR_D1:241case ESR_H5:242case ESR_R40:243v >>= (flow * 4);244v &= 0xF;245if (v) {246dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);247err = -EFAULT;248print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,249cet, sizeof(struct ce_task), false);250}251if (v & CE_ERR_ALGO_NOTSUP)252dev_err(ce->dev, "CE ERROR: algorithm not supported\n");253if (v & CE_ERR_DATALEN)254dev_err(ce->dev, "CE ERROR: data length error\n");255if (v & CE_ERR_KEYSRAM)256dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");257break;258case ESR_H6:259v >>= (flow * 8);260v &= 0xFF;261if (v) {262dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);263err = -EFAULT;264print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,265cet, sizeof(struct ce_task), false);266}267if (v & CE_ERR_ALGO_NOTSUP)268dev_err(ce->dev, "CE ERROR: algorithm not supported\n");269if (v & CE_ERR_DATALEN)270dev_err(ce->dev, "CE ERROR: data length error\n");271if (v & CE_ERR_KEYSRAM)272dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");273if (v & CE_ERR_ADDR_INVALID)274dev_err(ce->dev, "CE ERROR: address invalid\n");275if (v & CE_ERR_KEYLADDER)276dev_err(ce->dev, "CE ERROR: key ladder configuration error\n");277break;278}279280return err;281}282283static irqreturn_t ce_irq_handler(int irq, void *data)284{285struct sun8i_ce_dev *ce = (struct sun8i_ce_dev *)data;286int flow = 0;287u32 p;288289p = readl(ce->base + CE_ISR);290for (flow = 0; flow < MAXFLOW; flow++) {291if (p & (BIT(flow))) {292writel(BIT(flow), ce->base + CE_ISR);293ce->chanlist[flow].status = 1;294complete(&ce->chanlist[flow].complete);295}296}297298return IRQ_HANDLED;299}300301static struct sun8i_ce_alg_template ce_algs[] = {302{303.type = CRYPTO_ALG_TYPE_SKCIPHER,304.ce_algo_id = CE_ID_CIPHER_AES,305.ce_blockmode = CE_ID_OP_CBC,306.alg.skcipher.base = {307.base = {308.cra_name = "cbc(aes)",309.cra_driver_name = "cbc-aes-sun8i-ce",310.cra_priority = 400,311.cra_blocksize = AES_BLOCK_SIZE,312.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |313CRYPTO_ALG_ASYNC |314CRYPTO_ALG_NEED_FALLBACK,315.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),316.cra_module = THIS_MODULE,317.cra_alignmask = 0xf,318.cra_init = sun8i_ce_cipher_init,319.cra_exit = sun8i_ce_cipher_exit,320},321.min_keysize = AES_MIN_KEY_SIZE,322.max_keysize = AES_MAX_KEY_SIZE,323.ivsize = AES_BLOCK_SIZE,324.setkey = sun8i_ce_aes_setkey,325.encrypt = sun8i_ce_skencrypt,326.decrypt = sun8i_ce_skdecrypt,327},328.alg.skcipher.op = {329.do_one_request = sun8i_ce_cipher_do_one,330},331},332{333.type = CRYPTO_ALG_TYPE_SKCIPHER,334.ce_algo_id = CE_ID_CIPHER_AES,335.ce_blockmode = CE_ID_OP_ECB,336.alg.skcipher.base = {337.base = {338.cra_name = "ecb(aes)",339.cra_driver_name = "ecb-aes-sun8i-ce",340.cra_priority = 400,341.cra_blocksize = AES_BLOCK_SIZE,342.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |343CRYPTO_ALG_ASYNC |344CRYPTO_ALG_NEED_FALLBACK,345.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),346.cra_module = THIS_MODULE,347.cra_alignmask = 0xf,348.cra_init = sun8i_ce_cipher_init,349.cra_exit = sun8i_ce_cipher_exit,350},351.min_keysize = AES_MIN_KEY_SIZE,352.max_keysize = AES_MAX_KEY_SIZE,353.setkey = sun8i_ce_aes_setkey,354.encrypt = sun8i_ce_skencrypt,355.decrypt = sun8i_ce_skdecrypt,356},357.alg.skcipher.op = {358.do_one_request = sun8i_ce_cipher_do_one,359},360},361{362.type = CRYPTO_ALG_TYPE_SKCIPHER,363.ce_algo_id = CE_ID_CIPHER_DES3,364.ce_blockmode = CE_ID_OP_CBC,365.alg.skcipher.base = {366.base = {367.cra_name = "cbc(des3_ede)",368.cra_driver_name = "cbc-des3-sun8i-ce",369.cra_priority = 400,370.cra_blocksize = DES3_EDE_BLOCK_SIZE,371.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |372CRYPTO_ALG_ASYNC |373CRYPTO_ALG_NEED_FALLBACK,374.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),375.cra_module = THIS_MODULE,376.cra_alignmask = 0xf,377.cra_init = sun8i_ce_cipher_init,378.cra_exit = sun8i_ce_cipher_exit,379},380.min_keysize = DES3_EDE_KEY_SIZE,381.max_keysize = DES3_EDE_KEY_SIZE,382.ivsize = DES3_EDE_BLOCK_SIZE,383.setkey = sun8i_ce_des3_setkey,384.encrypt = sun8i_ce_skencrypt,385.decrypt = sun8i_ce_skdecrypt,386},387.alg.skcipher.op = {388.do_one_request = sun8i_ce_cipher_do_one,389},390},391{392.type = CRYPTO_ALG_TYPE_SKCIPHER,393.ce_algo_id = CE_ID_CIPHER_DES3,394.ce_blockmode = CE_ID_OP_ECB,395.alg.skcipher.base = {396.base = {397.cra_name = "ecb(des3_ede)",398.cra_driver_name = "ecb-des3-sun8i-ce",399.cra_priority = 400,400.cra_blocksize = DES3_EDE_BLOCK_SIZE,401.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |402CRYPTO_ALG_ASYNC |403CRYPTO_ALG_NEED_FALLBACK,404.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),405.cra_module = THIS_MODULE,406.cra_alignmask = 0xf,407.cra_init = sun8i_ce_cipher_init,408.cra_exit = sun8i_ce_cipher_exit,409},410.min_keysize = DES3_EDE_KEY_SIZE,411.max_keysize = DES3_EDE_KEY_SIZE,412.setkey = sun8i_ce_des3_setkey,413.encrypt = sun8i_ce_skencrypt,414.decrypt = sun8i_ce_skdecrypt,415},416.alg.skcipher.op = {417.do_one_request = sun8i_ce_cipher_do_one,418},419},420#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH421{ .type = CRYPTO_ALG_TYPE_AHASH,422.ce_algo_id = CE_ID_HASH_MD5,423.alg.hash.base = {424.init = sun8i_ce_hash_init,425.update = sun8i_ce_hash_update,426.final = sun8i_ce_hash_final,427.finup = sun8i_ce_hash_finup,428.digest = sun8i_ce_hash_digest,429.export = sun8i_ce_hash_export,430.import = sun8i_ce_hash_import,431.init_tfm = sun8i_ce_hash_init_tfm,432.exit_tfm = sun8i_ce_hash_exit_tfm,433.halg = {434.digestsize = MD5_DIGEST_SIZE,435.statesize = sizeof(struct md5_state),436.base = {437.cra_name = "md5",438.cra_driver_name = "md5-sun8i-ce",439.cra_priority = 300,440.cra_flags = CRYPTO_ALG_TYPE_AHASH |441CRYPTO_ALG_ASYNC |442CRYPTO_ALG_NEED_FALLBACK,443.cra_blocksize = MD5_HMAC_BLOCK_SIZE,444.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),445.cra_module = THIS_MODULE,446}447}448},449.alg.hash.op = {450.do_one_request = sun8i_ce_hash_run,451},452453},454{ .type = CRYPTO_ALG_TYPE_AHASH,455.ce_algo_id = CE_ID_HASH_SHA1,456.alg.hash.base = {457.init = sun8i_ce_hash_init,458.update = sun8i_ce_hash_update,459.final = sun8i_ce_hash_final,460.finup = sun8i_ce_hash_finup,461.digest = sun8i_ce_hash_digest,462.export = sun8i_ce_hash_export,463.import = sun8i_ce_hash_import,464.init_tfm = sun8i_ce_hash_init_tfm,465.exit_tfm = sun8i_ce_hash_exit_tfm,466.halg = {467.digestsize = SHA1_DIGEST_SIZE,468.statesize = sizeof(struct sha1_state),469.base = {470.cra_name = "sha1",471.cra_driver_name = "sha1-sun8i-ce",472.cra_priority = 300,473.cra_flags = CRYPTO_ALG_TYPE_AHASH |474CRYPTO_ALG_ASYNC |475CRYPTO_ALG_NEED_FALLBACK,476.cra_blocksize = SHA1_BLOCK_SIZE,477.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),478.cra_module = THIS_MODULE,479}480}481},482.alg.hash.op = {483.do_one_request = sun8i_ce_hash_run,484},485},486{ .type = CRYPTO_ALG_TYPE_AHASH,487.ce_algo_id = CE_ID_HASH_SHA224,488.alg.hash.base = {489.init = sun8i_ce_hash_init,490.update = sun8i_ce_hash_update,491.final = sun8i_ce_hash_final,492.finup = sun8i_ce_hash_finup,493.digest = sun8i_ce_hash_digest,494.export = sun8i_ce_hash_export,495.import = sun8i_ce_hash_import,496.init_tfm = sun8i_ce_hash_init_tfm,497.exit_tfm = sun8i_ce_hash_exit_tfm,498.halg = {499.digestsize = SHA224_DIGEST_SIZE,500.statesize = sizeof(struct sha256_state),501.base = {502.cra_name = "sha224",503.cra_driver_name = "sha224-sun8i-ce",504.cra_priority = 300,505.cra_flags = CRYPTO_ALG_TYPE_AHASH |506CRYPTO_ALG_ASYNC |507CRYPTO_ALG_NEED_FALLBACK,508.cra_blocksize = SHA224_BLOCK_SIZE,509.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),510.cra_module = THIS_MODULE,511}512}513},514.alg.hash.op = {515.do_one_request = sun8i_ce_hash_run,516},517},518{ .type = CRYPTO_ALG_TYPE_AHASH,519.ce_algo_id = CE_ID_HASH_SHA256,520.alg.hash.base = {521.init = sun8i_ce_hash_init,522.update = sun8i_ce_hash_update,523.final = sun8i_ce_hash_final,524.finup = sun8i_ce_hash_finup,525.digest = sun8i_ce_hash_digest,526.export = sun8i_ce_hash_export,527.import = sun8i_ce_hash_import,528.init_tfm = sun8i_ce_hash_init_tfm,529.exit_tfm = sun8i_ce_hash_exit_tfm,530.halg = {531.digestsize = SHA256_DIGEST_SIZE,532.statesize = sizeof(struct sha256_state),533.base = {534.cra_name = "sha256",535.cra_driver_name = "sha256-sun8i-ce",536.cra_priority = 300,537.cra_flags = CRYPTO_ALG_TYPE_AHASH |538CRYPTO_ALG_ASYNC |539CRYPTO_ALG_NEED_FALLBACK,540.cra_blocksize = SHA256_BLOCK_SIZE,541.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),542.cra_module = THIS_MODULE,543}544}545},546.alg.hash.op = {547.do_one_request = sun8i_ce_hash_run,548},549},550{ .type = CRYPTO_ALG_TYPE_AHASH,551.ce_algo_id = CE_ID_HASH_SHA384,552.alg.hash.base = {553.init = sun8i_ce_hash_init,554.update = sun8i_ce_hash_update,555.final = sun8i_ce_hash_final,556.finup = sun8i_ce_hash_finup,557.digest = sun8i_ce_hash_digest,558.export = sun8i_ce_hash_export,559.import = sun8i_ce_hash_import,560.init_tfm = sun8i_ce_hash_init_tfm,561.exit_tfm = sun8i_ce_hash_exit_tfm,562.halg = {563.digestsize = SHA384_DIGEST_SIZE,564.statesize = sizeof(struct sha512_state),565.base = {566.cra_name = "sha384",567.cra_driver_name = "sha384-sun8i-ce",568.cra_priority = 300,569.cra_flags = CRYPTO_ALG_TYPE_AHASH |570CRYPTO_ALG_ASYNC |571CRYPTO_ALG_NEED_FALLBACK,572.cra_blocksize = SHA384_BLOCK_SIZE,573.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),574.cra_module = THIS_MODULE,575}576}577},578.alg.hash.op = {579.do_one_request = sun8i_ce_hash_run,580},581},582{ .type = CRYPTO_ALG_TYPE_AHASH,583.ce_algo_id = CE_ID_HASH_SHA512,584.alg.hash.base = {585.init = sun8i_ce_hash_init,586.update = sun8i_ce_hash_update,587.final = sun8i_ce_hash_final,588.finup = sun8i_ce_hash_finup,589.digest = sun8i_ce_hash_digest,590.export = sun8i_ce_hash_export,591.import = sun8i_ce_hash_import,592.init_tfm = sun8i_ce_hash_init_tfm,593.exit_tfm = sun8i_ce_hash_exit_tfm,594.halg = {595.digestsize = SHA512_DIGEST_SIZE,596.statesize = sizeof(struct sha512_state),597.base = {598.cra_name = "sha512",599.cra_driver_name = "sha512-sun8i-ce",600.cra_priority = 300,601.cra_flags = CRYPTO_ALG_TYPE_AHASH |602CRYPTO_ALG_ASYNC |603CRYPTO_ALG_NEED_FALLBACK,604.cra_blocksize = SHA512_BLOCK_SIZE,605.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),606.cra_module = THIS_MODULE,607}608}609},610.alg.hash.op = {611.do_one_request = sun8i_ce_hash_run,612},613},614#endif615#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG616{617.type = CRYPTO_ALG_TYPE_RNG,618.alg.rng = {619.base = {620.cra_name = "stdrng",621.cra_driver_name = "sun8i-ce-prng",622.cra_priority = 300,623.cra_ctxsize = sizeof(struct sun8i_ce_rng_tfm_ctx),624.cra_module = THIS_MODULE,625.cra_init = sun8i_ce_prng_init,626.cra_exit = sun8i_ce_prng_exit,627},628.generate = sun8i_ce_prng_generate,629.seed = sun8i_ce_prng_seed,630.seedsize = PRNG_SEED_SIZE,631}632},633#endif634};635636static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)637{638struct sun8i_ce_dev *ce __maybe_unused = seq->private;639unsigned int i;640641for (i = 0; i < MAXFLOW; i++)642seq_printf(seq, "Channel %d: nreq %lu\n", i,643#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG644ce->chanlist[i].stat_req);645#else6460ul);647#endif648649for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {650if (!ce_algs[i].ce)651continue;652switch (ce_algs[i].type) {653case CRYPTO_ALG_TYPE_SKCIPHER:654seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",655ce_algs[i].alg.skcipher.base.base.cra_driver_name,656ce_algs[i].alg.skcipher.base.base.cra_name,657ce_algs[i].stat_req, ce_algs[i].stat_fb);658seq_printf(seq, "\tLast fallback is: %s\n",659ce_algs[i].fbname);660seq_printf(seq, "\tFallback due to 0 length: %lu\n",661ce_algs[i].stat_fb_len0);662seq_printf(seq, "\tFallback due to length !mod16: %lu\n",663ce_algs[i].stat_fb_mod16);664seq_printf(seq, "\tFallback due to length < IV: %lu\n",665ce_algs[i].stat_fb_leniv);666seq_printf(seq, "\tFallback due to source alignment: %lu\n",667ce_algs[i].stat_fb_srcali);668seq_printf(seq, "\tFallback due to dest alignment: %lu\n",669ce_algs[i].stat_fb_dstali);670seq_printf(seq, "\tFallback due to source length: %lu\n",671ce_algs[i].stat_fb_srclen);672seq_printf(seq, "\tFallback due to dest length: %lu\n",673ce_algs[i].stat_fb_dstlen);674seq_printf(seq, "\tFallback due to SG numbers: %lu\n",675ce_algs[i].stat_fb_maxsg);676break;677case CRYPTO_ALG_TYPE_AHASH:678seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",679ce_algs[i].alg.hash.base.halg.base.cra_driver_name,680ce_algs[i].alg.hash.base.halg.base.cra_name,681ce_algs[i].stat_req, ce_algs[i].stat_fb);682seq_printf(seq, "\tLast fallback is: %s\n",683ce_algs[i].fbname);684seq_printf(seq, "\tFallback due to 0 length: %lu\n",685ce_algs[i].stat_fb_len0);686seq_printf(seq, "\tFallback due to length: %lu\n",687ce_algs[i].stat_fb_srclen);688seq_printf(seq, "\tFallback due to alignment: %lu\n",689ce_algs[i].stat_fb_srcali);690seq_printf(seq, "\tFallback due to SG numbers: %lu\n",691ce_algs[i].stat_fb_maxsg);692break;693case CRYPTO_ALG_TYPE_RNG:694seq_printf(seq, "%s %s reqs=%lu bytes=%lu\n",695ce_algs[i].alg.rng.base.cra_driver_name,696ce_algs[i].alg.rng.base.cra_name,697ce_algs[i].stat_req, ce_algs[i].stat_bytes);698break;699}700}701#if defined(CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG) && \702defined(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)703seq_printf(seq, "HWRNG %lu %lu\n",704ce->hwrng_stat_req, ce->hwrng_stat_bytes);705#endif706return 0;707}708709DEFINE_SHOW_ATTRIBUTE(sun8i_ce_debugfs);710711static void sun8i_ce_free_chanlist(struct sun8i_ce_dev *ce, int i)712{713while (i >= 0) {714crypto_engine_exit(ce->chanlist[i].engine);715if (ce->chanlist[i].tl)716dma_free_coherent(ce->dev, sizeof(struct ce_task),717ce->chanlist[i].tl,718ce->chanlist[i].t_phy);719i--;720}721}722723/*724* Allocate the channel list structure725*/726static int sun8i_ce_allocate_chanlist(struct sun8i_ce_dev *ce)727{728int i, err;729730ce->chanlist = devm_kcalloc(ce->dev, MAXFLOW,731sizeof(struct sun8i_ce_flow), GFP_KERNEL);732if (!ce->chanlist)733return -ENOMEM;734735for (i = 0; i < MAXFLOW; i++) {736init_completion(&ce->chanlist[i].complete);737738ce->chanlist[i].engine = crypto_engine_alloc_init(ce->dev, true);739if (!ce->chanlist[i].engine) {740dev_err(ce->dev, "Cannot allocate engine\n");741i--;742err = -ENOMEM;743goto error_engine;744}745err = crypto_engine_start(ce->chanlist[i].engine);746if (err) {747dev_err(ce->dev, "Cannot start engine\n");748goto error_engine;749}750ce->chanlist[i].tl = dma_alloc_coherent(ce->dev,751sizeof(struct ce_task),752&ce->chanlist[i].t_phy,753GFP_KERNEL);754if (!ce->chanlist[i].tl) {755dev_err(ce->dev, "Cannot get DMA memory for task %d\n",756i);757err = -ENOMEM;758goto error_engine;759}760ce->chanlist[i].bounce_iv = devm_kmalloc(ce->dev, AES_BLOCK_SIZE,761GFP_KERNEL | GFP_DMA);762if (!ce->chanlist[i].bounce_iv) {763err = -ENOMEM;764goto error_engine;765}766ce->chanlist[i].backup_iv = devm_kmalloc(ce->dev, AES_BLOCK_SIZE,767GFP_KERNEL);768if (!ce->chanlist[i].backup_iv) {769err = -ENOMEM;770goto error_engine;771}772}773return 0;774error_engine:775sun8i_ce_free_chanlist(ce, i);776return err;777}778779/*780* Power management strategy: The device is suspended unless a TFM exists for781* one of the algorithms proposed by this driver.782*/783static int sun8i_ce_pm_suspend(struct device *dev)784{785struct sun8i_ce_dev *ce = dev_get_drvdata(dev);786int i;787788reset_control_assert(ce->reset);789for (i = 0; i < CE_MAX_CLOCKS; i++)790clk_disable_unprepare(ce->ceclks[i]);791return 0;792}793794static int sun8i_ce_pm_resume(struct device *dev)795{796struct sun8i_ce_dev *ce = dev_get_drvdata(dev);797int err, i;798799for (i = 0; i < CE_MAX_CLOCKS; i++) {800if (!ce->variant->ce_clks[i].name)801continue;802err = clk_prepare_enable(ce->ceclks[i]);803if (err) {804dev_err(ce->dev, "Cannot prepare_enable %s\n",805ce->variant->ce_clks[i].name);806goto error;807}808}809err = reset_control_deassert(ce->reset);810if (err) {811dev_err(ce->dev, "Cannot deassert reset control\n");812goto error;813}814return 0;815error:816sun8i_ce_pm_suspend(dev);817return err;818}819820static const struct dev_pm_ops sun8i_ce_pm_ops = {821SET_RUNTIME_PM_OPS(sun8i_ce_pm_suspend, sun8i_ce_pm_resume, NULL)822};823824static int sun8i_ce_pm_init(struct sun8i_ce_dev *ce)825{826int err;827828pm_runtime_use_autosuspend(ce->dev);829pm_runtime_set_autosuspend_delay(ce->dev, 2000);830831err = pm_runtime_set_suspended(ce->dev);832if (err)833return err;834835err = devm_pm_runtime_enable(ce->dev);836if (err)837return err;838839return 0;840}841842static int sun8i_ce_get_clks(struct sun8i_ce_dev *ce)843{844unsigned long cr;845int err, i;846847for (i = 0; i < CE_MAX_CLOCKS; i++) {848if (!ce->variant->ce_clks[i].name)849continue;850ce->ceclks[i] = devm_clk_get(ce->dev, ce->variant->ce_clks[i].name);851if (IS_ERR(ce->ceclks[i])) {852err = PTR_ERR(ce->ceclks[i]);853dev_err(ce->dev, "Cannot get %s CE clock err=%d\n",854ce->variant->ce_clks[i].name, err);855return err;856}857cr = clk_get_rate(ce->ceclks[i]);858if (!cr)859return -EINVAL;860if (ce->variant->ce_clks[i].freq > 0 &&861cr != ce->variant->ce_clks[i].freq) {862dev_info(ce->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n",863ce->variant->ce_clks[i].name,864ce->variant->ce_clks[i].freq,865ce->variant->ce_clks[i].freq / 1000000,866cr, cr / 1000000);867err = clk_set_rate(ce->ceclks[i], ce->variant->ce_clks[i].freq);868if (err)869dev_err(ce->dev, "Fail to set %s clk speed to %lu hz\n",870ce->variant->ce_clks[i].name,871ce->variant->ce_clks[i].freq);872}873if (ce->variant->ce_clks[i].max_freq > 0 &&874cr > ce->variant->ce_clks[i].max_freq)875dev_warn(ce->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommendation (%lu hz)",876ce->variant->ce_clks[i].name, cr,877ce->variant->ce_clks[i].max_freq);878}879return 0;880}881882static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)883{884int ce_method, err, id;885unsigned int i;886887for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {888ce_algs[i].ce = ce;889switch (ce_algs[i].type) {890case CRYPTO_ALG_TYPE_SKCIPHER:891id = ce_algs[i].ce_algo_id;892ce_method = ce->variant->alg_cipher[id];893if (ce_method == CE_ID_NOTSUPP) {894dev_dbg(ce->dev,895"DEBUG: Algo of %s not supported\n",896ce_algs[i].alg.skcipher.base.base.cra_name);897ce_algs[i].ce = NULL;898break;899}900id = ce_algs[i].ce_blockmode;901ce_method = ce->variant->op_mode[id];902if (ce_method == CE_ID_NOTSUPP) {903dev_dbg(ce->dev, "DEBUG: Blockmode of %s not supported\n",904ce_algs[i].alg.skcipher.base.base.cra_name);905ce_algs[i].ce = NULL;906break;907}908dev_info(ce->dev, "Register %s\n",909ce_algs[i].alg.skcipher.base.base.cra_name);910err = crypto_engine_register_skcipher(&ce_algs[i].alg.skcipher);911if (err) {912dev_err(ce->dev, "ERROR: Fail to register %s\n",913ce_algs[i].alg.skcipher.base.base.cra_name);914ce_algs[i].ce = NULL;915return err;916}917break;918case CRYPTO_ALG_TYPE_AHASH:919id = ce_algs[i].ce_algo_id;920ce_method = ce->variant->alg_hash[id];921if (ce_method == CE_ID_NOTSUPP) {922dev_info(ce->dev,923"DEBUG: Algo of %s not supported\n",924ce_algs[i].alg.hash.base.halg.base.cra_name);925ce_algs[i].ce = NULL;926break;927}928dev_info(ce->dev, "Register %s\n",929ce_algs[i].alg.hash.base.halg.base.cra_name);930err = crypto_engine_register_ahash(&ce_algs[i].alg.hash);931if (err) {932dev_err(ce->dev, "ERROR: Fail to register %s\n",933ce_algs[i].alg.hash.base.halg.base.cra_name);934ce_algs[i].ce = NULL;935return err;936}937break;938case CRYPTO_ALG_TYPE_RNG:939if (ce->variant->prng == CE_ID_NOTSUPP) {940dev_info(ce->dev,941"DEBUG: Algo of %s not supported\n",942ce_algs[i].alg.rng.base.cra_name);943ce_algs[i].ce = NULL;944break;945}946dev_info(ce->dev, "Register %s\n",947ce_algs[i].alg.rng.base.cra_name);948err = crypto_register_rng(&ce_algs[i].alg.rng);949if (err) {950dev_err(ce->dev, "Fail to register %s\n",951ce_algs[i].alg.rng.base.cra_name);952ce_algs[i].ce = NULL;953}954break;955default:956ce_algs[i].ce = NULL;957dev_err(ce->dev, "ERROR: tried to register an unknown algo\n");958}959}960return 0;961}962963static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce)964{965unsigned int i;966967for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {968if (!ce_algs[i].ce)969continue;970switch (ce_algs[i].type) {971case CRYPTO_ALG_TYPE_SKCIPHER:972dev_info(ce->dev, "Unregister %d %s\n", i,973ce_algs[i].alg.skcipher.base.base.cra_name);974crypto_engine_unregister_skcipher(&ce_algs[i].alg.skcipher);975break;976case CRYPTO_ALG_TYPE_AHASH:977dev_info(ce->dev, "Unregister %d %s\n", i,978ce_algs[i].alg.hash.base.halg.base.cra_name);979crypto_engine_unregister_ahash(&ce_algs[i].alg.hash);980break;981case CRYPTO_ALG_TYPE_RNG:982dev_info(ce->dev, "Unregister %d %s\n", i,983ce_algs[i].alg.rng.base.cra_name);984crypto_unregister_rng(&ce_algs[i].alg.rng);985break;986}987}988}989990static int sun8i_ce_probe(struct platform_device *pdev)991{992struct sun8i_ce_dev *ce;993int err, irq;994u32 v;995996ce = devm_kzalloc(&pdev->dev, sizeof(*ce), GFP_KERNEL);997if (!ce)998return -ENOMEM;9991000ce->dev = &pdev->dev;1001platform_set_drvdata(pdev, ce);10021003ce->variant = of_device_get_match_data(&pdev->dev);1004if (!ce->variant) {1005dev_err(&pdev->dev, "Missing Crypto Engine variant\n");1006return -EINVAL;1007}10081009ce->base = devm_platform_ioremap_resource(pdev, 0);1010if (IS_ERR(ce->base))1011return PTR_ERR(ce->base);10121013err = sun8i_ce_get_clks(ce);1014if (err)1015return err;10161017/* Get Non Secure IRQ */1018irq = platform_get_irq(pdev, 0);1019if (irq < 0)1020return irq;10211022ce->reset = devm_reset_control_get(&pdev->dev, NULL);1023if (IS_ERR(ce->reset))1024return dev_err_probe(&pdev->dev, PTR_ERR(ce->reset),1025"No reset control found\n");10261027mutex_init(&ce->mlock);1028mutex_init(&ce->rnglock);10291030err = sun8i_ce_allocate_chanlist(ce);1031if (err)1032return err;10331034err = sun8i_ce_pm_init(ce);1035if (err)1036goto error_pm;10371038err = devm_request_irq(&pdev->dev, irq, ce_irq_handler, 0,1039"sun8i-ce-ns", ce);1040if (err) {1041dev_err(ce->dev, "Cannot request CryptoEngine Non-secure IRQ (err=%d)\n", err);1042goto error_pm;1043}10441045err = sun8i_ce_register_algs(ce);1046if (err)1047goto error_alg;10481049err = pm_runtime_resume_and_get(ce->dev);1050if (err < 0)1051goto error_alg;10521053#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG1054sun8i_ce_hwrng_register(ce);1055#endif10561057v = readl(ce->base + CE_CTR);1058v >>= CE_DIE_ID_SHIFT;1059v &= CE_DIE_ID_MASK;1060dev_info(&pdev->dev, "CryptoEngine Die ID %x\n", v);10611062pm_runtime_put_sync(ce->dev);10631064if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {1065struct dentry *dbgfs_dir __maybe_unused;1066struct dentry *dbgfs_stats __maybe_unused;10671068/* Ignore error of debugfs */1069dbgfs_dir = debugfs_create_dir("sun8i-ce", NULL);1070dbgfs_stats = debugfs_create_file("stats", 0444,1071dbgfs_dir, ce,1072&sun8i_ce_debugfs_fops);10731074#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG1075ce->dbgfs_dir = dbgfs_dir;1076ce->dbgfs_stats = dbgfs_stats;1077#endif1078}10791080return 0;1081error_alg:1082sun8i_ce_unregister_algs(ce);1083error_pm:1084sun8i_ce_free_chanlist(ce, MAXFLOW - 1);1085return err;1086}10871088static void sun8i_ce_remove(struct platform_device *pdev)1089{1090struct sun8i_ce_dev *ce = platform_get_drvdata(pdev);10911092#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG1093sun8i_ce_hwrng_unregister(ce);1094#endif10951096sun8i_ce_unregister_algs(ce);10971098#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG1099debugfs_remove_recursive(ce->dbgfs_dir);1100#endif11011102sun8i_ce_free_chanlist(ce, MAXFLOW - 1);1103}11041105static const struct of_device_id sun8i_ce_crypto_of_match_table[] = {1106{ .compatible = "allwinner,sun8i-h3-crypto",1107.data = &ce_h3_variant },1108{ .compatible = "allwinner,sun8i-r40-crypto",1109.data = &ce_r40_variant },1110{ .compatible = "allwinner,sun20i-d1-crypto",1111.data = &ce_d1_variant },1112{ .compatible = "allwinner,sun50i-a64-crypto",1113.data = &ce_a64_variant },1114{ .compatible = "allwinner,sun50i-h5-crypto",1115.data = &ce_h5_variant },1116{ .compatible = "allwinner,sun50i-h6-crypto",1117.data = &ce_h6_variant },1118{ .compatible = "allwinner,sun50i-h616-crypto",1119.data = &ce_h616_variant },1120{}1121};1122MODULE_DEVICE_TABLE(of, sun8i_ce_crypto_of_match_table);11231124static struct platform_driver sun8i_ce_driver = {1125.probe = sun8i_ce_probe,1126.remove = sun8i_ce_remove,1127.driver = {1128.name = "sun8i-ce",1129.pm = &sun8i_ce_pm_ops,1130.of_match_table = sun8i_ce_crypto_of_match_table,1131},1132};11331134module_platform_driver(sun8i_ce_driver);11351136MODULE_DESCRIPTION("Allwinner Crypto Engine cryptographic offloader");1137MODULE_LICENSE("GPL");1138MODULE_AUTHOR("Corentin Labbe <[email protected]>");113911401141