Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89245107 authored by Naveen Krishna Chatradhi's avatar Naveen Krishna Chatradhi Committed by Herbert Xu
Browse files

crypto: s5p-sss - Add support for SSS module on Exynos



This patch adds new compatible and variant struct to support the SSS
module on Exynos4 (Exynos4210), Exynos5 (Exynos5420 and Exynos5250)
for which
1. AES register are at an offset of 0x200 and
2. hash interrupt is not available

Signed-off-by: default avatarNaveen Krishna Chatradhi <ch.naveen@samsung.com>
Reviewed-by: default avatarTomasz Figa <t.figa@samsung.com>
CC: David S. Miller <davem@davemloft.net>
CC: <linux-samsung-soc@vger.kernel.org>
Acked-by: default avatarVladimir Zapolskiy <vz@mleia.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 6b9f16e6
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -8,16 +8,25 @@ The SSS module in S5PV210 SoC supports the following:
-- SHA-1/SHA-256/MD5/HMAC (SHA-1/SHA-256/MD5)/PRNG
-- PRNG: Pseudo Random Number Generator

The SSS module in Exynos4 (Exynos4210) and
Exynos5 (Exynos5420 and Exynos5250) SoCs
supports the following also:
-- ARCFOUR (ARC4)
-- True Random Number Generator (TRNG)
-- Secure Key Manager

Required properties:

- compatible : Should contain entries for this and backward compatible
  SSS versions:
  - "samsung,s5pv210-secss" for S5PV210 SoC.
  - "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250,
		Exynos5260 and Exynos5420 SoCs.
- reg : Offset and length of the register set for the module
- interrupts : interrupt specifiers of SSS module interrupts, should contain
		two entries:
		- first : feed control interrupt,
		- second : hash interrupt.
		following entries:
		- first : feed control interrupt (required for all variants),
		- second : hash interrupt (required only for samsung,s5pv210-secss).

- clocks : list of clock phandle and specifier pairs for all clocks  listed in
		clock-names property.
+83 −24
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@
#define SSS_REG_FCPKDMAO                0x005C

/* AES registers */
#define SSS_REG_AES_CONTROL             0x4000
#define SSS_REG_AES_CONTROL		0x00
#define SSS_AES_BYTESWAP_DI             _BIT(11)
#define SSS_AES_BYTESWAP_DO             _BIT(10)
#define SSS_AES_BYTESWAP_IV             _BIT(9)
@@ -122,21 +122,25 @@
#define SSS_AES_CHAIN_MODE_CTR          _SBF(1, 0x02)
#define SSS_AES_MODE_DECRYPT            _BIT(0)

#define SSS_REG_AES_STATUS              0x4004
#define SSS_REG_AES_STATUS		0x04
#define SSS_AES_BUSY                    _BIT(2)
#define SSS_AES_INPUT_READY             _BIT(1)
#define SSS_AES_OUTPUT_READY            _BIT(0)

#define SSS_REG_AES_IN_DATA(s)          (0x4010 + (s << 2))
#define SSS_REG_AES_OUT_DATA(s)         (0x4020 + (s << 2))
#define SSS_REG_AES_IV_DATA(s)          (0x4030 + (s << 2))
#define SSS_REG_AES_CNT_DATA(s)         (0x4040 + (s << 2))
#define SSS_REG_AES_KEY_DATA(s)         (0x4080 + (s << 2))
#define SSS_REG_AES_IN_DATA(s)		(0x10 + (s << 2))
#define SSS_REG_AES_OUT_DATA(s)		(0x20 + (s << 2))
#define SSS_REG_AES_IV_DATA(s)		(0x30 + (s << 2))
#define SSS_REG_AES_CNT_DATA(s)		(0x40 + (s << 2))
#define SSS_REG_AES_KEY_DATA(s)		(0x80 + (s << 2))

#define SSS_REG(dev, reg)               ((dev)->ioaddr + (SSS_REG_##reg))
#define SSS_READ(dev, reg)              __raw_readl(SSS_REG(dev, reg))
#define SSS_WRITE(dev, reg, val)        __raw_writel((val), SSS_REG(dev, reg))

#define SSS_AES_REG(dev, reg)           ((dev)->aes_ioaddr + SSS_REG_##reg)
#define SSS_AES_WRITE(dev, reg, val)    __raw_writel((val), \
						SSS_AES_REG(dev, reg))

/* HW engine modes */
#define FLAGS_AES_DECRYPT               _BIT(0)
#define FLAGS_AES_MODE_MASK             _SBF(1, 0x03)
@@ -146,6 +150,20 @@
#define AES_KEY_LEN         16
#define CRYPTO_QUEUE_LEN    1

