Path: blob/master/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
26292 views
// SPDX-License-Identifier: GPL-2.01/*2* sun8i-ss-core.c - hardware cryptographic offloader for3* Allwinner A80/A83T SoC4*5* Copyright (C) 2015-2019 Corentin Labbe <[email protected]>6*7* Core file which registers crypto algorithms supported by the SecuritySystem8*9* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst10*/1112#include <crypto/engine.h>13#include <crypto/internal/rng.h>14#include <crypto/internal/skcipher.h>15#include <linux/clk.h>16#include <linux/delay.h>17#include <linux/dma-mapping.h>18#include <linux/err.h>19#include <linux/interrupt.h>20#include <linux/io.h>21#include <linux/irq.h>22#include <linux/kernel.h>23#include <linux/module.h>24#include <linux/of.h>25#include <linux/platform_device.h>26#include <linux/pm_runtime.h>27#include <linux/reset.h>2829#include "sun8i-ss.h"3031static const struct ss_variant ss_a80_variant = {32.alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES,33},34.alg_hash = { SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP,35},36.op_mode = { SS_OP_ECB, SS_OP_CBC,37},38.ss_clks = {39{ "bus", 0, 300 * 1000 * 1000 },40{ "mod", 0, 300 * 1000 * 1000 },41}42};4344static const struct ss_variant ss_a83t_variant = {45.alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES,46},47.alg_hash = { SS_ALG_MD5, SS_ALG_SHA1, SS_ALG_SHA224, SS_ALG_SHA256,48},49.op_mode = { SS_OP_ECB, SS_OP_CBC,50},51.ss_clks = {52{ "bus", 0, 300 * 1000 * 1000 },53{ "mod", 0, 300 * 1000 * 1000 },54}55};5657/*58* sun8i_ss_get_engine_number() get the next channel slot59* This is a simple round-robin way of getting the next channel60*/61int sun8i_ss_get_engine_number(struct sun8i_ss_dev *ss)62{63return atomic_inc_return(&ss->flow) % MAXFLOW;64}6566int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx,67const char *name)68{69int flow = rctx->flow;70unsigned int ivlen = rctx->ivlen;71u32 v = SS_START;72int i;7374#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG75ss->flows[flow].stat_req++;76#endif7778/* choose between stream0/stream1 */79if (flow)80v |= SS_FLOW1;81else82v |= SS_FLOW0;8384v |= rctx->op_mode;85v |= rctx->method;8687if (rctx->op_dir)88v |= SS_DECRYPTION;8990switch (rctx->keylen) {91case 128 / 8:92v |= SS_AES_128BITS << 7;93break;94case 192 / 8:95v |= SS_AES_192BITS << 7;96break;97case 256 / 8:98v |= SS_AES_256BITS << 7;99break;100}101102for (i = 0; i < MAX_SG; i++) {103if (!rctx->t_dst[i].addr)104break;105106mutex_lock(&ss->mlock);107writel(rctx->p_key, ss->base + SS_KEY_ADR_REG);108109if (ivlen) {110if (rctx->op_dir == SS_ENCRYPTION) {111if (i == 0)112writel(rctx->p_iv[0], ss->base + SS_IV_ADR_REG);113else114writel(rctx->t_dst[i - 1].addr + rctx->t_dst[i - 1].len * 4 - ivlen, ss->base + SS_IV_ADR_REG);115} else {116writel(rctx->p_iv[i], ss->base + SS_IV_ADR_REG);117}118}119120dev_dbg(ss->dev,121"Processing SG %d on flow %d %s ctl=%x %d to %d method=%x opmode=%x opdir=%x srclen=%d\n",122i, flow, name, v,123rctx->t_src[i].len, rctx->t_dst[i].len,124rctx->method, rctx->op_mode,125rctx->op_dir, rctx->t_src[i].len);126127writel(rctx->t_src[i].addr, ss->base + SS_SRC_ADR_REG);128writel(rctx->t_dst[i].addr, ss->base + SS_DST_ADR_REG);129writel(rctx->t_src[i].len, ss->base + SS_LEN_ADR_REG);130131reinit_completion(&ss->flows[flow].complete);132ss->flows[flow].status = 0;133wmb();134135writel(v, ss->base + SS_CTL_REG);136mutex_unlock(&ss->mlock);137wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,138msecs_to_jiffies(2000));139if (ss->flows[flow].status == 0) {140dev_err(ss->dev, "DMA timeout for %s\n", name);141return -EFAULT;142}143}144145return 0;146}147148static irqreturn_t ss_irq_handler(int irq, void *data)149{150struct sun8i_ss_dev *ss = (struct sun8i_ss_dev *)data;151int flow = 0;152u32 p;153154p = readl(ss->base + SS_INT_STA_REG);155for (flow = 0; flow < MAXFLOW; flow++) {156if (p & (BIT(flow))) {157writel(BIT(flow), ss->base + SS_INT_STA_REG);158ss->flows[flow].status = 1;159complete(&ss->flows[flow].complete);160}161}162163return IRQ_HANDLED;164}165166static struct sun8i_ss_alg_template ss_algs[] = {167{168.type = CRYPTO_ALG_TYPE_SKCIPHER,169.ss_algo_id = SS_ID_CIPHER_AES,170.ss_blockmode = SS_ID_OP_CBC,171.alg.skcipher.base = {172.base = {173.cra_name = "cbc(aes)",174.cra_driver_name = "cbc-aes-sun8i-ss",175.cra_priority = 400,176.cra_blocksize = AES_BLOCK_SIZE,177.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |178CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |179CRYPTO_ALG_NEED_FALLBACK,180.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),181.cra_module = THIS_MODULE,182.cra_alignmask = 0xf,183.cra_init = sun8i_ss_cipher_init,184.cra_exit = sun8i_ss_cipher_exit,185},186.min_keysize = AES_MIN_KEY_SIZE,187.max_keysize = AES_MAX_KEY_SIZE,188.ivsize = AES_BLOCK_SIZE,189.setkey = sun8i_ss_aes_setkey,190.encrypt = sun8i_ss_skencrypt,191.decrypt = sun8i_ss_skdecrypt,192},193.alg.skcipher.op = {194.do_one_request = sun8i_ss_handle_cipher_request,195},196},197{198.type = CRYPTO_ALG_TYPE_SKCIPHER,199.ss_algo_id = SS_ID_CIPHER_AES,200.ss_blockmode = SS_ID_OP_ECB,201.alg.skcipher.base = {202.base = {203.cra_name = "ecb(aes)",204.cra_driver_name = "ecb-aes-sun8i-ss",205.cra_priority = 400,206.cra_blocksize = AES_BLOCK_SIZE,207.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |208CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |209CRYPTO_ALG_NEED_FALLBACK,210.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),211.cra_module = THIS_MODULE,212.cra_alignmask = 0xf,213.cra_init = sun8i_ss_cipher_init,214.cra_exit = sun8i_ss_cipher_exit,215},216.min_keysize = AES_MIN_KEY_SIZE,217.max_keysize = AES_MAX_KEY_SIZE,218.setkey = sun8i_ss_aes_setkey,219.encrypt = sun8i_ss_skencrypt,220.decrypt = sun8i_ss_skdecrypt,221},222.alg.skcipher.op = {223.do_one_request = sun8i_ss_handle_cipher_request,224},225},226{227.type = CRYPTO_ALG_TYPE_SKCIPHER,228.ss_algo_id = SS_ID_CIPHER_DES3,229.ss_blockmode = SS_ID_OP_CBC,230.alg.skcipher.base = {231.base = {232.cra_name = "cbc(des3_ede)",233.cra_driver_name = "cbc-des3-sun8i-ss",234.cra_priority = 400,235.cra_blocksize = DES3_EDE_BLOCK_SIZE,236.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |237CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |238CRYPTO_ALG_NEED_FALLBACK,239.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),240.cra_module = THIS_MODULE,241.cra_alignmask = 0xf,242.cra_init = sun8i_ss_cipher_init,243.cra_exit = sun8i_ss_cipher_exit,244},245.min_keysize = DES3_EDE_KEY_SIZE,246.max_keysize = DES3_EDE_KEY_SIZE,247.ivsize = DES3_EDE_BLOCK_SIZE,248.setkey = sun8i_ss_des3_setkey,249.encrypt = sun8i_ss_skencrypt,250.decrypt = sun8i_ss_skdecrypt,251},252.alg.skcipher.op = {253.do_one_request = sun8i_ss_handle_cipher_request,254},255},256{257.type = CRYPTO_ALG_TYPE_SKCIPHER,258.ss_algo_id = SS_ID_CIPHER_DES3,259.ss_blockmode = SS_ID_OP_ECB,260.alg.skcipher.base = {261.base = {262.cra_name = "ecb(des3_ede)",263.cra_driver_name = "ecb-des3-sun8i-ss",264.cra_priority = 400,265.cra_blocksize = DES3_EDE_BLOCK_SIZE,266.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |267CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |268CRYPTO_ALG_NEED_FALLBACK,269.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),270.cra_module = THIS_MODULE,271.cra_alignmask = 0xf,272.cra_init = sun8i_ss_cipher_init,273.cra_exit = sun8i_ss_cipher_exit,274},275.min_keysize = DES3_EDE_KEY_SIZE,276.max_keysize = DES3_EDE_KEY_SIZE,277.setkey = sun8i_ss_des3_setkey,278.encrypt = sun8i_ss_skencrypt,279.decrypt = sun8i_ss_skdecrypt,280},281.alg.skcipher.op = {282.do_one_request = sun8i_ss_handle_cipher_request,283},284},285#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG286{287.type = CRYPTO_ALG_TYPE_RNG,288.alg.rng = {289.base = {290.cra_name = "stdrng",291.cra_driver_name = "sun8i-ss-prng",292.cra_priority = 300,293.cra_ctxsize = sizeof(struct sun8i_ss_rng_tfm_ctx),294.cra_module = THIS_MODULE,295.cra_init = sun8i_ss_prng_init,296.cra_exit = sun8i_ss_prng_exit,297},298.generate = sun8i_ss_prng_generate,299.seed = sun8i_ss_prng_seed,300.seedsize = PRNG_SEED_SIZE,301}302},303#endif304#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH305{ .type = CRYPTO_ALG_TYPE_AHASH,306.ss_algo_id = SS_ID_HASH_MD5,307.alg.hash.base = {308.init = sun8i_ss_hash_init,309.update = sun8i_ss_hash_update,310.final = sun8i_ss_hash_final,311.finup = sun8i_ss_hash_finup,312.digest = sun8i_ss_hash_digest,313.export = sun8i_ss_hash_export,314.import = sun8i_ss_hash_import,315.init_tfm = sun8i_ss_hash_init_tfm,316.exit_tfm = sun8i_ss_hash_exit_tfm,317.halg = {318.digestsize = MD5_DIGEST_SIZE,319.statesize = sizeof(struct md5_state),320.base = {321.cra_name = "md5",322.cra_driver_name = "md5-sun8i-ss",323.cra_priority = 300,324.cra_flags = CRYPTO_ALG_TYPE_AHASH |325CRYPTO_ALG_ASYNC |326CRYPTO_ALG_NEED_FALLBACK,327.cra_blocksize = MD5_HMAC_BLOCK_SIZE,328.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),329.cra_module = THIS_MODULE,330}331}332},333.alg.hash.op = {334.do_one_request = sun8i_ss_hash_run,335},336},337{ .type = CRYPTO_ALG_TYPE_AHASH,338.ss_algo_id = SS_ID_HASH_SHA1,339.alg.hash.base = {340.init = sun8i_ss_hash_init,341.update = sun8i_ss_hash_update,342.final = sun8i_ss_hash_final,343.finup = sun8i_ss_hash_finup,344.digest = sun8i_ss_hash_digest,345.export = sun8i_ss_hash_export,346.import = sun8i_ss_hash_import,347.init_tfm = sun8i_ss_hash_init_tfm,348.exit_tfm = sun8i_ss_hash_exit_tfm,349.halg = {350.digestsize = SHA1_DIGEST_SIZE,351.statesize = sizeof(struct sha1_state),352.base = {353.cra_name = "sha1",354.cra_driver_name = "sha1-sun8i-ss",355.cra_priority = 300,356.cra_flags = CRYPTO_ALG_TYPE_AHASH |357CRYPTO_ALG_ASYNC |358CRYPTO_ALG_NEED_FALLBACK,359.cra_blocksize = SHA1_BLOCK_SIZE,360.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),361.cra_module = THIS_MODULE,362}363}364},365.alg.hash.op = {366.do_one_request = sun8i_ss_hash_run,367},368},369{ .type = CRYPTO_ALG_TYPE_AHASH,370.ss_algo_id = SS_ID_HASH_SHA224,371.alg.hash.base = {372.init = sun8i_ss_hash_init,373.update = sun8i_ss_hash_update,374.final = sun8i_ss_hash_final,375.finup = sun8i_ss_hash_finup,376.digest = sun8i_ss_hash_digest,377.export = sun8i_ss_hash_export,378.import = sun8i_ss_hash_import,379.init_tfm = sun8i_ss_hash_init_tfm,380.exit_tfm = sun8i_ss_hash_exit_tfm,381.halg = {382.digestsize = SHA224_DIGEST_SIZE,383.statesize = sizeof(struct sha256_state),384.base = {385.cra_name = "sha224",386.cra_driver_name = "sha224-sun8i-ss",387.cra_priority = 300,388.cra_flags = CRYPTO_ALG_TYPE_AHASH |389CRYPTO_ALG_ASYNC |390CRYPTO_ALG_NEED_FALLBACK,391.cra_blocksize = SHA224_BLOCK_SIZE,392.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),393.cra_module = THIS_MODULE,394}395}396},397.alg.hash.op = {398.do_one_request = sun8i_ss_hash_run,399},400},401{ .type = CRYPTO_ALG_TYPE_AHASH,402.ss_algo_id = SS_ID_HASH_SHA256,403.alg.hash.base = {404.init = sun8i_ss_hash_init,405.update = sun8i_ss_hash_update,406.final = sun8i_ss_hash_final,407.finup = sun8i_ss_hash_finup,408.digest = sun8i_ss_hash_digest,409.export = sun8i_ss_hash_export,410.import = sun8i_ss_hash_import,411.init_tfm = sun8i_ss_hash_init_tfm,412.exit_tfm = sun8i_ss_hash_exit_tfm,413.halg = {414.digestsize = SHA256_DIGEST_SIZE,415.statesize = sizeof(struct sha256_state),416.base = {417.cra_name = "sha256",418.cra_driver_name = "sha256-sun8i-ss",419.cra_priority = 300,420.cra_flags = CRYPTO_ALG_TYPE_AHASH |421CRYPTO_ALG_ASYNC |422CRYPTO_ALG_NEED_FALLBACK,423.cra_blocksize = SHA256_BLOCK_SIZE,424.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),425.cra_module = THIS_MODULE,426}427}428},429.alg.hash.op = {430.do_one_request = sun8i_ss_hash_run,431},432},433{ .type = CRYPTO_ALG_TYPE_AHASH,434.ss_algo_id = SS_ID_HASH_SHA1,435.alg.hash.base = {436.init = sun8i_ss_hash_init,437.update = sun8i_ss_hash_update,438.final = sun8i_ss_hash_final,439.finup = sun8i_ss_hash_finup,440.digest = sun8i_ss_hash_digest,441.export = sun8i_ss_hash_export,442.import = sun8i_ss_hash_import,443.init_tfm = sun8i_ss_hash_init_tfm,444.exit_tfm = sun8i_ss_hash_exit_tfm,445.setkey = sun8i_ss_hmac_setkey,446.halg = {447.digestsize = SHA1_DIGEST_SIZE,448.statesize = sizeof(struct sha1_state),449.base = {450.cra_name = "hmac(sha1)",451.cra_driver_name = "hmac-sha1-sun8i-ss",452.cra_priority = 300,453.cra_flags = CRYPTO_ALG_TYPE_AHASH |454CRYPTO_ALG_ASYNC |455CRYPTO_ALG_NEED_FALLBACK,456.cra_blocksize = SHA1_BLOCK_SIZE,457.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),458.cra_module = THIS_MODULE,459}460}461},462.alg.hash.op = {463.do_one_request = sun8i_ss_hash_run,464},465},466#endif467};468469static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)470{471struct sun8i_ss_dev *ss __maybe_unused = seq->private;472unsigned int i;473474for (i = 0; i < MAXFLOW; i++)475seq_printf(seq, "Channel %d: nreq %lu\n", i,476#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG477ss->flows[i].stat_req);478#else4790ul);480#endif481482for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {483if (!ss_algs[i].ss)484continue;485switch (ss_algs[i].type) {486case CRYPTO_ALG_TYPE_SKCIPHER:487seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",488ss_algs[i].alg.skcipher.base.base.cra_driver_name,489ss_algs[i].alg.skcipher.base.base.cra_name,490ss_algs[i].stat_req, ss_algs[i].stat_fb);491492seq_printf(seq, "\tLast fallback is: %s\n",493ss_algs[i].fbname);494seq_printf(seq, "\tFallback due to length: %lu\n",495ss_algs[i].stat_fb_len);496seq_printf(seq, "\tFallback due to SG length: %lu\n",497ss_algs[i].stat_fb_sglen);498seq_printf(seq, "\tFallback due to alignment: %lu\n",499ss_algs[i].stat_fb_align);500seq_printf(seq, "\tFallback due to SG numbers: %lu\n",501ss_algs[i].stat_fb_sgnum);502break;503case CRYPTO_ALG_TYPE_RNG:504seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",505ss_algs[i].alg.rng.base.cra_driver_name,506ss_algs[i].alg.rng.base.cra_name,507ss_algs[i].stat_req, ss_algs[i].stat_bytes);508break;509case CRYPTO_ALG_TYPE_AHASH:510seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",511ss_algs[i].alg.hash.base.halg.base.cra_driver_name,512ss_algs[i].alg.hash.base.halg.base.cra_name,513ss_algs[i].stat_req, ss_algs[i].stat_fb);514seq_printf(seq, "\tLast fallback is: %s\n",515ss_algs[i].fbname);516seq_printf(seq, "\tFallback due to length: %lu\n",517ss_algs[i].stat_fb_len);518seq_printf(seq, "\tFallback due to SG length: %lu\n",519ss_algs[i].stat_fb_sglen);520seq_printf(seq, "\tFallback due to alignment: %lu\n",521ss_algs[i].stat_fb_align);522seq_printf(seq, "\tFallback due to SG numbers: %lu\n",523ss_algs[i].stat_fb_sgnum);524break;525}526}527return 0;528}529530DEFINE_SHOW_ATTRIBUTE(sun8i_ss_debugfs);531532static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)533{534while (i >= 0) {535crypto_engine_exit(ss->flows[i].engine);536i--;537}538}539540/*541* Allocate the flow list structure542*/543static int allocate_flows(struct sun8i_ss_dev *ss)544{545int i, j, err;546547ss->flows = devm_kcalloc(ss->dev, MAXFLOW, sizeof(struct sun8i_ss_flow),548GFP_KERNEL);549if (!ss->flows)550return -ENOMEM;551552for (i = 0; i < MAXFLOW; i++) {553init_completion(&ss->flows[i].complete);554555ss->flows[i].biv = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,556GFP_KERNEL);557if (!ss->flows[i].biv) {558err = -ENOMEM;559goto error_engine;560}561562for (j = 0; j < MAX_SG; j++) {563ss->flows[i].iv[j] = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,564GFP_KERNEL);565if (!ss->flows[i].iv[j]) {566err = -ENOMEM;567goto error_engine;568}569}570571/* the padding could be up to two block. */572ss->flows[i].pad = devm_kmalloc(ss->dev, MAX_PAD_SIZE,573GFP_KERNEL);574if (!ss->flows[i].pad) {575err = -ENOMEM;576goto error_engine;577}578ss->flows[i].result =579devm_kmalloc(ss->dev, max(SHA256_DIGEST_SIZE,580dma_get_cache_alignment()),581GFP_KERNEL);582if (!ss->flows[i].result) {583err = -ENOMEM;584goto error_engine;585}586587ss->flows[i].engine = crypto_engine_alloc_init(ss->dev, true);588if (!ss->flows[i].engine) {589dev_err(ss->dev, "Cannot allocate engine\n");590i--;591err = -ENOMEM;592goto error_engine;593}594err = crypto_engine_start(ss->flows[i].engine);595if (err) {596dev_err(ss->dev, "Cannot start engine\n");597goto error_engine;598}599}600return 0;601error_engine:602sun8i_ss_free_flows(ss, i);603return err;604}605606/*607* Power management strategy: The device is suspended unless a TFM exists for608* one of the algorithms proposed by this driver.609*/610static int sun8i_ss_pm_suspend(struct device *dev)611{612struct sun8i_ss_dev *ss = dev_get_drvdata(dev);613int i;614615reset_control_assert(ss->reset);616for (i = 0; i < SS_MAX_CLOCKS; i++)617clk_disable_unprepare(ss->ssclks[i]);618return 0;619}620621static int sun8i_ss_pm_resume(struct device *dev)622{623struct sun8i_ss_dev *ss = dev_get_drvdata(dev);624int err, i;625626for (i = 0; i < SS_MAX_CLOCKS; i++) {627if (!ss->variant->ss_clks[i].name)628continue;629err = clk_prepare_enable(ss->ssclks[i]);630if (err) {631dev_err(ss->dev, "Cannot prepare_enable %s\n",632ss->variant->ss_clks[i].name);633goto error;634}635}636err = reset_control_deassert(ss->reset);637if (err) {638dev_err(ss->dev, "Cannot deassert reset control\n");639goto error;640}641/* enable interrupts for all flows */642writel(BIT(0) | BIT(1), ss->base + SS_INT_CTL_REG);643644return 0;645error:646sun8i_ss_pm_suspend(dev);647return err;648}649650static const struct dev_pm_ops sun8i_ss_pm_ops = {651SET_RUNTIME_PM_OPS(sun8i_ss_pm_suspend, sun8i_ss_pm_resume, NULL)652};653654static int sun8i_ss_pm_init(struct sun8i_ss_dev *ss)655{656int err;657658pm_runtime_use_autosuspend(ss->dev);659pm_runtime_set_autosuspend_delay(ss->dev, 2000);660661err = pm_runtime_set_suspended(ss->dev);662if (err)663return err;664pm_runtime_enable(ss->dev);665return err;666}667668static void sun8i_ss_pm_exit(struct sun8i_ss_dev *ss)669{670pm_runtime_disable(ss->dev);671}672673static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)674{675int ss_method, err, id;676unsigned int i;677678for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {679ss_algs[i].ss = ss;680switch (ss_algs[i].type) {681case CRYPTO_ALG_TYPE_SKCIPHER:682id = ss_algs[i].ss_algo_id;683ss_method = ss->variant->alg_cipher[id];684if (ss_method == SS_ID_NOTSUPP) {685dev_info(ss->dev,686"DEBUG: Algo of %s not supported\n",687ss_algs[i].alg.skcipher.base.base.cra_name);688ss_algs[i].ss = NULL;689break;690}691id = ss_algs[i].ss_blockmode;692ss_method = ss->variant->op_mode[id];693if (ss_method == SS_ID_NOTSUPP) {694dev_info(ss->dev, "DEBUG: Blockmode of %s not supported\n",695ss_algs[i].alg.skcipher.base.base.cra_name);696ss_algs[i].ss = NULL;697break;698}699dev_info(ss->dev, "DEBUG: Register %s\n",700ss_algs[i].alg.skcipher.base.base.cra_name);701err = crypto_engine_register_skcipher(&ss_algs[i].alg.skcipher);702if (err) {703dev_err(ss->dev, "Fail to register %s\n",704ss_algs[i].alg.skcipher.base.base.cra_name);705ss_algs[i].ss = NULL;706return err;707}708break;709case CRYPTO_ALG_TYPE_RNG:710err = crypto_register_rng(&ss_algs[i].alg.rng);711if (err) {712dev_err(ss->dev, "Fail to register %s\n",713ss_algs[i].alg.rng.base.cra_name);714ss_algs[i].ss = NULL;715}716break;717case CRYPTO_ALG_TYPE_AHASH:718id = ss_algs[i].ss_algo_id;719ss_method = ss->variant->alg_hash[id];720if (ss_method == SS_ID_NOTSUPP) {721dev_info(ss->dev,722"DEBUG: Algo of %s not supported\n",723ss_algs[i].alg.hash.base.halg.base.cra_name);724ss_algs[i].ss = NULL;725break;726}727dev_info(ss->dev, "Register %s\n",728ss_algs[i].alg.hash.base.halg.base.cra_name);729err = crypto_engine_register_ahash(&ss_algs[i].alg.hash);730if (err) {731dev_err(ss->dev, "ERROR: Fail to register %s\n",732ss_algs[i].alg.hash.base.halg.base.cra_name);733ss_algs[i].ss = NULL;734return err;735}736break;737default:738ss_algs[i].ss = NULL;739dev_err(ss->dev, "ERROR: tried to register an unknown algo\n");740}741}742return 0;743}744745static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)746{747unsigned int i;748749for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {750if (!ss_algs[i].ss)751continue;752switch (ss_algs[i].type) {753case CRYPTO_ALG_TYPE_SKCIPHER:754dev_info(ss->dev, "Unregister %d %s\n", i,755ss_algs[i].alg.skcipher.base.base.cra_name);756crypto_engine_unregister_skcipher(&ss_algs[i].alg.skcipher);757break;758case CRYPTO_ALG_TYPE_RNG:759dev_info(ss->dev, "Unregister %d %s\n", i,760ss_algs[i].alg.rng.base.cra_name);761crypto_unregister_rng(&ss_algs[i].alg.rng);762break;763case CRYPTO_ALG_TYPE_AHASH:764dev_info(ss->dev, "Unregister %d %s\n", i,765ss_algs[i].alg.hash.base.halg.base.cra_name);766crypto_engine_unregister_ahash(&ss_algs[i].alg.hash);767break;768}769}770}771772static int sun8i_ss_get_clks(struct sun8i_ss_dev *ss)773{774unsigned long cr;775int err, i;776777for (i = 0; i < SS_MAX_CLOCKS; i++) {778if (!ss->variant->ss_clks[i].name)779continue;780ss->ssclks[i] = devm_clk_get(ss->dev, ss->variant->ss_clks[i].name);781if (IS_ERR(ss->ssclks[i])) {782err = PTR_ERR(ss->ssclks[i]);783dev_err(ss->dev, "Cannot get %s SS clock err=%d\n",784ss->variant->ss_clks[i].name, err);785return err;786}787cr = clk_get_rate(ss->ssclks[i]);788if (!cr)789return -EINVAL;790if (ss->variant->ss_clks[i].freq > 0 &&791cr != ss->variant->ss_clks[i].freq) {792dev_info(ss->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n",793ss->variant->ss_clks[i].name,794ss->variant->ss_clks[i].freq,795ss->variant->ss_clks[i].freq / 1000000,796cr, cr / 1000000);797err = clk_set_rate(ss->ssclks[i], ss->variant->ss_clks[i].freq);798if (err)799dev_err(ss->dev, "Fail to set %s clk speed to %lu hz\n",800ss->variant->ss_clks[i].name,801ss->variant->ss_clks[i].freq);802}803if (ss->variant->ss_clks[i].max_freq > 0 &&804cr > ss->variant->ss_clks[i].max_freq)805dev_warn(ss->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommendation (%lu hz)",806ss->variant->ss_clks[i].name, cr,807ss->variant->ss_clks[i].max_freq);808}809return 0;810}811812static int sun8i_ss_probe(struct platform_device *pdev)813{814struct sun8i_ss_dev *ss;815int err, irq;816u32 v;817818ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);819if (!ss)820return -ENOMEM;821822ss->dev = &pdev->dev;823platform_set_drvdata(pdev, ss);824825ss->variant = of_device_get_match_data(&pdev->dev);826if (!ss->variant) {827dev_err(&pdev->dev, "Missing Crypto Engine variant\n");828return -EINVAL;829}830831ss->base = devm_platform_ioremap_resource(pdev, 0);832if (IS_ERR(ss->base))833return PTR_ERR(ss->base);834835err = sun8i_ss_get_clks(ss);836if (err)837return err;838839irq = platform_get_irq(pdev, 0);840if (irq < 0)841return irq;842843ss->reset = devm_reset_control_get(&pdev->dev, NULL);844if (IS_ERR(ss->reset))845return dev_err_probe(&pdev->dev, PTR_ERR(ss->reset),846"No reset control found\n");847848mutex_init(&ss->mlock);849850err = allocate_flows(ss);851if (err)852return err;853854err = sun8i_ss_pm_init(ss);855if (err)856goto error_pm;857858err = devm_request_irq(&pdev->dev, irq, ss_irq_handler, 0, "sun8i-ss", ss);859if (err) {860dev_err(ss->dev, "Cannot request SecuritySystem IRQ (err=%d)\n", err);861goto error_irq;862}863864err = sun8i_ss_register_algs(ss);865if (err)866goto error_alg;867868err = pm_runtime_resume_and_get(ss->dev);869if (err < 0)870goto error_alg;871872v = readl(ss->base + SS_CTL_REG);873v >>= SS_DIE_ID_SHIFT;874v &= SS_DIE_ID_MASK;875dev_info(&pdev->dev, "Security System Die ID %x\n", v);876877pm_runtime_put_sync(ss->dev);878879if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {880struct dentry *dbgfs_dir __maybe_unused;881struct dentry *dbgfs_stats __maybe_unused;882883/* Ignore error of debugfs */884dbgfs_dir = debugfs_create_dir("sun8i-ss", NULL);885dbgfs_stats = debugfs_create_file("stats", 0444,886dbgfs_dir, ss,887&sun8i_ss_debugfs_fops);888889#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG890ss->dbgfs_dir = dbgfs_dir;891ss->dbgfs_stats = dbgfs_stats;892#endif893}894895return 0;896error_alg:897sun8i_ss_unregister_algs(ss);898error_irq:899sun8i_ss_pm_exit(ss);900error_pm:901sun8i_ss_free_flows(ss, MAXFLOW - 1);902return err;903}904905static void sun8i_ss_remove(struct platform_device *pdev)906{907struct sun8i_ss_dev *ss = platform_get_drvdata(pdev);908909sun8i_ss_unregister_algs(ss);910911#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG912debugfs_remove_recursive(ss->dbgfs_dir);913#endif914915sun8i_ss_free_flows(ss, MAXFLOW - 1);916917sun8i_ss_pm_exit(ss);918}919920static const struct of_device_id sun8i_ss_crypto_of_match_table[] = {921{ .compatible = "allwinner,sun8i-a83t-crypto",922.data = &ss_a83t_variant },923{ .compatible = "allwinner,sun9i-a80-crypto",924.data = &ss_a80_variant },925{}926};927MODULE_DEVICE_TABLE(of, sun8i_ss_crypto_of_match_table);928929static struct platform_driver sun8i_ss_driver = {930.probe = sun8i_ss_probe,931.remove = sun8i_ss_remove,932.driver = {933.name = "sun8i-ss",934.pm = &sun8i_ss_pm_ops,935.of_match_table = sun8i_ss_crypto_of_match_table,936},937};938939module_platform_driver(sun8i_ss_driver);940941MODULE_DESCRIPTION("Allwinner SecuritySystem cryptographic offloader");942MODULE_LICENSE("GPL");943MODULE_AUTHOR("Corentin Labbe <[email protected]>");944945946