brintos

brintos / linux-shallow public Read only

0
0
Text · 24.3 KiB · 0dbc022 Raw
945 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * sun8i-ss-core.c - hardware cryptographic offloader for4 * Allwinner A80/A83T SoC5 *6 * Copyright (C) 2015-2019 Corentin Labbe <clabbe.montjoie@gmail.com>7 *8 * Core file which registers crypto algorithms supported by the SecuritySystem9 *10 * You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst11 */12 13#include <crypto/engine.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>29 30#include "sun8i-ss.h"31 32static const struct ss_variant ss_a80_variant = {33	.alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES,34	},35	.alg_hash = { SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP,36	},37	.op_mode = { SS_OP_ECB, SS_OP_CBC,38	},39	.ss_clks = {40		{ "bus", 0, 300 * 1000 * 1000 },41		{ "mod", 0, 300 * 1000 * 1000 },42	}43};44 45static const struct ss_variant ss_a83t_variant = {46	.alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES,47	},48	.alg_hash = { SS_ALG_MD5, SS_ALG_SHA1, SS_ALG_SHA224, SS_ALG_SHA256,49	},50	.op_mode = { SS_OP_ECB, SS_OP_CBC,51	},52	.ss_clks = {53		{ "bus", 0, 300 * 1000 * 1000 },54		{ "mod", 0, 300 * 1000 * 1000 },55	}56};57 58/*59 * sun8i_ss_get_engine_number() get the next channel slot60 * This is a simple round-robin way of getting the next channel61 */62int sun8i_ss_get_engine_number(struct sun8i_ss_dev *ss)63{64	return atomic_inc_return(&ss->flow) % MAXFLOW;65}66 67int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx,68		      const char *name)69{70	int flow = rctx->flow;71	unsigned int ivlen = rctx->ivlen;72	u32 v = SS_START;73	int i;74 75#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG76	ss->flows[flow].stat_req++;77#endif78 79	/* choose between stream0/stream1 */80	if (flow)81		v |= SS_FLOW1;82	else83		v |= SS_FLOW0;84 85	v |= rctx->op_mode;86	v |= rctx->method;87 88	if (rctx->op_dir)89		v |= SS_DECRYPTION;90 91	switch (rctx->keylen) {92	case 128 / 8:93		v |= SS_AES_128BITS << 7;94		break;95	case 192 / 8:96		v |= SS_AES_192BITS << 7;97		break;98	case 256 / 8:99		v |= SS_AES_256BITS << 7;100		break;101	}102 103	for (i = 0; i < MAX_SG; i++) {104		if (!rctx->t_dst[i].addr)105			break;106 107		mutex_lock(&ss->mlock);108		writel(rctx->p_key, ss->base + SS_KEY_ADR_REG);109 110		if (ivlen) {111			if (rctx->op_dir == SS_ENCRYPTION) {112				if (i == 0)113					writel(rctx->p_iv[0], ss->base + SS_IV_ADR_REG);114				else115					writel(rctx->t_dst[i - 1].addr + rctx->t_dst[i - 1].len * 4 - ivlen, ss->base + SS_IV_ADR_REG);116			} else {117				writel(rctx->p_iv[i], ss->base + SS_IV_ADR_REG);118			}119		}120 121		dev_dbg(ss->dev,122			"Processing SG %d on flow %d %s ctl=%x %d to %d method=%x opmode=%x opdir=%x srclen=%d\n",123			i, flow, name, v,124			rctx->t_src[i].len, rctx->t_dst[i].len,125			rctx->method, rctx->op_mode,126			rctx->op_dir, rctx->t_src[i].len);127 128		writel(rctx->t_src[i].addr, ss->base + SS_SRC_ADR_REG);129		writel(rctx->t_dst[i].addr, ss->base + SS_DST_ADR_REG);130		writel(rctx->t_src[i].len, ss->base + SS_LEN_ADR_REG);131 132		reinit_completion(&ss->flows[flow].complete);133		ss->flows[flow].status = 0;134		wmb();135 136		writel(v, ss->base + SS_CTL_REG);137		mutex_unlock(&ss->mlock);138		wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,139							  msecs_to_jiffies(2000));140		if (ss->flows[flow].status == 0) {141			dev_err(ss->dev, "DMA timeout for %s\n", name);142			return -EFAULT;143		}144	}145 146	return 0;147}148 149static irqreturn_t ss_irq_handler(int irq, void *data)150{151	struct sun8i_ss_dev *ss = (struct sun8i_ss_dev *)data;152	int flow = 0;153	u32 p;154 155	p = readl(ss->base + SS_INT_STA_REG);156	for (flow = 0; flow < MAXFLOW; flow++) {157		if (p & (BIT(flow))) {158			writel(BIT(flow), ss->base + SS_INT_STA_REG);159			ss->flows[flow].status = 1;160			complete(&ss->flows[flow].complete);161		}162	}163 164	return IRQ_HANDLED;165}166 167static struct sun8i_ss_alg_template ss_algs[] = {168{169	.type = CRYPTO_ALG_TYPE_SKCIPHER,170	.ss_algo_id = SS_ID_CIPHER_AES,171	.ss_blockmode = SS_ID_OP_CBC,172	.alg.skcipher.base = {173		.base = {174			.cra_name = "cbc(aes)",175			.cra_driver_name = "cbc-aes-sun8i-ss",176			.cra_priority = 400,177			.cra_blocksize = AES_BLOCK_SIZE,178			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |179				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |180				CRYPTO_ALG_NEED_FALLBACK,181			.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),182			.cra_module = THIS_MODULE,183			.cra_alignmask = 0xf,184			.cra_init = sun8i_ss_cipher_init,185			.cra_exit = sun8i_ss_cipher_exit,186		},187		.min_keysize	= AES_MIN_KEY_SIZE,188		.max_keysize	= AES_MAX_KEY_SIZE,189		.ivsize		= AES_BLOCK_SIZE,190		.setkey		= sun8i_ss_aes_setkey,191		.encrypt	= sun8i_ss_skencrypt,192		.decrypt	= sun8i_ss_skdecrypt,193	},194	.alg.skcipher.op = {195		.do_one_request = sun8i_ss_handle_cipher_request,196	},197},198{199	.type = CRYPTO_ALG_TYPE_SKCIPHER,200	.ss_algo_id = SS_ID_CIPHER_AES,201	.ss_blockmode = SS_ID_OP_ECB,202	.alg.skcipher.base = {203		.base = {204			.cra_name = "ecb(aes)",205			.cra_driver_name = "ecb-aes-sun8i-ss",206			.cra_priority = 400,207			.cra_blocksize = AES_BLOCK_SIZE,208			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |209				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |210				CRYPTO_ALG_NEED_FALLBACK,211			.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),212			.cra_module = THIS_MODULE,213			.cra_alignmask = 0xf,214			.cra_init = sun8i_ss_cipher_init,215			.cra_exit = sun8i_ss_cipher_exit,216		},217		.min_keysize	= AES_MIN_KEY_SIZE,218		.max_keysize	= AES_MAX_KEY_SIZE,219		.setkey		= sun8i_ss_aes_setkey,220		.encrypt	= sun8i_ss_skencrypt,221		.decrypt	= sun8i_ss_skdecrypt,222	},223	.alg.skcipher.op = {224		.do_one_request = sun8i_ss_handle_cipher_request,225	},226},227{228	.type = CRYPTO_ALG_TYPE_SKCIPHER,229	.ss_algo_id = SS_ID_CIPHER_DES3,230	.ss_blockmode = SS_ID_OP_CBC,231	.alg.skcipher.base = {232		.base = {233			.cra_name = "cbc(des3_ede)",234			.cra_driver_name = "cbc-des3-sun8i-ss",235			.cra_priority = 400,236			.cra_blocksize = DES3_EDE_BLOCK_SIZE,237			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |238				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |239				CRYPTO_ALG_NEED_FALLBACK,240			.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),241			.cra_module = THIS_MODULE,242			.cra_alignmask = 0xf,243			.cra_init = sun8i_ss_cipher_init,244			.cra_exit = sun8i_ss_cipher_exit,245		},246		.min_keysize	= DES3_EDE_KEY_SIZE,247		.max_keysize	= DES3_EDE_KEY_SIZE,248		.ivsize		= DES3_EDE_BLOCK_SIZE,249		.setkey		= sun8i_ss_des3_setkey,250		.encrypt	= sun8i_ss_skencrypt,251		.decrypt	= sun8i_ss_skdecrypt,252	},253	.alg.skcipher.op = {254		.do_one_request = sun8i_ss_handle_cipher_request,255	},256},257{258	.type = CRYPTO_ALG_TYPE_SKCIPHER,259	.ss_algo_id = SS_ID_CIPHER_DES3,260	.ss_blockmode = SS_ID_OP_ECB,261	.alg.skcipher.base = {262		.base = {263			.cra_name = "ecb(des3_ede)",264			.cra_driver_name = "ecb-des3-sun8i-ss",265			.cra_priority = 400,266			.cra_blocksize = DES3_EDE_BLOCK_SIZE,267			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |268				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |269				CRYPTO_ALG_NEED_FALLBACK,270			.cra_ctxsize = sizeof(struct sun8i_cipher_tfm_ctx),271			.cra_module = THIS_MODULE,272			.cra_alignmask = 0xf,273			.cra_init = sun8i_ss_cipher_init,274			.cra_exit = sun8i_ss_cipher_exit,275		},276		.min_keysize	= DES3_EDE_KEY_SIZE,277		.max_keysize	= DES3_EDE_KEY_SIZE,278		.setkey		= sun8i_ss_des3_setkey,279		.encrypt	= sun8i_ss_skencrypt,280		.decrypt	= sun8i_ss_skdecrypt,281	},282	.alg.skcipher.op = {283		.do_one_request = sun8i_ss_handle_cipher_request,284	},285},286#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG287{288	.type = CRYPTO_ALG_TYPE_RNG,289	.alg.rng = {290		.base = {291			.cra_name		= "stdrng",292			.cra_driver_name	= "sun8i-ss-prng",293			.cra_priority		= 300,294			.cra_ctxsize = sizeof(struct sun8i_ss_rng_tfm_ctx),295			.cra_module		= THIS_MODULE,296			.cra_init		= sun8i_ss_prng_init,297			.cra_exit		= sun8i_ss_prng_exit,298		},299		.generate               = sun8i_ss_prng_generate,300		.seed                   = sun8i_ss_prng_seed,301		.seedsize               = PRNG_SEED_SIZE,302	}303},304#endif305#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH306{	.type = CRYPTO_ALG_TYPE_AHASH,307	.ss_algo_id = SS_ID_HASH_MD5,308	.alg.hash.base = {309		.init = sun8i_ss_hash_init,310		.update = sun8i_ss_hash_update,311		.final = sun8i_ss_hash_final,312		.finup = sun8i_ss_hash_finup,313		.digest = sun8i_ss_hash_digest,314		.export = sun8i_ss_hash_export,315		.import = sun8i_ss_hash_import,316		.init_tfm = sun8i_ss_hash_init_tfm,317		.exit_tfm = sun8i_ss_hash_exit_tfm,318		.halg = {319			.digestsize = MD5_DIGEST_SIZE,320			.statesize = sizeof(struct md5_state),321			.base = {322				.cra_name = "md5",323				.cra_driver_name = "md5-sun8i-ss",324				.cra_priority = 300,325				.cra_flags = CRYPTO_ALG_TYPE_AHASH |326					CRYPTO_ALG_ASYNC |327					CRYPTO_ALG_NEED_FALLBACK,328				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,329				.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),330				.cra_module = THIS_MODULE,331			}332		}333	},334	.alg.hash.op = {335		.do_one_request = sun8i_ss_hash_run,336	},337},338{	.type = CRYPTO_ALG_TYPE_AHASH,339	.ss_algo_id = SS_ID_HASH_SHA1,340	.alg.hash.base = {341		.init = sun8i_ss_hash_init,342		.update = sun8i_ss_hash_update,343		.final = sun8i_ss_hash_final,344		.finup = sun8i_ss_hash_finup,345		.digest = sun8i_ss_hash_digest,346		.export = sun8i_ss_hash_export,347		.import = sun8i_ss_hash_import,348		.init_tfm = sun8i_ss_hash_init_tfm,349		.exit_tfm = sun8i_ss_hash_exit_tfm,350		.halg = {351			.digestsize = SHA1_DIGEST_SIZE,352			.statesize = sizeof(struct sha1_state),353			.base = {354				.cra_name = "sha1",355				.cra_driver_name = "sha1-sun8i-ss",356				.cra_priority = 300,357				.cra_flags = CRYPTO_ALG_TYPE_AHASH |358					CRYPTO_ALG_ASYNC |359					CRYPTO_ALG_NEED_FALLBACK,360				.cra_blocksize = SHA1_BLOCK_SIZE,361				.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),362				.cra_module = THIS_MODULE,363			}364		}365	},366	.alg.hash.op = {367		.do_one_request = sun8i_ss_hash_run,368	},369},370{	.type = CRYPTO_ALG_TYPE_AHASH,371	.ss_algo_id = SS_ID_HASH_SHA224,372	.alg.hash.base = {373		.init = sun8i_ss_hash_init,374		.update = sun8i_ss_hash_update,375		.final = sun8i_ss_hash_final,376		.finup = sun8i_ss_hash_finup,377		.digest = sun8i_ss_hash_digest,378		.export = sun8i_ss_hash_export,379		.import = sun8i_ss_hash_import,380		.init_tfm = sun8i_ss_hash_init_tfm,381		.exit_tfm = sun8i_ss_hash_exit_tfm,382		.halg = {383			.digestsize = SHA224_DIGEST_SIZE,384			.statesize = sizeof(struct sha256_state),385			.base = {386				.cra_name = "sha224",387				.cra_driver_name = "sha224-sun8i-ss",388				.cra_priority = 300,389				.cra_flags = CRYPTO_ALG_TYPE_AHASH |390					CRYPTO_ALG_ASYNC |391					CRYPTO_ALG_NEED_FALLBACK,392				.cra_blocksize = SHA224_BLOCK_SIZE,393				.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),394				.cra_module = THIS_MODULE,395			}396		}397	},398	.alg.hash.op = {399		.do_one_request = sun8i_ss_hash_run,400	},401},402{	.type = CRYPTO_ALG_TYPE_AHASH,403	.ss_algo_id = SS_ID_HASH_SHA256,404	.alg.hash.base = {405		.init = sun8i_ss_hash_init,406		.update = sun8i_ss_hash_update,407		.final = sun8i_ss_hash_final,408		.finup = sun8i_ss_hash_finup,409		.digest = sun8i_ss_hash_digest,410		.export = sun8i_ss_hash_export,411		.import = sun8i_ss_hash_import,412		.init_tfm = sun8i_ss_hash_init_tfm,413		.exit_tfm = sun8i_ss_hash_exit_tfm,414		.halg = {415			.digestsize = SHA256_DIGEST_SIZE,416			.statesize = sizeof(struct sha256_state),417			.base = {418				.cra_name = "sha256",419				.cra_driver_name = "sha256-sun8i-ss",420				.cra_priority = 300,421				.cra_flags = CRYPTO_ALG_TYPE_AHASH |422					CRYPTO_ALG_ASYNC |423					CRYPTO_ALG_NEED_FALLBACK,424				.cra_blocksize = SHA256_BLOCK_SIZE,425				.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),426				.cra_module = THIS_MODULE,427			}428		}429	},430	.alg.hash.op = {431		.do_one_request = sun8i_ss_hash_run,432	},433},434{	.type = CRYPTO_ALG_TYPE_AHASH,435	.ss_algo_id = SS_ID_HASH_SHA1,436	.alg.hash.base = {437		.init = sun8i_ss_hash_init,438		.update = sun8i_ss_hash_update,439		.final = sun8i_ss_hash_final,440		.finup = sun8i_ss_hash_finup,441		.digest = sun8i_ss_hash_digest,442		.export = sun8i_ss_hash_export,443		.import = sun8i_ss_hash_import,444		.init_tfm = sun8i_ss_hash_init_tfm,445		.exit_tfm = sun8i_ss_hash_exit_tfm,446		.setkey = sun8i_ss_hmac_setkey,447		.halg = {448			.digestsize = SHA1_DIGEST_SIZE,449			.statesize = sizeof(struct sha1_state),450			.base = {451				.cra_name = "hmac(sha1)",452				.cra_driver_name = "hmac-sha1-sun8i-ss",453				.cra_priority = 300,454				.cra_flags = CRYPTO_ALG_TYPE_AHASH |455					CRYPTO_ALG_ASYNC |456					CRYPTO_ALG_NEED_FALLBACK,457				.cra_blocksize = SHA1_BLOCK_SIZE,458				.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),459				.cra_module = THIS_MODULE,460			}461		}462	},463	.alg.hash.op = {464		.do_one_request = sun8i_ss_hash_run,465	},466},467#endif468};469 470static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)471{472	struct sun8i_ss_dev *ss __maybe_unused = seq->private;473	unsigned int i;474 475	for (i = 0; i < MAXFLOW; i++)476		seq_printf(seq, "Channel %d: nreq %lu\n", i,477#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG478			   ss->flows[i].stat_req);479#else480			   0ul);481#endif482 483	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {484		if (!ss_algs[i].ss)485			continue;486		switch (ss_algs[i].type) {487		case CRYPTO_ALG_TYPE_SKCIPHER:488			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",489				   ss_algs[i].alg.skcipher.base.base.cra_driver_name,490				   ss_algs[i].alg.skcipher.base.base.cra_name,491				   ss_algs[i].stat_req, ss_algs[i].stat_fb);492 493			seq_printf(seq, "\tLast fallback is: %s\n",494				   ss_algs[i].fbname);495			seq_printf(seq, "\tFallback due to length: %lu\n",496				   ss_algs[i].stat_fb_len);497			seq_printf(seq, "\tFallback due to SG length: %lu\n",498				   ss_algs[i].stat_fb_sglen);499			seq_printf(seq, "\tFallback due to alignment: %lu\n",500				   ss_algs[i].stat_fb_align);501			seq_printf(seq, "\tFallback due to SG numbers: %lu\n",502				   ss_algs[i].stat_fb_sgnum);503			break;504		case CRYPTO_ALG_TYPE_RNG:505			seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",506				   ss_algs[i].alg.rng.base.cra_driver_name,507				   ss_algs[i].alg.rng.base.cra_name,508				   ss_algs[i].stat_req, ss_algs[i].stat_bytes);509			break;510		case CRYPTO_ALG_TYPE_AHASH:511			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",512				   ss_algs[i].alg.hash.base.halg.base.cra_driver_name,513				   ss_algs[i].alg.hash.base.halg.base.cra_name,514				   ss_algs[i].stat_req, ss_algs[i].stat_fb);515			seq_printf(seq, "\tLast fallback is: %s\n",516				   ss_algs[i].fbname);517			seq_printf(seq, "\tFallback due to length: %lu\n",518				   ss_algs[i].stat_fb_len);519			seq_printf(seq, "\tFallback due to SG length: %lu\n",520				   ss_algs[i].stat_fb_sglen);521			seq_printf(seq, "\tFallback due to alignment: %lu\n",522				   ss_algs[i].stat_fb_align);523			seq_printf(seq, "\tFallback due to SG numbers: %lu\n",524				   ss_algs[i].stat_fb_sgnum);525			break;526		}527	}528	return 0;529}530 531DEFINE_SHOW_ATTRIBUTE(sun8i_ss_debugfs);532 533static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)534{535	while (i >= 0) {536		crypto_engine_exit(ss->flows[i].engine);537		i--;538	}539}540 541/*542 * Allocate the flow list structure543 */544static int allocate_flows(struct sun8i_ss_dev *ss)545{546	int i, j, err;547 548	ss->flows = devm_kcalloc(ss->dev, MAXFLOW, sizeof(struct sun8i_ss_flow),549				 GFP_KERNEL);550	if (!ss->flows)551		return -ENOMEM;552 553	for (i = 0; i < MAXFLOW; i++) {554		init_completion(&ss->flows[i].complete);555 556		ss->flows[i].biv = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,557						GFP_KERNEL);558		if (!ss->flows[i].biv) {559			err = -ENOMEM;560			goto error_engine;561		}562 563		for (j = 0; j < MAX_SG; j++) {564			ss->flows[i].iv[j] = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,565							  GFP_KERNEL);566			if (!ss->flows[i].iv[j]) {567				err = -ENOMEM;568				goto error_engine;569			}570		}571 572		/* the padding could be up to two block. */573		ss->flows[i].pad = devm_kmalloc(ss->dev, MAX_PAD_SIZE,574						GFP_KERNEL);575		if (!ss->flows[i].pad) {576			err = -ENOMEM;577			goto error_engine;578		}579		ss->flows[i].result =580			devm_kmalloc(ss->dev, max(SHA256_DIGEST_SIZE,581						  dma_get_cache_alignment()),582				     GFP_KERNEL);583		if (!ss->flows[i].result) {584			err = -ENOMEM;585			goto error_engine;586		}587 588		ss->flows[i].engine = crypto_engine_alloc_init(ss->dev, true);589		if (!ss->flows[i].engine) {590			dev_err(ss->dev, "Cannot allocate engine\n");591			i--;592			err = -ENOMEM;593			goto error_engine;594		}595		err = crypto_engine_start(ss->flows[i].engine);596		if (err) {597			dev_err(ss->dev, "Cannot start engine\n");598			goto error_engine;599		}600	}601	return 0;602error_engine:603	sun8i_ss_free_flows(ss, i);604	return err;605}606 607/*608 * Power management strategy: The device is suspended unless a TFM exists for609 * one of the algorithms proposed by this driver.610 */611static int sun8i_ss_pm_suspend(struct device *dev)612{613	struct sun8i_ss_dev *ss = dev_get_drvdata(dev);614	int i;615 616	reset_control_assert(ss->reset);617	for (i = 0; i < SS_MAX_CLOCKS; i++)618		clk_disable_unprepare(ss->ssclks[i]);619	return 0;620}621 622static int sun8i_ss_pm_resume(struct device *dev)623{624	struct sun8i_ss_dev *ss = dev_get_drvdata(dev);625	int err, i;626 627	for (i = 0; i < SS_MAX_CLOCKS; i++) {628		if (!ss->variant->ss_clks[i].name)629			continue;630		err = clk_prepare_enable(ss->ssclks[i]);631		if (err) {632			dev_err(ss->dev, "Cannot prepare_enable %s\n",633				ss->variant->ss_clks[i].name);634			goto error;635		}636	}637	err = reset_control_deassert(ss->reset);638	if (err) {639		dev_err(ss->dev, "Cannot deassert reset control\n");640		goto error;641	}642	/* enable interrupts for all flows */643	writel(BIT(0) | BIT(1), ss->base + SS_INT_CTL_REG);644 645	return 0;646error:647	sun8i_ss_pm_suspend(dev);648	return err;649}650 651static const struct dev_pm_ops sun8i_ss_pm_ops = {652	SET_RUNTIME_PM_OPS(sun8i_ss_pm_suspend, sun8i_ss_pm_resume, NULL)653};654 655static int sun8i_ss_pm_init(struct sun8i_ss_dev *ss)656{657	int err;658 659	pm_runtime_use_autosuspend(ss->dev);660	pm_runtime_set_autosuspend_delay(ss->dev, 2000);661 662	err = pm_runtime_set_suspended(ss->dev);663	if (err)664		return err;665	pm_runtime_enable(ss->dev);666	return err;667}668 669static void sun8i_ss_pm_exit(struct sun8i_ss_dev *ss)670{671	pm_runtime_disable(ss->dev);672}673 674static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)675{676	int ss_method, err, id;677	unsigned int i;678 679	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {680		ss_algs[i].ss = ss;681		switch (ss_algs[i].type) {682		case CRYPTO_ALG_TYPE_SKCIPHER:683			id = ss_algs[i].ss_algo_id;684			ss_method = ss->variant->alg_cipher[id];685			if (ss_method == SS_ID_NOTSUPP) {686				dev_info(ss->dev,687					 "DEBUG: Algo of %s not supported\n",688					 ss_algs[i].alg.skcipher.base.base.cra_name);689				ss_algs[i].ss = NULL;690				break;691			}692			id = ss_algs[i].ss_blockmode;693			ss_method = ss->variant->op_mode[id];694			if (ss_method == SS_ID_NOTSUPP) {695				dev_info(ss->dev, "DEBUG: Blockmode of %s not supported\n",696					 ss_algs[i].alg.skcipher.base.base.cra_name);697				ss_algs[i].ss = NULL;698				break;699			}700			dev_info(ss->dev, "DEBUG: Register %s\n",701				 ss_algs[i].alg.skcipher.base.base.cra_name);702			err = crypto_engine_register_skcipher(&ss_algs[i].alg.skcipher);703			if (err) {704				dev_err(ss->dev, "Fail to register %s\n",705					ss_algs[i].alg.skcipher.base.base.cra_name);706				ss_algs[i].ss = NULL;707				return err;708			}709			break;710		case CRYPTO_ALG_TYPE_RNG:711			err = crypto_register_rng(&ss_algs[i].alg.rng);712			if (err) {713				dev_err(ss->dev, "Fail to register %s\n",714					ss_algs[i].alg.rng.base.cra_name);715				ss_algs[i].ss = NULL;716			}717			break;718		case CRYPTO_ALG_TYPE_AHASH:719			id = ss_algs[i].ss_algo_id;720			ss_method = ss->variant->alg_hash[id];721			if (ss_method == SS_ID_NOTSUPP) {722				dev_info(ss->dev,723					"DEBUG: Algo of %s not supported\n",724					ss_algs[i].alg.hash.base.halg.base.cra_name);725				ss_algs[i].ss = NULL;726				break;727			}728			dev_info(ss->dev, "Register %s\n",729				 ss_algs[i].alg.hash.base.halg.base.cra_name);730			err = crypto_engine_register_ahash(&ss_algs[i].alg.hash);731			if (err) {732				dev_err(ss->dev, "ERROR: Fail to register %s\n",733					ss_algs[i].alg.hash.base.halg.base.cra_name);734				ss_algs[i].ss = NULL;735				return err;736			}737			break;738		default:739			ss_algs[i].ss = NULL;740			dev_err(ss->dev, "ERROR: tried to register an unknown algo\n");741		}742	}743	return 0;744}745 746static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)747{748	unsigned int i;749 750	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {751		if (!ss_algs[i].ss)752			continue;753		switch (ss_algs[i].type) {754		case CRYPTO_ALG_TYPE_SKCIPHER:755			dev_info(ss->dev, "Unregister %d %s\n", i,756				 ss_algs[i].alg.skcipher.base.base.cra_name);757			crypto_engine_unregister_skcipher(&ss_algs[i].alg.skcipher);758			break;759		case CRYPTO_ALG_TYPE_RNG:760			dev_info(ss->dev, "Unregister %d %s\n", i,761				 ss_algs[i].alg.rng.base.cra_name);762			crypto_unregister_rng(&ss_algs[i].alg.rng);763			break;764		case CRYPTO_ALG_TYPE_AHASH:765			dev_info(ss->dev, "Unregister %d %s\n", i,766				 ss_algs[i].alg.hash.base.halg.base.cra_name);767			crypto_engine_unregister_ahash(&ss_algs[i].alg.hash);768			break;769		}770	}771}772 773static int sun8i_ss_get_clks(struct sun8i_ss_dev *ss)774{775	unsigned long cr;776	int err, i;777 778	for (i = 0; i < SS_MAX_CLOCKS; i++) {779		if (!ss->variant->ss_clks[i].name)780			continue;781		ss->ssclks[i] = devm_clk_get(ss->dev, ss->variant->ss_clks[i].name);782		if (IS_ERR(ss->ssclks[i])) {783			err = PTR_ERR(ss->ssclks[i]);784			dev_err(ss->dev, "Cannot get %s SS clock err=%d\n",785				ss->variant->ss_clks[i].name, err);786			return err;787		}788		cr = clk_get_rate(ss->ssclks[i]);789		if (!cr)790			return -EINVAL;791		if (ss->variant->ss_clks[i].freq > 0 &&792		    cr != ss->variant->ss_clks[i].freq) {793			dev_info(ss->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n",794				 ss->variant->ss_clks[i].name,795				 ss->variant->ss_clks[i].freq,796				 ss->variant->ss_clks[i].freq / 1000000,797				 cr, cr / 1000000);798			err = clk_set_rate(ss->ssclks[i], ss->variant->ss_clks[i].freq);799			if (err)800				dev_err(ss->dev, "Fail to set %s clk speed to %lu hz\n",801					ss->variant->ss_clks[i].name,802					ss->variant->ss_clks[i].freq);803		}804		if (ss->variant->ss_clks[i].max_freq > 0 &&805		    cr > ss->variant->ss_clks[i].max_freq)806			dev_warn(ss->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommendation (%lu hz)",807				 ss->variant->ss_clks[i].name, cr,808				 ss->variant->ss_clks[i].max_freq);809	}810	return 0;811}812 813static int sun8i_ss_probe(struct platform_device *pdev)814{815	struct sun8i_ss_dev *ss;816	int err, irq;817	u32 v;818 819	ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);820	if (!ss)821		return -ENOMEM;822 823	ss->dev = &pdev->dev;824	platform_set_drvdata(pdev, ss);825 826	ss->variant = of_device_get_match_data(&pdev->dev);827	if (!ss->variant) {828		dev_err(&pdev->dev, "Missing Crypto Engine variant\n");829		return -EINVAL;830	}831 832	ss->base = devm_platform_ioremap_resource(pdev, 0);833	if (IS_ERR(ss->base))834		return PTR_ERR(ss->base);835 836	err = sun8i_ss_get_clks(ss);837	if (err)838		return err;839 840	irq = platform_get_irq(pdev, 0);841	if (irq < 0)842		return irq;843 844	ss->reset = devm_reset_control_get(&pdev->dev, NULL);845	if (IS_ERR(ss->reset))846		return dev_err_probe(&pdev->dev, PTR_ERR(ss->reset),847				     "No reset control found\n");848 849	mutex_init(&ss->mlock);850 851	err = allocate_flows(ss);852	if (err)853		return err;854 855	err = sun8i_ss_pm_init(ss);856	if (err)857		goto error_pm;858 859	err = devm_request_irq(&pdev->dev, irq, ss_irq_handler, 0, "sun8i-ss", ss);860	if (err) {861		dev_err(ss->dev, "Cannot request SecuritySystem IRQ (err=%d)\n", err);862		goto error_irq;863	}864 865	err = sun8i_ss_register_algs(ss);866	if (err)867		goto error_alg;868 869	err = pm_runtime_resume_and_get(ss->dev);870	if (err < 0)871		goto error_alg;872 873	v = readl(ss->base + SS_CTL_REG);874	v >>= SS_DIE_ID_SHIFT;875	v &= SS_DIE_ID_MASK;876	dev_info(&pdev->dev, "Security System Die ID %x\n", v);877 878	pm_runtime_put_sync(ss->dev);879 880	if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {881		struct dentry *dbgfs_dir __maybe_unused;882		struct dentry *dbgfs_stats __maybe_unused;883 884		/* Ignore error of debugfs */885		dbgfs_dir = debugfs_create_dir("sun8i-ss", NULL);886		dbgfs_stats = debugfs_create_file("stats", 0444,887						   dbgfs_dir, ss,888						   &sun8i_ss_debugfs_fops);889 890#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG891		ss->dbgfs_dir = dbgfs_dir;892		ss->dbgfs_stats = dbgfs_stats;893#endif894	}895 896	return 0;897error_alg:898	sun8i_ss_unregister_algs(ss);899error_irq:900	sun8i_ss_pm_exit(ss);901error_pm:902	sun8i_ss_free_flows(ss, MAXFLOW - 1);903	return err;904}905 906static void sun8i_ss_remove(struct platform_device *pdev)907{908	struct sun8i_ss_dev *ss = platform_get_drvdata(pdev);909 910	sun8i_ss_unregister_algs(ss);911 912#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG913	debugfs_remove_recursive(ss->dbgfs_dir);914#endif915 916	sun8i_ss_free_flows(ss, MAXFLOW - 1);917 918	sun8i_ss_pm_exit(ss);919}920 921static const struct of_device_id sun8i_ss_crypto_of_match_table[] = {922	{ .compatible = "allwinner,sun8i-a83t-crypto",923	  .data = &ss_a83t_variant },924	{ .compatible = "allwinner,sun9i-a80-crypto",925	  .data = &ss_a80_variant },926	{}927};928MODULE_DEVICE_TABLE(of, sun8i_ss_crypto_of_match_table);929 930static struct platform_driver sun8i_ss_driver = {931	.probe		 = sun8i_ss_probe,932	.remove_new	 = sun8i_ss_remove,933	.driver		 = {934		.name		= "sun8i-ss",935		.pm             = &sun8i_ss_pm_ops,936		.of_match_table	= sun8i_ss_crypto_of_match_table,937	},938};939 940module_platform_driver(sun8i_ss_driver);941 942MODULE_DESCRIPTION("Allwinner SecuritySystem cryptographic offloader");943MODULE_LICENSE("GPL");944MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>");945