/**
 * struct samsung_aes_variant - platform specific SSS driver data
 * @has_hash_irq: true if SSS module uses hash interrupt, false otherwise
 * @aes_offset: AES register offset from SSS module's base.
 *
 * Specifies platform specific configuration of SSS module.
 * Note: A structure for driver specific platform data is used for future
 * expansion of its usage.
 */
struct samsung_aes_variant {
	bool			    has_hash_irq;
	unsigned int		    aes_offset;
};

struct s5p_aes_reqctx {
	unsigned long mode;
};
@@ -162,6 +180,7 @@ struct s5p_aes_dev {
	struct device              *dev;
	struct clk                 *clk;
	void __iomem               *ioaddr;
	void __iomem               *aes_ioaddr;
	int                         irq_hash;
	int                         irq_fc;

@@ -174,16 +193,48 @@ struct s5p_aes_dev {
	struct crypto_queue         queue;
	bool                        busy;
	spinlock_t                  lock;

	struct samsung_aes_variant *variant;
};

static struct s5p_aes_dev *s5p_dev;

static const struct samsung_aes_variant s5p_aes_data = {
	.has_hash_irq	= true,
	.aes_offset	= 0x4000,
};

static const struct samsung_aes_variant exynos_aes_data = {
	.has_hash_irq	= false,
	.aes_offset	= 0x200,
};

static const struct of_device_id s5p_sss_dt_match[] = {
	{ .compatible = "samsung,s5pv210-secss" },
	{
		.compatible = "samsung,s5pv210-secss",
		.data = &s5p_aes_data,
	},
	{
		.compatible = "samsung,exynos4210-secss",
		.data = &exynos_aes_data,
	},
	{ },
};
MODULE_DEVICE_TABLE(of, s5p_sss_dt_match);

static inline struct samsung_aes_variant *find_s5p_sss_version
				   (struct platform_device *pdev)
{
	if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) {
		const struct of_device_id *match;
		match = of_match_node(s5p_sss_dt_match,
					pdev->dev.of_node);
		return (struct samsung_aes_variant *)match->data;
	}
	return (struct samsung_aes_variant *)
			platform_get_device_id(pdev)->driver_data;
}

static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
{
	SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg));
@@ -329,14 +380,14 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
{
	void __iomem *keystart;

	memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
	memcpy(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);

	if (keylen == AES_KEYSIZE_256)
		keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0);
		keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0);
	else if (keylen == AES_KEYSIZE_192)
		keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2);
		keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2);
	else
		keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4);
		keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4);

	memcpy(keystart, key, keylen);
}
@@ -386,7 +437,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
	if (err)
		goto outdata_error;

	SSS_WRITE(dev, AES_CONTROL, aes_control);
	SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
	s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);

	s5p_set_dma_indata(dev,  req->src);
@@ -571,6 +622,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
	struct s5p_aes_dev *pdata;
	struct device      *dev = &pdev->dev;
	struct resource    *res;
	struct samsung_aes_variant *variant;

	if (s5p_dev)
		return -EEXIST;
@@ -584,6 +636,8 @@ static int s5p_aes_probe(struct platform_device *pdev)
	if (IS_ERR(pdata->ioaddr))
		return PTR_ERR(pdata->ioaddr);

	variant = find_s5p_sss_version(pdev);

	pdata->clk = devm_clk_get(dev, "secss");
	if (IS_ERR(pdata->clk)) {
		dev_err(dev, "failed to find secss clock source\n");
@@ -594,6 +648,8 @@ static int s5p_aes_probe(struct platform_device *pdev)

	spin_lock_init(&pdata->lock);

	pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset;

	pdata->irq_fc = platform_get_irq(pdev, 0);
	if (pdata->irq_fc < 0) {
		err = pdata->irq_fc;
@@ -607,6 +663,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
		goto err_irq;
	}

	if (variant->has_hash_irq) {
		pdata->irq_hash = platform_get_irq(pdev, 1);
		if (pdata->irq_hash < 0) {
			err = pdata->irq_hash;
@@ -619,7 +676,9 @@ static int s5p_aes_probe(struct platform_device *pdev)
			dev_warn(dev, "hash interrupt is not available.\n");
			goto err_irq;
		}
	}

	pdata->variant = variant;
	pdata->dev = dev;
	platform_set_drvdata(pdev, pdata);
	s5p_dev = pdata;