This is an automatically generated commit which aids following Kernel patch history, as git will see the move and copy as a rename thus defeating the purpose. For the original discussion see: https://lists.openwrt.org/pipermail/openwrt-devel/2023-October/041673.html Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org> Link: https://github.com/openwrt/openwrt/pull/23139 Signed-off-by: Nick Hainke <vincent@systemli.org>
165 lines
5.9 KiB
Diff
165 lines
5.9 KiB
Diff
From 8f66ccbd8f67ab41b29f54f383f8a8516be7696c Mon Sep 17 00:00:00 2001
|
|
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
|
Date: Wed, 30 Apr 2025 18:16:35 +0200
|
|
Subject: [PATCH] hwrng: rockchip - add support for RK3576's RNG
|
|
|
|
The Rockchip RK3576 SoC uses a new hardware random number generator IP.
|
|
It's also used on the Rockchip RK3562 and the Rockchip RK3528.
|
|
|
|
It has several modes of operation and self-checking features that are
|
|
not implemented here. For starters, it has a DRNG output, which is an
|
|
AES-CTR pseudo-random number generator that can be reseeded from the
|
|
true entropy regularly.
|
|
|
|
However, it also allows for access of the true entropy generator
|
|
directly. This entropy is generated from an oscillator.
|
|
|
|
There are several configuration registers which we don't touch here. The
|
|
oscillator can be switched between a "CRO" and "STR" oscillator, and the
|
|
length of the oscillator can be configured.
|
|
|
|
The hardware also supports some automatic continuous entropy quality
|
|
checking, which is also not implemented in this driver for the time
|
|
being.
|
|
|
|
The output as-is has been deemed sufficient to be useful:
|
|
|
|
rngtest: starting FIPS tests...
|
|
rngtest: bits received from input: 20000032
|
|
rngtest: FIPS 140-2 successes: 997
|
|
rngtest: FIPS 140-2 failures: 3
|
|
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
|
|
rngtest: FIPS 140-2(2001-10-10) Poker: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Runs: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Long run: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
|
|
rngtest: input channel speed: (min=17.050; avg=1897.272;
|
|
max=19531250.000)Kibits/s
|
|
rngtest: FIPS tests speed: (min=44.773; avg=71.179; max=96.820)Mibits/s
|
|
rngtest: Program run time: 11760715 microseconds
|
|
rngtest: bits received from input: 40000032
|
|
rngtest: FIPS 140-2 successes: 1997
|
|
rngtest: FIPS 140-2 failures: 3
|
|
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
|
|
rngtest: FIPS 140-2(2001-10-10) Poker: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Runs: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Long run: 1
|
|
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
|
|
rngtest: input channel speed: (min=17.050; avg=1798.618;
|
|
max=19531250.000)Kibits/s
|
|
rngtest: FIPS tests speed: (min=44.773; avg=64.561; max=96.820)Mibits/s
|
|
rngtest: Program run time: 23507723 microseconds
|
|
|
|
Stretching the entropy can then be left up to Linux's actual entropy
|
|
pool.
|
|
|
|
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
|
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
|
---
|
|
drivers/char/hw_random/rockchip-rng.c | 73 +++++++++++++++++++++++++++
|
|
1 file changed, 73 insertions(+)
|
|
|
|
--- a/drivers/char/hw_random/rockchip-rng.c
|
|
+++ b/drivers/char/hw_random/rockchip-rng.c
|
|
@@ -93,6 +93,30 @@
|
|
#define TRNG_v1_VERSION_CODE 0x46bc
|
|
/* end of TRNG_V1 register definitions */
|
|
|
|
+/*
|
|
+ * RKRNG register definitions
|
|
+ * The RKRNG IP is a stand-alone TRNG implementation (not part of a crypto IP)
|
|
+ * and can be found in the Rockchip RK3576, Rockchip RK3562 and Rockchip RK3528
|
|
+ * SoCs. It can either output true randomness (TRNG) or "deterministic"
|
|
+ * randomness derived from hashing the true entropy (DRNG). This driver
|
|
+ * implementation uses just the true entropy, and leaves stretching the entropy
|
|
+ * up to Linux.
|
|
+ */
|
|
+#define RKRNG_CFG 0x0000
|
|
+#define RKRNG_CTRL 0x0010
|
|
+#define RKRNG_CTRL_REQ_TRNG BIT(4)
|
|
+#define RKRNG_STATE 0x0014
|
|
+#define RKRNG_STATE_TRNG_RDY BIT(4)
|
|
+#define RKRNG_TRNG_DATA0 0x0050
|
|
+#define RKRNG_TRNG_DATA1 0x0054
|
|
+#define RKRNG_TRNG_DATA2 0x0058
|
|
+#define RKRNG_TRNG_DATA3 0x005C
|
|
+#define RKRNG_TRNG_DATA4 0x0060
|
|
+#define RKRNG_TRNG_DATA5 0x0064
|
|
+#define RKRNG_TRNG_DATA6 0x0068
|
|
+#define RKRNG_TRNG_DATA7 0x006C
|
|
+#define RKRNG_READ_LEN 32
|
|
+
|
|
/* Before removing this assert, give rk3588_rng_read an upper bound of 32 */
|
|
static_assert(RK_RNG_MAX_BYTE <= (TRNG_V1_RAND7 + 4 - TRNG_V1_RAND0),
|
|
"You raised RK_RNG_MAX_BYTE and broke rk3588-rng, congrats.");
|
|
@@ -205,6 +229,46 @@ out:
|
|
return (ret < 0) ? ret : to_read;
|
|
}
|
|
|
|
+static int rk3576_rng_init(struct hwrng *rng)
|
|
+{
|
|
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
|
+
|
|
+ return rk_rng_enable_clks(rk_rng);
|
|
+}
|
|
+
|
|
+static int rk3576_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
|
+{
|
|
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
|
+ size_t to_read = min_t(size_t, max, RKRNG_READ_LEN);
|
|
+ int ret = 0;
|
|
+ u32 val;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(rk_rng->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ rk_rng_writel(rk_rng, RKRNG_CTRL_REQ_TRNG | (RKRNG_CTRL_REQ_TRNG << 16),
|
|
+ RKRNG_CTRL);
|
|
+
|
|
+ if (readl_poll_timeout(rk_rng->base + RKRNG_STATE, val,
|
|
+ (val & RKRNG_STATE_TRNG_RDY), RK_RNG_POLL_PERIOD_US,
|
|
+ RK_RNG_POLL_TIMEOUT_US)) {
|
|
+ dev_err(rk_rng->dev, "timed out waiting for data\n");
|
|
+ ret = -ETIMEDOUT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ rk_rng_writel(rk_rng, RKRNG_STATE_TRNG_RDY, RKRNG_STATE);
|
|
+
|
|
+ memcpy_fromio(buf, rk_rng->base + RKRNG_TRNG_DATA0, to_read);
|
|
+
|
|
+out:
|
|
+ pm_runtime_mark_last_busy(rk_rng->dev);
|
|
+ pm_runtime_put_sync_autosuspend(rk_rng->dev);
|
|
+
|
|
+ return (ret < 0) ? ret : to_read;
|
|
+}
|
|
+
|
|
static int rk3588_rng_init(struct hwrng *rng)
|
|
{
|
|
struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
|
@@ -305,6 +369,14 @@ static const struct rk_rng_soc_data rk35
|
|
.reset_optional = false,
|
|
};
|
|
|
|
+static const struct rk_rng_soc_data rk3576_soc_data = {
|
|
+ .rk_rng_init = rk3576_rng_init,
|
|
+ .rk_rng_read = rk3576_rng_read,
|
|
+ .rk_rng_cleanup = rk3588_rng_cleanup,
|
|
+ .quality = 999, /* as determined by actual testing */
|
|
+ .reset_optional = true,
|
|
+};
|
|
+
|
|
static const struct rk_rng_soc_data rk3588_soc_data = {
|
|
.rk_rng_init = rk3588_rng_init,
|
|
.rk_rng_read = rk3588_rng_read,
|
|
@@ -397,6 +469,7 @@ static const struct dev_pm_ops rk_rng_pm
|
|
|
|
static const struct of_device_id rk_rng_dt_match[] = {
|
|
{ .compatible = "rockchip,rk3568-rng", .data = (void *)&rk3568_soc_data },
|
|
+ { .compatible = "rockchip,rk3576-rng", .data = (void *)&rk3576_soc_data },
|
|
{ .compatible = "rockchip,rk3588-rng", .data = (void *)&rk3588_soc_data },
|
|
{ /* sentinel */ },
|
|
};
|