mirror of
https://github.com/andreili/SBC_builder.git
synced 2025-08-23 19:04:06 +02:00
303 lines
9.1 KiB
Diff
303 lines
9.1 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Paolo Sabatino <paolo.sabatino@gmail.com>
|
|
Date: Sun, 14 Jan 2024 11:53:20 +0100
|
|
Subject: rockchip64: add TRNG to existing crypto v1 driver
|
|
|
|
original patch source: https://patchwork.kernel.org/project/linux-rockchip/patch/20230707115242.3411259-1-clabbe@baylibre.com/
|
|
---
|
|
drivers/crypto/Kconfig | 8 +
|
|
drivers/crypto/rockchip/Makefile | 1 +
|
|
drivers/crypto/rockchip/rk3288_crypto.c | 18 +-
|
|
drivers/crypto/rockchip/rk3288_crypto.h | 18 ++
|
|
drivers/crypto/rockchip/rk3288_crypto_ahash.c | 2 +
|
|
drivers/crypto/rockchip/rk3288_crypto_skcipher.c | 2 +
|
|
drivers/crypto/rockchip/rk3288_crypto_trng.c | 92 ++++++++++
|
|
7 files changed, 140 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/Kconfig
|
|
+++ b/drivers/crypto/Kconfig
|
|
@@ -694,6 +694,14 @@ config CRYPTO_DEV_ROCKCHIP
|
|
This driver interfaces with the hardware crypto accelerator.
|
|
Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode.
|
|
|
|
+config CRYPTO_DEV_ROCKCHIP_TRNG
|
|
+ bool "Support for Rockchip TRNG"
|
|
+ depends on CRYPTO_DEV_ROCKCHIP
|
|
+ select HW_RANDOM
|
|
+ help
|
|
+ Select this option if you want to provide kernel-side support for
|
|
+ the True Random Number Generator found in the Crypto IP.
|
|
+
|
|
config CRYPTO_DEV_ROCKCHIP_DEBUG
|
|
bool "Enable Rockchip crypto stats"
|
|
depends on CRYPTO_DEV_ROCKCHIP
|
|
diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/rockchip/Makefile
|
|
+++ b/drivers/crypto/rockchip/Makefile
|
|
@@ -3,3 +3,4 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o
|
|
rk_crypto-objs := rk3288_crypto.o \
|
|
rk3288_crypto_skcipher.o \
|
|
rk3288_crypto_ahash.o
|
|
+rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG) += rk3288_crypto_trng.o
|
|
diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/rockchip/rk3288_crypto.c
|
|
+++ b/drivers/crypto/rockchip/rk3288_crypto.c
|
|
@@ -47,15 +47,18 @@ static const struct rk_variant rk3288_variant = {
|
|
.num_clks = 4,
|
|
.rkclks = {
|
|
{ "sclk", 150000000},
|
|
- }
|
|
+ },
|
|
+ .trng = false,
|
|
};
|
|
|
|
static const struct rk_variant rk3328_variant = {
|
|
.num_clks = 3,
|
|
+ .trng = false,
|
|
};
|
|
|
|
static const struct rk_variant rk3399_variant = {
|
|
.num_clks = 3,
|
|
+ .trng = true,
|
|
};
|
|
|
|
static int rk_crypto_get_clks(struct rk_crypto_info *dev)
|
|
@@ -201,6 +204,10 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
|
|
seq_printf(seq, "%s %s requests: %lu\n",
|
|
dev_driver_string(dd->dev), dev_name(dd->dev),
|
|
dd->nreq);
|
|
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG
|
|
+ seq_printf(seq, "HWRNG: %lu %lu\n",
|
|
+ dd->hwrng_stat_req, dd->hwrng_stat_bytes);
|
|
+#endif
|
|
}
|
|
spin_unlock(&rocklist.lock);
|
|
|
|
@@ -395,6 +402,10 @@ static int rk_crypto_probe(struct platform_device *pdev)
|
|
dev_err(dev, "Fail to register crypto algorithms");
|
|
goto err_register_alg;
|
|
}
|
|
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG
|
|
+ if (crypto_info->variant->trng)
|
|
+ rk3288_hwrng_register(crypto_info);
|
|
+#endif
|
|
|
|
register_debugfs(crypto_info);
|
|
}
|
|
@@ -425,6 +436,11 @@ static void rk_crypto_remove(struct platform_device *pdev)
|
|
#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
|
|
debugfs_remove_recursive(rocklist.dbgfs_dir);
|
|
#endif
|
|
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_TRNG
|
|
+ if (crypto_tmp->variant->trng)
|
|
+ rk3288_hwrng_unregister(crypto_tmp);
|
|
+#endif
|
|
+
|
|
rk_crypto_unregister();
|
|
}
|
|
rk_crypto_pm_exit(crypto_tmp);
|
|
diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/rockchip/rk3288_crypto.h
|
|
+++ b/drivers/crypto/rockchip/rk3288_crypto.h
|
|
@@ -11,6 +11,7 @@
|
|
#include <crypto/sha1.h>
|
|
#include <crypto/sha2.h>
|
|
#include <linux/dma-mapping.h>
|
|
+#include <linux/hw_random.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/scatterlist.h>
|
|
@@ -180,6 +181,16 @@
|
|
#define RK_CRYPTO_HASH_DOUT_6 0x01a4
|
|
#define RK_CRYPTO_HASH_DOUT_7 0x01a8
|
|
|
|
+#define RK_CRYPTO_TRNG_CTRL 0x0200
|
|
+#define RK_CRYPTO_OSC_ENABLE BIT(16)
|
|
+#define RK_CRYPTO_TRNG_DOUT_0 0x0204
|
|
+/* sample < 1000 lead to 100% failure on rngtest,
|
|
+ * using more than 1200 does not increase success.
|
|
+ */
|
|
+#define RK_CRYPTO_RNG_SAMPLE 1200
|
|
+
|
|
+#define RK_CRYPTO_MAX_TRNG_BYTE 32
|
|
+
|
|
#define CRYPTO_READ(dev, offset) \
|
|
readl_relaxed(((dev)->reg + (offset)))
|
|
#define CRYPTO_WRITE(dev, offset, val) \
|
|
@@ -209,6 +220,7 @@ struct rk_clks {
|
|
struct rk_variant {
|
|
int num_clks;
|
|
struct rk_clks rkclks[RK_MAX_CLKS];
|
|
+ bool trng;
|
|
};
|
|
|
|
struct rk_crypto_info {
|
|
@@ -219,11 +231,15 @@ struct rk_crypto_info {
|
|
struct reset_control *rst;
|
|
void __iomem *reg;
|
|
int irq;
|
|
+ struct mutex lock;
|
|
+ struct hwrng hwrng;
|
|
const struct rk_variant *variant;
|
|
unsigned long nreq;
|
|
struct crypto_engine *engine;
|
|
struct completion complete;
|
|
int status;
|
|
+ unsigned long hwrng_stat_req;
|
|
+ unsigned long hwrng_stat_bytes;
|
|
};
|
|
|
|
/* the private variable of hash */
|
|
@@ -283,3 +299,5 @@ extern struct rk_crypto_tmp rk_ahash_md5;
|
|
|
|
struct rk_crypto_info *get_rk_crypto(void);
|
|
#endif
|
|
+int rk3288_hwrng_register(struct rk_crypto_info *rk);
|
|
+void rk3288_hwrng_unregister(struct rk_crypto_info *rk);
|
|
diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c
|
|
+++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
|
|
@@ -298,6 +298,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
|
|
goto theend;
|
|
}
|
|
|
|
+ mutex_lock(&rkc->lock);
|
|
rk_ahash_reg_init(areq, rkc);
|
|
|
|
while (sg) {
|
|
@@ -332,6 +333,7 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
|
|
}
|
|
|
|
theend:
|
|
+ mutex_unlock(&rkc->lock);
|
|
pm_runtime_put_autosuspend(rkc->dev);
|
|
|
|
rk_hash_unprepare(engine, breq);
|
|
diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
|
|
+++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
|
|
@@ -363,6 +363,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req)
|
|
}
|
|
}
|
|
err = 0;
|
|
+ mutex_unlock(&rkc->lock);
|
|
rk_cipher_hw_init(rkc, areq);
|
|
if (ivsize) {
|
|
if (ivsize == DES_BLOCK_SIZE)
|
|
@@ -378,6 +379,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req)
|
|
crypto_dma_start(rkc, sgs, sgd, todo / 4);
|
|
wait_for_completion_interruptible_timeout(&rkc->complete,
|
|
msecs_to_jiffies(2000));
|
|
+ mutex_unlock(&rkc->lock);
|
|
if (!rkc->status) {
|
|
dev_err(rkc->dev, "DMA timeout\n");
|
|
err = -EFAULT;
|
|
diff --git a/drivers/crypto/rockchip/rk3288_crypto_trng.c b/drivers/crypto/rockchip/rk3288_crypto_trng.c
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/crypto/rockchip/rk3288_crypto_trng.c
|
|
@@ -0,0 +1,92 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * rk3288_crypto_trng.c - hardware cryptographic offloader for rockchip
|
|
+ *
|
|
+ * Copyright (C) 2022-2023 Corentin Labbe <clabbe@baylibre.com>
|
|
+ *
|
|
+ * This file handle the TRNG
|
|
+ */
|
|
+#include "rk3288_crypto.h"
|
|
+#include <linux/hw_random.h>
|
|
+#include <linux/iopoll.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+
|
|
+static int rk3288_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
|
|
+{
|
|
+ struct rk_crypto_info *rk;
|
|
+ unsigned int todo;
|
|
+ int err = 0;
|
|
+ int i;
|
|
+ u32 v;
|
|
+
|
|
+ rk = container_of(hwrng, struct rk_crypto_info, hwrng);
|
|
+
|
|
+ todo = min_t(size_t, max, RK_CRYPTO_MAX_TRNG_BYTE);
|
|
+
|
|
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
|
|
+ rk->hwrng_stat_req++;
|
|
+ rk->hwrng_stat_bytes += todo;
|
|
+#endif
|
|
+
|
|
+ err = pm_runtime_resume_and_get(rk->dev);
|
|
+ if (err < 0)
|
|
+ goto err_pm;
|
|
+
|
|
+ mutex_lock(&rk->lock);
|
|
+
|
|
+#define HIWORD_UPDATE(val, mask, shift) \
|
|
+ ((val) << (shift) | (mask) << ((shift) + 16))
|
|
+ v = RK_CRYPTO_OSC_ENABLE | RK_CRYPTO_RNG_SAMPLE;
|
|
+ CRYPTO_WRITE(rk, RK_CRYPTO_TRNG_CTRL, v);
|
|
+
|
|
+ v = HIWORD_UPDATE(RK_CRYPTO_TRNG_START, RK_CRYPTO_TRNG_START, 0);
|
|
+ CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v);
|
|
+ wmb();
|
|
+
|
|
+ err = readl_poll_timeout(rk->reg + RK_CRYPTO_CTRL, v,
|
|
+ !(v & RK_CRYPTO_TRNG_START),
|
|
+ 100, 2000);
|
|
+ if (err) {
|
|
+ dev_err(rk->dev, "HWRNG read timeout");
|
|
+ goto readfail;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < todo / 4; i++) {
|
|
+ v = readl(rk->reg + RK_CRYPTO_TRNG_DOUT_0 + i * 4);
|
|
+ put_unaligned_le32(v, data + i * 4);
|
|
+ }
|
|
+
|
|
+ err = todo;
|
|
+
|
|
+ v = HIWORD_UPDATE(0, RK_CRYPTO_TRNG_START, 0);
|
|
+ CRYPTO_WRITE(rk, RK_CRYPTO_CTRL, v);
|
|
+
|
|
+readfail:
|
|
+ mutex_unlock(&rk->lock);
|
|
+
|
|
+ pm_runtime_put(rk->dev);
|
|
+
|
|
+err_pm:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+int rk3288_hwrng_register(struct rk_crypto_info *rk)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ dev_info(rk->dev, "Register TRNG with sample=%d\n", RK_CRYPTO_RNG_SAMPLE);
|
|
+
|
|
+ rk->hwrng.name = "Rockchip rk3288 TRNG";
|
|
+ rk->hwrng.read = rk3288_trng_read;
|
|
+ rk->hwrng.quality = 300;
|
|
+
|
|
+ ret = hwrng_register(&rk->hwrng);
|
|
+ if (ret)
|
|
+ dev_err(rk->dev, "Fail to register the TRNG\n");
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void rk3288_hwrng_unregister(struct rk_crypto_info *rk)
|
|
+{
|
|
+ hwrng_unregister(&rk->hwrng);
|
|
+}
|
|
--
|
|
Armbian
|
|
|