162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) 2012-2019 ARM Limited or its affiliates. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/crypto.h>
862306a36Sopenharmony_ci#include <linux/moduleparam.h>
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "cc_driver.h"
2062306a36Sopenharmony_ci#include "cc_request_mgr.h"
2162306a36Sopenharmony_ci#include "cc_buffer_mgr.h"
2262306a36Sopenharmony_ci#include "cc_debugfs.h"
2362306a36Sopenharmony_ci#include "cc_cipher.h"
2462306a36Sopenharmony_ci#include "cc_aead.h"
2562306a36Sopenharmony_ci#include "cc_hash.h"
2662306a36Sopenharmony_ci#include "cc_sram_mgr.h"
2762306a36Sopenharmony_ci#include "cc_pm.h"
2862306a36Sopenharmony_ci#include "cc_fips.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cibool cc_dump_desc;
3162306a36Sopenharmony_cimodule_param_named(dump_desc, cc_dump_desc, bool, 0600);
3262306a36Sopenharmony_ciMODULE_PARM_DESC(cc_dump_desc, "Dump descriptors to kernel log as debugging aid");
3362306a36Sopenharmony_cibool cc_dump_bytes;
3462306a36Sopenharmony_cimodule_param_named(dump_bytes, cc_dump_bytes, bool, 0600);
3562306a36Sopenharmony_ciMODULE_PARM_DESC(cc_dump_bytes, "Dump buffers to kernel log as debugging aid");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic bool cc_sec_disable;
3862306a36Sopenharmony_cimodule_param_named(sec_disable, cc_sec_disable, bool, 0600);
3962306a36Sopenharmony_ciMODULE_PARM_DESC(cc_sec_disable, "Disable security functions");
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistruct cc_hw_data {
4262306a36Sopenharmony_ci	char *name;
4362306a36Sopenharmony_ci	enum cc_hw_rev rev;
4462306a36Sopenharmony_ci	u32 sig;
4562306a36Sopenharmony_ci	u32 cidr_0123;
4662306a36Sopenharmony_ci	u32 pidr_0124;
4762306a36Sopenharmony_ci	int std_bodies;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define CC_NUM_IDRS 4
5162306a36Sopenharmony_ci#define CC_HW_RESET_LOOP_COUNT 10
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Note: PIDR3 holds CMOD/Rev so ignored for HW identification purposes */
5462306a36Sopenharmony_cistatic const u32 pidr_0124_offsets[CC_NUM_IDRS] = {
5562306a36Sopenharmony_ci	CC_REG(PERIPHERAL_ID_0), CC_REG(PERIPHERAL_ID_1),
5662306a36Sopenharmony_ci	CC_REG(PERIPHERAL_ID_2), CC_REG(PERIPHERAL_ID_4)
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const u32 cidr_0123_offsets[CC_NUM_IDRS] = {
6062306a36Sopenharmony_ci	CC_REG(COMPONENT_ID_0), CC_REG(COMPONENT_ID_1),
6162306a36Sopenharmony_ci	CC_REG(COMPONENT_ID_2), CC_REG(COMPONENT_ID_3)
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Hardware revisions defs. */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* The 703 is a OSCCA only variant of the 713 */
6762306a36Sopenharmony_cistatic const struct cc_hw_data cc703_hw = {
6862306a36Sopenharmony_ci	.name = "703", .rev = CC_HW_REV_713, .cidr_0123 = 0xB105F00DU,
6962306a36Sopenharmony_ci	.pidr_0124 = 0x040BB0D0U, .std_bodies = CC_STD_OSCCA
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic const struct cc_hw_data cc713_hw = {
7362306a36Sopenharmony_ci	.name = "713", .rev = CC_HW_REV_713, .cidr_0123 = 0xB105F00DU,
7462306a36Sopenharmony_ci	.pidr_0124 = 0x040BB0D0U, .std_bodies = CC_STD_ALL
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct cc_hw_data cc712_hw = {
7862306a36Sopenharmony_ci	.name = "712", .rev = CC_HW_REV_712, .sig =  0xDCC71200U,
7962306a36Sopenharmony_ci	.std_bodies = CC_STD_ALL
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic const struct cc_hw_data cc710_hw = {
8362306a36Sopenharmony_ci	.name = "710", .rev = CC_HW_REV_710, .sig =  0xDCC63200U,
8462306a36Sopenharmony_ci	.std_bodies = CC_STD_ALL
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic const struct cc_hw_data cc630p_hw = {
8862306a36Sopenharmony_ci	.name = "630P", .rev = CC_HW_REV_630, .sig = 0xDCC63000U,
8962306a36Sopenharmony_ci	.std_bodies = CC_STD_ALL
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const struct of_device_id arm_ccree_dev_of_match[] = {
9362306a36Sopenharmony_ci	{ .compatible = "arm,cryptocell-703-ree", .data = &cc703_hw },
9462306a36Sopenharmony_ci	{ .compatible = "arm,cryptocell-713-ree", .data = &cc713_hw },
9562306a36Sopenharmony_ci	{ .compatible = "arm,cryptocell-712-ree", .data = &cc712_hw },
9662306a36Sopenharmony_ci	{ .compatible = "arm,cryptocell-710-ree", .data = &cc710_hw },
9762306a36Sopenharmony_ci	{ .compatible = "arm,cryptocell-630p-ree", .data = &cc630p_hw },
9862306a36Sopenharmony_ci	{}
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, arm_ccree_dev_of_match);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void init_cc_cache_params(struct cc_drvdata *drvdata)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct device *dev = drvdata_to_dev(drvdata);
10562306a36Sopenharmony_ci	u32 cache_params, ace_const, val;
10662306a36Sopenharmony_ci	u64 mask;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* compute CC_AXIM_CACHE_PARAMS */
10962306a36Sopenharmony_ci	cache_params = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS));
11062306a36Sopenharmony_ci	dev_dbg(dev, "Cache params previous: 0x%08X\n", cache_params);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* non cached or write-back, write allocate */
11362306a36Sopenharmony_ci	val = drvdata->coherent ? 0xb : 0x2;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	mask = CC_GENMASK(CC_AXIM_CACHE_PARAMS_AWCACHE);
11662306a36Sopenharmony_ci	cache_params &= ~mask;
11762306a36Sopenharmony_ci	cache_params |= FIELD_PREP(mask, val);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	mask = CC_GENMASK(CC_AXIM_CACHE_PARAMS_AWCACHE_LAST);
12062306a36Sopenharmony_ci	cache_params &= ~mask;
12162306a36Sopenharmony_ci	cache_params |= FIELD_PREP(mask, val);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	mask = CC_GENMASK(CC_AXIM_CACHE_PARAMS_ARCACHE);
12462306a36Sopenharmony_ci	cache_params &= ~mask;
12562306a36Sopenharmony_ci	cache_params |= FIELD_PREP(mask, val);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	drvdata->cache_params = cache_params;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	dev_dbg(dev, "Cache params current: 0x%08X\n", cache_params);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (drvdata->hw_rev <= CC_HW_REV_710)
13262306a36Sopenharmony_ci		return;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* compute CC_AXIM_ACE_CONST */
13562306a36Sopenharmony_ci	ace_const = cc_ioread(drvdata, CC_REG(AXIM_ACE_CONST));
13662306a36Sopenharmony_ci	dev_dbg(dev, "ACE-const previous: 0x%08X\n", ace_const);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* system or outer-sharable */
13962306a36Sopenharmony_ci	val = drvdata->coherent ? 0x2 : 0x3;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	mask = CC_GENMASK(CC_AXIM_ACE_CONST_ARDOMAIN);
14262306a36Sopenharmony_ci	ace_const &= ~mask;
14362306a36Sopenharmony_ci	ace_const |= FIELD_PREP(mask, val);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	mask = CC_GENMASK(CC_AXIM_ACE_CONST_AWDOMAIN);
14662306a36Sopenharmony_ci	ace_const &= ~mask;
14762306a36Sopenharmony_ci	ace_const |= FIELD_PREP(mask, val);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	dev_dbg(dev, "ACE-const current: 0x%08X\n", ace_const);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	drvdata->ace_const = ace_const;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic u32 cc_read_idr(struct cc_drvdata *drvdata, const u32 *idr_offsets)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	int i;
15762306a36Sopenharmony_ci	union {
15862306a36Sopenharmony_ci		u8 regs[CC_NUM_IDRS];
15962306a36Sopenharmony_ci		__le32 val;
16062306a36Sopenharmony_ci	} idr;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	for (i = 0; i < CC_NUM_IDRS; ++i)
16362306a36Sopenharmony_ci		idr.regs[i] = cc_ioread(drvdata, idr_offsets[i]);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return le32_to_cpu(idr.val);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_civoid __dump_byte_array(const char *name, const u8 *buf, size_t len)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	char prefix[64];
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!buf)
17362306a36Sopenharmony_ci		return;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	snprintf(prefix, sizeof(prefix), "%s[%zu]: ", name, len);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_ADDRESS, 16, 1, buf,
17862306a36Sopenharmony_ci		       len, false);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic irqreturn_t cc_isr(int irq, void *dev_id)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct cc_drvdata *drvdata = (struct cc_drvdata *)dev_id;
18462306a36Sopenharmony_ci	struct device *dev = drvdata_to_dev(drvdata);
18562306a36Sopenharmony_ci	u32 irr;
18662306a36Sopenharmony_ci	u32 imr;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */
18962306a36Sopenharmony_ci	/* if driver suspended return, probably shared interrupt */
19062306a36Sopenharmony_ci	if (pm_runtime_suspended(dev))
19162306a36Sopenharmony_ci		return IRQ_NONE;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* read the interrupt status */
19462306a36Sopenharmony_ci	irr = cc_ioread(drvdata, CC_REG(HOST_IRR));
19562306a36Sopenharmony_ci	dev_dbg(dev, "Got IRR=0x%08X\n", irr);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (irr == 0) /* Probably shared interrupt line */
19862306a36Sopenharmony_ci		return IRQ_NONE;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	imr = cc_ioread(drvdata, CC_REG(HOST_IMR));
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* clear interrupt - must be before processing events */
20362306a36Sopenharmony_ci	cc_iowrite(drvdata, CC_REG(HOST_ICR), irr);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	drvdata->irq = irr;
20662306a36Sopenharmony_ci	/* Completion interrupt - most probable */
20762306a36Sopenharmony_ci	if (irr & drvdata->comp_mask) {
20862306a36Sopenharmony_ci		/* Mask all completion interrupts - will be unmasked in
20962306a36Sopenharmony_ci		 * deferred service handler
21062306a36Sopenharmony_ci		 */
21162306a36Sopenharmony_ci		cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | drvdata->comp_mask);
21262306a36Sopenharmony_ci		irr &= ~drvdata->comp_mask;
21362306a36Sopenharmony_ci		complete_request(drvdata);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_FIPS
21662306a36Sopenharmony_ci	/* TEE FIPS interrupt */
21762306a36Sopenharmony_ci	if (irr & CC_GPR0_IRQ_MASK) {
21862306a36Sopenharmony_ci		/* Mask interrupt - will be unmasked in Deferred service
21962306a36Sopenharmony_ci		 * handler
22062306a36Sopenharmony_ci		 */
22162306a36Sopenharmony_ci		cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_GPR0_IRQ_MASK);
22262306a36Sopenharmony_ci		irr &= ~CC_GPR0_IRQ_MASK;
22362306a36Sopenharmony_ci		fips_handler(drvdata);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci#endif
22662306a36Sopenharmony_ci	/* AXI error interrupt */
22762306a36Sopenharmony_ci	if (irr & CC_AXI_ERR_IRQ_MASK) {
22862306a36Sopenharmony_ci		u32 axi_err;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		/* Read the AXI error ID */
23162306a36Sopenharmony_ci		axi_err = cc_ioread(drvdata, CC_REG(AXIM_MON_ERR));
23262306a36Sopenharmony_ci		dev_dbg(dev, "AXI completion error: axim_mon_err=0x%08X\n",
23362306a36Sopenharmony_ci			axi_err);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		irr &= ~CC_AXI_ERR_IRQ_MASK;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (irr) {
23962306a36Sopenharmony_ci		dev_dbg_ratelimited(dev, "IRR includes unknown cause bits (0x%08X)\n",
24062306a36Sopenharmony_ci				    irr);
24162306a36Sopenharmony_ci		/* Just warning */
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return IRQ_HANDLED;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cibool cc_wait_for_reset_completion(struct cc_drvdata *drvdata)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	unsigned int val;
25062306a36Sopenharmony_ci	unsigned int i;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/* 712/710/63 has no reset completion indication, always return true */
25362306a36Sopenharmony_ci	if (drvdata->hw_rev <= CC_HW_REV_712)
25462306a36Sopenharmony_ci		return true;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	for (i = 0; i < CC_HW_RESET_LOOP_COUNT; i++) {
25762306a36Sopenharmony_ci		/* in cc7x3 NVM_IS_IDLE indicates that CC reset is
25862306a36Sopenharmony_ci		 *  completed and device is fully functional
25962306a36Sopenharmony_ci		 */
26062306a36Sopenharmony_ci		val = cc_ioread(drvdata, CC_REG(NVM_IS_IDLE));
26162306a36Sopenharmony_ci		if (val & CC_NVM_IS_IDLE_MASK) {
26262306a36Sopenharmony_ci			/* hw indicate reset completed */
26362306a36Sopenharmony_ci			return true;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci		/* allow scheduling other process on the processor */
26662306a36Sopenharmony_ci		schedule();
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	/* reset not completed */
26962306a36Sopenharmony_ci	return false;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciint init_cc_regs(struct cc_drvdata *drvdata)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	unsigned int val;
27562306a36Sopenharmony_ci	struct device *dev = drvdata_to_dev(drvdata);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Unmask all AXI interrupt sources AXI_CFG1 register   */
27862306a36Sopenharmony_ci	/* AXI interrupt config are obsoleted startign at cc7x3 */
27962306a36Sopenharmony_ci	if (drvdata->hw_rev <= CC_HW_REV_712) {
28062306a36Sopenharmony_ci		val = cc_ioread(drvdata, CC_REG(AXIM_CFG));
28162306a36Sopenharmony_ci		cc_iowrite(drvdata, CC_REG(AXIM_CFG), val & ~CC_AXI_IRQ_MASK);
28262306a36Sopenharmony_ci		dev_dbg(dev, "AXIM_CFG=0x%08X\n",
28362306a36Sopenharmony_ci			cc_ioread(drvdata, CC_REG(AXIM_CFG)));
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Clear all pending interrupts */
28762306a36Sopenharmony_ci	val = cc_ioread(drvdata, CC_REG(HOST_IRR));
28862306a36Sopenharmony_ci	dev_dbg(dev, "IRR=0x%08X\n", val);
28962306a36Sopenharmony_ci	cc_iowrite(drvdata, CC_REG(HOST_ICR), val);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* Unmask relevant interrupt cause */
29262306a36Sopenharmony_ci	val = drvdata->comp_mask | CC_AXI_ERR_IRQ_MASK;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (drvdata->hw_rev >= CC_HW_REV_712)
29562306a36Sopenharmony_ci		val |= CC_GPR0_IRQ_MASK;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	cc_iowrite(drvdata, CC_REG(HOST_IMR), ~val);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	cc_iowrite(drvdata, CC_REG(AXIM_CACHE_PARAMS), drvdata->cache_params);
30062306a36Sopenharmony_ci	if (drvdata->hw_rev >= CC_HW_REV_712)
30162306a36Sopenharmony_ci		cc_iowrite(drvdata, CC_REG(AXIM_ACE_CONST), drvdata->ace_const);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return 0;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic int init_cc_resources(struct platform_device *plat_dev)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct resource *req_mem_cc_regs = NULL;
30962306a36Sopenharmony_ci	struct cc_drvdata *new_drvdata;
31062306a36Sopenharmony_ci	struct device *dev = &plat_dev->dev;
31162306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
31262306a36Sopenharmony_ci	u32 val, hw_rev_pidr, sig_cidr;
31362306a36Sopenharmony_ci	u64 dma_mask;
31462306a36Sopenharmony_ci	const struct cc_hw_data *hw_rev;
31562306a36Sopenharmony_ci	struct clk *clk;
31662306a36Sopenharmony_ci	int irq;
31762306a36Sopenharmony_ci	int rc = 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL);
32062306a36Sopenharmony_ci	if (!new_drvdata)
32162306a36Sopenharmony_ci		return -ENOMEM;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	hw_rev = of_device_get_match_data(dev);
32462306a36Sopenharmony_ci	new_drvdata->hw_rev_name = hw_rev->name;
32562306a36Sopenharmony_ci	new_drvdata->hw_rev = hw_rev->rev;
32662306a36Sopenharmony_ci	new_drvdata->std_bodies = hw_rev->std_bodies;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (hw_rev->rev >= CC_HW_REV_712) {
32962306a36Sopenharmony_ci		new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP);
33062306a36Sopenharmony_ci		new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_712);
33162306a36Sopenharmony_ci		new_drvdata->ver_offset = CC_REG(HOST_VERSION_712);
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP8);
33462306a36Sopenharmony_ci		new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_630);
33562306a36Sopenharmony_ci		new_drvdata->ver_offset = CC_REG(HOST_VERSION_630);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	new_drvdata->comp_mask = CC_COMP_IRQ_MASK;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	platform_set_drvdata(plat_dev, new_drvdata);
34162306a36Sopenharmony_ci	new_drvdata->plat_dev = plat_dev;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	clk = devm_clk_get_optional(dev, NULL);
34462306a36Sopenharmony_ci	if (IS_ERR(clk))
34562306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(clk), "Error getting clock\n");
34662306a36Sopenharmony_ci	new_drvdata->clk = clk;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	new_drvdata->coherent = of_dma_is_coherent(np);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* Get device resources */
35162306a36Sopenharmony_ci	/* First CC registers space */
35262306a36Sopenharmony_ci	/* Map registers space */
35362306a36Sopenharmony_ci	new_drvdata->cc_base = devm_platform_get_and_ioremap_resource(plat_dev,
35462306a36Sopenharmony_ci								      0, &req_mem_cc_regs);
35562306a36Sopenharmony_ci	if (IS_ERR(new_drvdata->cc_base))
35662306a36Sopenharmony_ci		return PTR_ERR(new_drvdata->cc_base);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name,
35962306a36Sopenharmony_ci		req_mem_cc_regs);
36062306a36Sopenharmony_ci	dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n",
36162306a36Sopenharmony_ci		&req_mem_cc_regs->start, new_drvdata->cc_base);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Then IRQ */
36462306a36Sopenharmony_ci	irq = platform_get_irq(plat_dev, 0);
36562306a36Sopenharmony_ci	if (irq < 0)
36662306a36Sopenharmony_ci		return irq;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	init_completion(&new_drvdata->hw_queue_avail);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (!dev->dma_mask)
37162306a36Sopenharmony_ci		dev->dma_mask = &dev->coherent_dma_mask;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN);
37462306a36Sopenharmony_ci	rc = dma_set_coherent_mask(dev, dma_mask);
37562306a36Sopenharmony_ci	if (rc) {
37662306a36Sopenharmony_ci		dev_err(dev, "Failed in dma_set_coherent_mask, mask=%llx\n",
37762306a36Sopenharmony_ci			dma_mask);
37862306a36Sopenharmony_ci		return rc;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	rc = clk_prepare_enable(new_drvdata->clk);
38262306a36Sopenharmony_ci	if (rc) {
38362306a36Sopenharmony_ci		dev_err(dev, "Failed to enable clock");
38462306a36Sopenharmony_ci		return rc;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	new_drvdata->sec_disabled = cc_sec_disable;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
39062306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
39162306a36Sopenharmony_ci	pm_runtime_set_active(dev);
39262306a36Sopenharmony_ci	pm_runtime_enable(dev);
39362306a36Sopenharmony_ci	rc = pm_runtime_get_sync(dev);
39462306a36Sopenharmony_ci	if (rc < 0) {
39562306a36Sopenharmony_ci		dev_err(dev, "pm_runtime_get_sync() failed: %d\n", rc);
39662306a36Sopenharmony_ci		goto post_pm_err;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Wait for Cryptocell reset completion */
40062306a36Sopenharmony_ci	if (!cc_wait_for_reset_completion(new_drvdata)) {
40162306a36Sopenharmony_ci		dev_err(dev, "Cryptocell reset not completed");
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (hw_rev->rev <= CC_HW_REV_712) {
40562306a36Sopenharmony_ci		/* Verify correct mapping */
40662306a36Sopenharmony_ci		val = cc_ioread(new_drvdata, new_drvdata->sig_offset);
40762306a36Sopenharmony_ci		if (val != hw_rev->sig) {
40862306a36Sopenharmony_ci			dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n",
40962306a36Sopenharmony_ci				val, hw_rev->sig);
41062306a36Sopenharmony_ci			rc = -EINVAL;
41162306a36Sopenharmony_ci			goto post_pm_err;
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci		sig_cidr = val;
41462306a36Sopenharmony_ci		hw_rev_pidr = cc_ioread(new_drvdata, new_drvdata->ver_offset);
41562306a36Sopenharmony_ci	} else {
41662306a36Sopenharmony_ci		/* Verify correct mapping */
41762306a36Sopenharmony_ci		val = cc_read_idr(new_drvdata, pidr_0124_offsets);
41862306a36Sopenharmony_ci		if (val != hw_rev->pidr_0124) {
41962306a36Sopenharmony_ci			dev_err(dev, "Invalid CC PIDR: PIDR0124=0x%08X != expected=0x%08X\n",
42062306a36Sopenharmony_ci				val,  hw_rev->pidr_0124);
42162306a36Sopenharmony_ci			rc = -EINVAL;
42262306a36Sopenharmony_ci			goto post_pm_err;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci		hw_rev_pidr = val;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		val = cc_read_idr(new_drvdata, cidr_0123_offsets);
42762306a36Sopenharmony_ci		if (val != hw_rev->cidr_0123) {
42862306a36Sopenharmony_ci			dev_err(dev, "Invalid CC CIDR: CIDR0123=0x%08X != expected=0x%08X\n",
42962306a36Sopenharmony_ci			val,  hw_rev->cidr_0123);
43062306a36Sopenharmony_ci			rc = -EINVAL;
43162306a36Sopenharmony_ci			goto post_pm_err;
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci		sig_cidr = val;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		/* Check HW engine configuration */
43662306a36Sopenharmony_ci		val = cc_ioread(new_drvdata, CC_REG(HOST_REMOVE_INPUT_PINS));
43762306a36Sopenharmony_ci		switch (val) {
43862306a36Sopenharmony_ci		case CC_PINS_FULL:
43962306a36Sopenharmony_ci			/* This is fine */
44062306a36Sopenharmony_ci			break;
44162306a36Sopenharmony_ci		case CC_PINS_SLIM:
44262306a36Sopenharmony_ci			if (new_drvdata->std_bodies & CC_STD_NIST) {
44362306a36Sopenharmony_ci				dev_warn(dev, "703 mode forced due to HW configuration.\n");
44462306a36Sopenharmony_ci				new_drvdata->std_bodies = CC_STD_OSCCA;
44562306a36Sopenharmony_ci			}
44662306a36Sopenharmony_ci			break;
44762306a36Sopenharmony_ci		default:
44862306a36Sopenharmony_ci			dev_err(dev, "Unsupported engines configuration.\n");
44962306a36Sopenharmony_ci			rc = -EINVAL;
45062306a36Sopenharmony_ci			goto post_pm_err;
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		/* Check security disable state */
45462306a36Sopenharmony_ci		val = cc_ioread(new_drvdata, CC_REG(SECURITY_DISABLED));
45562306a36Sopenharmony_ci		val &= CC_SECURITY_DISABLED_MASK;
45662306a36Sopenharmony_ci		new_drvdata->sec_disabled |= !!val;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		if (!new_drvdata->sec_disabled) {
45962306a36Sopenharmony_ci			new_drvdata->comp_mask |= CC_CPP_SM4_ABORT_MASK;
46062306a36Sopenharmony_ci			if (new_drvdata->std_bodies & CC_STD_NIST)
46162306a36Sopenharmony_ci				new_drvdata->comp_mask |= CC_CPP_AES_ABORT_MASK;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (new_drvdata->sec_disabled)
46662306a36Sopenharmony_ci		dev_info(dev, "Security Disabled mode is in effect. Security functions disabled.\n");
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* Display HW versions */
46962306a36Sopenharmony_ci	dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X/0x%8X, Driver version %s\n",
47062306a36Sopenharmony_ci		 hw_rev->name, hw_rev_pidr, sig_cidr, DRV_MODULE_VERSION);
47162306a36Sopenharmony_ci	/* register the driver isr function */
47262306a36Sopenharmony_ci	rc = devm_request_irq(dev, irq, cc_isr, IRQF_SHARED, "ccree",
47362306a36Sopenharmony_ci			      new_drvdata);
47462306a36Sopenharmony_ci	if (rc) {
47562306a36Sopenharmony_ci		dev_err(dev, "Could not register to interrupt %d\n", irq);
47662306a36Sopenharmony_ci		goto post_pm_err;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	dev_dbg(dev, "Registered to IRQ: %d\n", irq);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	init_cc_cache_params(new_drvdata);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	rc = init_cc_regs(new_drvdata);
48362306a36Sopenharmony_ci	if (rc) {
48462306a36Sopenharmony_ci		dev_err(dev, "init_cc_regs failed\n");
48562306a36Sopenharmony_ci		goto post_pm_err;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	rc = cc_debugfs_init(new_drvdata);
48962306a36Sopenharmony_ci	if (rc) {
49062306a36Sopenharmony_ci		dev_err(dev, "Failed registering debugfs interface\n");
49162306a36Sopenharmony_ci		goto post_regs_err;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	rc = cc_fips_init(new_drvdata);
49562306a36Sopenharmony_ci	if (rc) {
49662306a36Sopenharmony_ci		dev_err(dev, "cc_fips_init failed 0x%x\n", rc);
49762306a36Sopenharmony_ci		goto post_debugfs_err;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci	rc = cc_sram_mgr_init(new_drvdata);
50062306a36Sopenharmony_ci	if (rc) {
50162306a36Sopenharmony_ci		dev_err(dev, "cc_sram_mgr_init failed\n");
50262306a36Sopenharmony_ci		goto post_fips_init_err;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	new_drvdata->mlli_sram_addr =
50662306a36Sopenharmony_ci		cc_sram_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE);
50762306a36Sopenharmony_ci	if (new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR) {
50862306a36Sopenharmony_ci		rc = -ENOMEM;
50962306a36Sopenharmony_ci		goto post_fips_init_err;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	rc = cc_req_mgr_init(new_drvdata);
51362306a36Sopenharmony_ci	if (rc) {
51462306a36Sopenharmony_ci		dev_err(dev, "cc_req_mgr_init failed\n");
51562306a36Sopenharmony_ci		goto post_fips_init_err;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	rc = cc_buffer_mgr_init(new_drvdata);
51962306a36Sopenharmony_ci	if (rc) {
52062306a36Sopenharmony_ci		dev_err(dev, "cc_buffer_mgr_init failed\n");
52162306a36Sopenharmony_ci		goto post_req_mgr_err;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* hash must be allocated first due to use of send_request_init()
52562306a36Sopenharmony_ci	 * and dependency of AEAD on it
52662306a36Sopenharmony_ci	 */
52762306a36Sopenharmony_ci	rc = cc_hash_alloc(new_drvdata);
52862306a36Sopenharmony_ci	if (rc) {
52962306a36Sopenharmony_ci		dev_err(dev, "cc_hash_alloc failed\n");
53062306a36Sopenharmony_ci		goto post_buf_mgr_err;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Allocate crypto algs */
53462306a36Sopenharmony_ci	rc = cc_cipher_alloc(new_drvdata);
53562306a36Sopenharmony_ci	if (rc) {
53662306a36Sopenharmony_ci		dev_err(dev, "cc_cipher_alloc failed\n");
53762306a36Sopenharmony_ci		goto post_hash_err;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	rc = cc_aead_alloc(new_drvdata);
54162306a36Sopenharmony_ci	if (rc) {
54262306a36Sopenharmony_ci		dev_err(dev, "cc_aead_alloc failed\n");
54362306a36Sopenharmony_ci		goto post_cipher_err;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/* If we got here and FIPS mode is enabled
54762306a36Sopenharmony_ci	 * it means all FIPS test passed, so let TEE
54862306a36Sopenharmony_ci	 * know we're good.
54962306a36Sopenharmony_ci	 */
55062306a36Sopenharmony_ci	cc_set_ree_fips_status(new_drvdata, true);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	pm_runtime_put(dev);
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cipost_cipher_err:
55662306a36Sopenharmony_ci	cc_cipher_free(new_drvdata);
55762306a36Sopenharmony_cipost_hash_err:
55862306a36Sopenharmony_ci	cc_hash_free(new_drvdata);
55962306a36Sopenharmony_cipost_buf_mgr_err:
56062306a36Sopenharmony_ci	 cc_buffer_mgr_fini(new_drvdata);
56162306a36Sopenharmony_cipost_req_mgr_err:
56262306a36Sopenharmony_ci	cc_req_mgr_fini(new_drvdata);
56362306a36Sopenharmony_cipost_fips_init_err:
56462306a36Sopenharmony_ci	cc_fips_fini(new_drvdata);
56562306a36Sopenharmony_cipost_debugfs_err:
56662306a36Sopenharmony_ci	cc_debugfs_fini(new_drvdata);
56762306a36Sopenharmony_cipost_regs_err:
56862306a36Sopenharmony_ci	fini_cc_regs(new_drvdata);
56962306a36Sopenharmony_cipost_pm_err:
57062306a36Sopenharmony_ci	pm_runtime_put_noidle(dev);
57162306a36Sopenharmony_ci	pm_runtime_disable(dev);
57262306a36Sopenharmony_ci	pm_runtime_set_suspended(dev);
57362306a36Sopenharmony_ci	clk_disable_unprepare(new_drvdata->clk);
57462306a36Sopenharmony_ci	return rc;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_civoid fini_cc_regs(struct cc_drvdata *drvdata)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	/* Mask all interrupts */
58062306a36Sopenharmony_ci	cc_iowrite(drvdata, CC_REG(HOST_IMR), 0xFFFFFFFF);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic void cleanup_cc_resources(struct platform_device *plat_dev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct device *dev = &plat_dev->dev;
58662306a36Sopenharmony_ci	struct cc_drvdata *drvdata =
58762306a36Sopenharmony_ci		(struct cc_drvdata *)platform_get_drvdata(plat_dev);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	cc_aead_free(drvdata);
59062306a36Sopenharmony_ci	cc_cipher_free(drvdata);
59162306a36Sopenharmony_ci	cc_hash_free(drvdata);
59262306a36Sopenharmony_ci	cc_buffer_mgr_fini(drvdata);
59362306a36Sopenharmony_ci	cc_req_mgr_fini(drvdata);
59462306a36Sopenharmony_ci	cc_fips_fini(drvdata);
59562306a36Sopenharmony_ci	cc_debugfs_fini(drvdata);
59662306a36Sopenharmony_ci	fini_cc_regs(drvdata);
59762306a36Sopenharmony_ci	pm_runtime_put_noidle(dev);
59862306a36Sopenharmony_ci	pm_runtime_disable(dev);
59962306a36Sopenharmony_ci	pm_runtime_set_suspended(dev);
60062306a36Sopenharmony_ci	clk_disable_unprepare(drvdata->clk);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ciunsigned int cc_get_default_hash_len(struct cc_drvdata *drvdata)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	if (drvdata->hw_rev >= CC_HW_REV_712)
60662306a36Sopenharmony_ci		return HASH_LEN_SIZE_712;
60762306a36Sopenharmony_ci	else
60862306a36Sopenharmony_ci		return HASH_LEN_SIZE_630;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic int ccree_probe(struct platform_device *plat_dev)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	int rc;
61462306a36Sopenharmony_ci	struct device *dev = &plat_dev->dev;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Map registers space */
61762306a36Sopenharmony_ci	rc = init_cc_resources(plat_dev);
61862306a36Sopenharmony_ci	if (rc)
61962306a36Sopenharmony_ci		return rc;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	dev_info(dev, "ARM ccree device initialized\n");
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int ccree_remove(struct platform_device *plat_dev)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct device *dev = &plat_dev->dev;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	dev_dbg(dev, "Releasing ccree resources...\n");
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	cleanup_cc_resources(plat_dev);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	dev_info(dev, "ARM ccree device terminated\n");
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	return 0;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic struct platform_driver ccree_driver = {
64062306a36Sopenharmony_ci	.driver = {
64162306a36Sopenharmony_ci		   .name = "ccree",
64262306a36Sopenharmony_ci		   .of_match_table = arm_ccree_dev_of_match,
64362306a36Sopenharmony_ci#ifdef CONFIG_PM
64462306a36Sopenharmony_ci		   .pm = &ccree_pm,
64562306a36Sopenharmony_ci#endif
64662306a36Sopenharmony_ci	},
64762306a36Sopenharmony_ci	.probe = ccree_probe,
64862306a36Sopenharmony_ci	.remove = ccree_remove,
64962306a36Sopenharmony_ci};
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int __init ccree_init(void)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	int rc;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	cc_debugfs_global_init();
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	rc = platform_driver_register(&ccree_driver);
65862306a36Sopenharmony_ci	if (rc) {
65962306a36Sopenharmony_ci		cc_debugfs_global_fini();
66062306a36Sopenharmony_ci		return rc;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	return 0;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_cimodule_init(ccree_init);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void __exit ccree_exit(void)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	platform_driver_unregister(&ccree_driver);
67062306a36Sopenharmony_ci	cc_debugfs_global_fini();
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_cimodule_exit(ccree_exit);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/* Module description */
67562306a36Sopenharmony_ciMODULE_DESCRIPTION("ARM TrustZone CryptoCell REE Driver");
67662306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION);
67762306a36Sopenharmony_ciMODULE_AUTHOR("ARM");
67862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
679