[openwrt/openwrt] rockchip: add RK3588 Hardware Random Number Generator
LEDE Commits
lede-commits at lists.infradead.org
Mon Jul 14 13:39:01 PDT 2025
hauke pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/e02c7a201488932f28c67231d225cfab23c14914
commit e02c7a201488932f28c67231d225cfab23c14914
Author: Marty Jones <mj8263788 at gmail.com>
AuthorDate: Sun Jun 15 21:07:46 2025 -0400
rockchip: add RK3588 Hardware Random Number Generator
Backport support for RK3588 hardware RNG driver.
Signed-off-by: Marty Jones <mj8263788 at gmail.com>
Link: https://github.com/openwrt/openwrt/pull/19366
Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
...dings-reset-Add-SCMI-reset-IDs-for-RK3588.patch | 74 ++++
...s-rng-add-binding-for-Rockchip-RK3588-RNG.patch | 91 +++++
...-rng-rockchip-rk3588-rng-Drop-unnecessary.patch | 27 ++
...ckchip-store-dev-pointer-in-driver-struct.patch | 67 ++++
...hip-eliminate-some-unnecessary-dereferenc.patch | 42 ++
...hip-add-support-for-rk3588-s-standalone-T.patch | 422 +++++++++++++++++++++
...arm64-dts-rockchip-Add-rng-node-to-RK3588.patch | 34 ++
...ockchip-change-rng-reset-id-back-to-its-c.patch | 25 ++
8 files changed, 782 insertions(+)
diff --git a/target/linux/rockchip/patches-6.12/057-03-v6.15-dt-bindings-reset-Add-SCMI-reset-IDs-for-RK3588.patch b/target/linux/rockchip/patches-6.12/057-03-v6.15-dt-bindings-reset-Add-SCMI-reset-IDs-for-RK3588.patch
new file mode 100644
index 0000000000..8f98680aea
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-03-v6.15-dt-bindings-reset-Add-SCMI-reset-IDs-for-RK3588.patch
@@ -0,0 +1,74 @@
+From 849d9db170fc8a03ce9f64133a1d0cd46c135105 Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:46 +0100
+Subject: [PATCH] dt-bindings: reset: Add SCMI reset IDs for RK3588
+
+When TF-A is used to assert/deassert the resets through SCMI, the
+IDs communicated to it are different than the ones mainline Linux uses.
+
+Import the list of SCMI reset IDs from mainline TF-A so that devicetrees
+can use these IDs more easily.
+
+Co-developed-by: XiaoDong Huang <derrick.huang at rock-chips.com>
+Signed-off-by: XiaoDong Huang <derrick.huang at rock-chips.com>
+Acked-by: Conor Dooley <conor.dooley at microchip.com>
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ .../dt-bindings/reset/rockchip,rk3588-cru.h | 41 ++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+--- a/include/dt-bindings/reset/rockchip,rk3588-cru.h
++++ b/include/dt-bindings/reset/rockchip,rk3588-cru.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+ /*
+- * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
++ * Copyright (c) 2021, 2024 Rockchip Electronics Co. Ltd.
+ * Copyright (c) 2022 Collabora Ltd.
+ *
+ * Author: Elaine Zhang <zhangqing at rock-chips.com>
+@@ -753,4 +753,43 @@
+
+ #define SRST_A_HDMIRX_BIU 660
+
++/* SCMI Secure Resets */
++
++/* Name=SECURE_SOFTRST_CON00,Offset=0xA00 */
++#define SCMI_SRST_A_SECURE_NS_BIU 10
++#define SCMI_SRST_H_SECURE_NS_BIU 11
++#define SCMI_SRST_A_SECURE_S_BIU 12
++#define SCMI_SRST_H_SECURE_S_BIU 13
++#define SCMI_SRST_P_SECURE_S_BIU 14
++#define SCMI_SRST_CRYPTO_CORE 15
++/* Name=SECURE_SOFTRST_CON01,Offset=0xA04 */
++#define SCMI_SRST_CRYPTO_PKA 16
++#define SCMI_SRST_CRYPTO_RNG 17
++#define SCMI_SRST_A_CRYPTO 18
++#define SCMI_SRST_H_CRYPTO 19
++#define SCMI_SRST_KEYLADDER_CORE 25
++#define SCMI_SRST_KEYLADDER_RNG 26
++#define SCMI_SRST_A_KEYLADDER 27
++#define SCMI_SRST_H_KEYLADDER 28
++#define SCMI_SRST_P_OTPC_S 29
++#define SCMI_SRST_OTPC_S 30
++#define SCMI_SRST_WDT_S 31
++/* Name=SECURE_SOFTRST_CON02,Offset=0xA08 */
++#define SCMI_SRST_T_WDT_S 32
++#define SCMI_SRST_H_BOOTROM 33
++#define SCMI_SRST_A_DCF 34
++#define SCMI_SRST_P_DCF 35
++#define SCMI_SRST_H_BOOTROM_NS 37
++#define SCMI_SRST_P_KEYLADDER 46
++#define SCMI_SRST_H_TRNG_S 47
++/* Name=SECURE_SOFTRST_CON03,Offset=0xA0C */
++#define SCMI_SRST_H_TRNG_NS 48
++#define SCMI_SRST_D_SDMMC_BUFFER 49
++#define SCMI_SRST_H_SDMMC 50
++#define SCMI_SRST_H_SDMMC_BUFFER 51
++#define SCMI_SRST_SDMMC 52
++#define SCMI_SRST_P_TRNG_CHK 53
++#define SCMI_SRST_TRNG_S 54
++
++
+ #endif
diff --git a/target/linux/rockchip/patches-6.12/057-04-v6.15-dt-bindings-rng-add-binding-for-Rockchip-RK3588-RNG.patch b/target/linux/rockchip/patches-6.12/057-04-v6.15-dt-bindings-rng-add-binding-for-Rockchip-RK3588-RNG.patch
new file mode 100644
index 0000000000..cb7e15527b
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-04-v6.15-dt-bindings-rng-add-binding-for-Rockchip-RK3588-RNG.patch
@@ -0,0 +1,91 @@
+From e00fc3d6e7c2d0b2ab5cf03a576df39cd94479aa Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:47 +0100
+Subject: [PATCH] dt-bindings: rng: add binding for Rockchip RK3588 RNG
+
+The Rockchip RK3588 SoC has two hardware RNGs accessible to the
+non-secure world: an RNG in the Crypto IP, and a standalone RNG that is
+new to this SoC.
+
+Add a binding for this new standalone RNG. It is distinct hardware from
+the existing rockchip,rk3568-rng, and therefore gets its own binding as
+the two hardware IPs are unrelated other than both being made by the
+same vendor.
+
+The RNG is capable of firing an interrupt when entropy is ready.
+
+The reset is optional, as the hardware does a power-on reset, and
+functions without the software manually resetting it.
+
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Acked-by: Conor Dooley <conor.dooley at microchip.com>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ .../bindings/rng/rockchip,rk3588-rng.yaml | 60 +++++++++++++++++++
+ MAINTAINERS | 1 +
+ 2 files changed, 61 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/rng/rockchip,rk3588-rng.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/rng/rockchip,rk3588-rng.yaml
+@@ -0,0 +1,60 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/rng/rockchip,rk3588-rng.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Rockchip RK3588 TRNG
++
++description: True Random Number Generator on Rockchip RK3588 SoC
++
++maintainers:
++ - Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
++
++properties:
++ compatible:
++ enum:
++ - rockchip,rk3588-rng
++
++ reg:
++ maxItems: 1
++
++ clocks:
++ items:
++ - description: TRNG AHB clock
++
++ interrupts:
++ maxItems: 1
++
++ resets:
++ maxItems: 1
++
++required:
++ - compatible
++ - reg
++ - clocks
++ - interrupts
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/clock/rockchip,rk3588-cru.h>
++ #include <dt-bindings/interrupt-controller/arm-gic.h>
++ #include <dt-bindings/interrupt-controller/irq.h>
++ #include <dt-bindings/reset/rockchip,rk3588-cru.h>
++ bus {
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ rng at fe378000 {
++ compatible = "rockchip,rk3588-rng";
++ reg = <0x0 0xfe378000 0x0 0x200>;
++ interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH 0>;
++ clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
++ resets = <&scmi_reset SCMI_SRST_H_TRNG_NS>;
++ status = "okay";
++ };
++ };
++
++...
diff --git a/target/linux/rockchip/patches-6.12/057-05-v6.15-dt-bindings-rng-rockchip-rk3588-rng-Drop-unnecessary.patch b/target/linux/rockchip/patches-6.12/057-05-v6.15-dt-bindings-rng-rockchip-rk3588-rng-Drop-unnecessary.patch
new file mode 100644
index 0000000000..1dde09f1af
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-05-v6.15-dt-bindings-rng-rockchip-rk3588-rng-Drop-unnecessary.patch
@@ -0,0 +1,27 @@
+From 52b3b329d8e589575d16d8d9adbca9e08041ee82 Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
+Date: Fri, 7 Mar 2025 10:33:09 +0100
+Subject: [PATCH] dt-bindings: rng: rockchip,rk3588-rng: Drop unnecessary
+ status from example
+
+Device nodes are enabled by default, so no need for 'status = "okay"' in
+the DTS example.
+
+Reviewed-by: Heiko Stuebner <heiko at sntech.de>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
+Acked-by: Rob Herring (Arm) <robh at kernel.org>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ Documentation/devicetree/bindings/rng/rockchip,rk3588-rng.yaml | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/rng/rockchip,rk3588-rng.yaml
++++ b/Documentation/devicetree/bindings/rng/rockchip,rk3588-rng.yaml
+@@ -53,7 +53,6 @@ examples:
+ interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
+ resets = <&scmi_reset SCMI_SRST_H_TRNG_NS>;
+- status = "okay";
+ };
+ };
+
diff --git a/target/linux/rockchip/patches-6.12/057-06-v6.15-hwrng-rockchip-store-dev-pointer-in-driver-struct.patch b/target/linux/rockchip/patches-6.12/057-06-v6.15-hwrng-rockchip-store-dev-pointer-in-driver-struct.patch
new file mode 100644
index 0000000000..2f14fcd888
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-06-v6.15-hwrng-rockchip-store-dev-pointer-in-driver-struct.patch
@@ -0,0 +1,67 @@
+From 8bb8609293ff3d8998d75c8db605c0529e83bcd9 Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:48 +0100
+Subject: [PATCH] hwrng: rockchip - store dev pointer in driver struct
+
+The rockchip rng driver does a dance to store the dev pointer in the
+hwrng's unsigned long "priv" member. However, since the struct hwrng
+member of rk_rng is not a pointer, we can use container_of to get the
+struct rk_rng instance from just the struct hwrng*, which means we don't
+have to subvert what little there is in C of a type system and can
+instead store a pointer to the device struct in the rk_rng itself.
+
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ drivers/char/hw_random/rockchip-rng.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/char/hw_random/rockchip-rng.c
++++ b/drivers/char/hw_random/rockchip-rng.c
+@@ -54,6 +54,7 @@ struct rk_rng {
+ void __iomem *base;
+ int clk_num;
+ struct clk_bulk_data *clk_bulks;
++ struct device *dev;
+ };
+
+ /* The mask in the upper 16 bits determines the bits that are updated */
+@@ -70,8 +71,7 @@ static int rk_rng_init(struct hwrng *rng
+ /* start clocks */
+ ret = clk_bulk_prepare_enable(rk_rng->clk_num, rk_rng->clk_bulks);
+ if (ret < 0) {
+- dev_err((struct device *) rk_rng->rng.priv,
+- "Failed to enable clks %d\n", ret);
++ dev_err(rk_rng->dev, "Failed to enable clocks: %d\n", ret);
+ return ret;
+ }
+
+@@ -105,7 +105,7 @@ static int rk_rng_read(struct hwrng *rng
+ u32 reg;
+ int ret = 0;
+
+- ret = pm_runtime_resume_and_get((struct device *) rk_rng->rng.priv);
++ ret = pm_runtime_resume_and_get(rk_rng->dev);
+ if (ret < 0)
+ return ret;
+
+@@ -122,8 +122,8 @@ static int rk_rng_read(struct hwrng *rng
+ /* Read random data stored in the registers */
+ memcpy_fromio(buf, rk_rng->base + TRNG_RNG_DOUT, to_read);
+ out:
+- pm_runtime_mark_last_busy((struct device *) rk_rng->rng.priv);
+- pm_runtime_put_sync_autosuspend((struct device *) rk_rng->rng.priv);
++ pm_runtime_mark_last_busy(rk_rng->dev);
++ pm_runtime_put_sync_autosuspend(rk_rng->dev);
+
+ return (ret < 0) ? ret : to_read;
+ }
+@@ -164,7 +164,7 @@ static int rk_rng_probe(struct platform_
+ rk_rng->rng.cleanup = rk_rng_cleanup;
+ }
+ rk_rng->rng.read = rk_rng_read;
+- rk_rng->rng.priv = (unsigned long) dev;
++ rk_rng->dev = dev;
+ rk_rng->rng.quality = 900;
+
+ pm_runtime_set_autosuspend_delay(dev, RK_RNG_AUTOSUSPEND_DELAY);
diff --git a/target/linux/rockchip/patches-6.12/057-07-v6.15-hwrng-rockchip-eliminate-some-unnecessary-dereferenc.patch b/target/linux/rockchip/patches-6.12/057-07-v6.15-hwrng-rockchip-eliminate-some-unnecessary-dereferenc.patch
new file mode 100644
index 0000000000..a3bdff9641
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-07-v6.15-hwrng-rockchip-eliminate-some-unnecessary-dereferenc.patch
@@ -0,0 +1,42 @@
+From 24aaa42ed65c0811b598674a593fc653d643a7e6 Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:49 +0100
+Subject: [PATCH] hwrng: rockchip - eliminate some unnecessary dereferences
+
+Despite assigning a temporary variable the value of &pdev->dev early on
+in the probe function, the probe function then continues to use this
+construct when it could just use the local dev variable instead.
+
+Simplify this by using the local dev variable directly.
+
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ drivers/char/hw_random/rockchip-rng.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/char/hw_random/rockchip-rng.c
++++ b/drivers/char/hw_random/rockchip-rng.c
+@@ -148,7 +148,7 @@ static int rk_rng_probe(struct platform_
+ return dev_err_probe(dev, rk_rng->clk_num,
+ "Failed to get clks property\n");
+
+- rst = devm_reset_control_array_get_exclusive(&pdev->dev);
++ rst = devm_reset_control_array_get_exclusive(dev);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset property\n");
+
+@@ -171,11 +171,11 @@ static int rk_rng_probe(struct platform_
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+- return dev_err_probe(&pdev->dev, ret, "Runtime pm activation failed.\n");
++ return dev_err_probe(dev, ret, "Runtime pm activation failed.\n");
+
+ ret = devm_hwrng_register(dev, &rk_rng->rng);
+ if (ret)
+- return dev_err_probe(&pdev->dev, ret, "Failed to register Rockchip hwrng\n");
++ return dev_err_probe(dev, ret, "Failed to register Rockchip hwrng\n");
+
+ return 0;
+ }
diff --git a/target/linux/rockchip/patches-6.12/057-08-v6.15-hwrng-rockchip-add-support-for-rk3588-s-standalone-T.patch b/target/linux/rockchip/patches-6.12/057-08-v6.15-hwrng-rockchip-add-support-for-rk3588-s-standalone-T.patch
new file mode 100644
index 0000000000..9ae621a54a
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-08-v6.15-hwrng-rockchip-add-support-for-rk3588-s-standalone-T.patch
@@ -0,0 +1,422 @@
+From 8eff8eb83fc0ae8b5f76220e2bb8644d836e99ff Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:50 +0100
+Subject: [PATCH] hwrng: rockchip - add support for rk3588's standalone TRNG
+
+The RK3588 SoC includes several TRNGs, one part of the Crypto IP block,
+and the other one (referred to as "trngv1") as a standalone new IP.
+
+Add support for this new standalone TRNG to the driver by both
+generalising it to support multiple different rockchip RNGs and then
+implementing the required functionality for the new hardware.
+
+This work was partly based on the downstream vendor driver by Rockchip's
+Lin Jinhan, which is why they are listed as a Co-author.
+
+While the hardware does support notifying the CPU with an IRQ when the
+random data is ready, I've discovered while implementing the code to use
+this interrupt that this results in significantly slower throughput of
+the TRNG even when under heavy CPU load. I assume this is because with
+only 32 bytes of data per invocation, the overhead of reinitialising a
+completion, enabling the interrupt, sleeping and then triggering the
+completion in the IRQ handler is way more expensive than busylooping.
+
+Speaking of busylooping, the poll interval for reading the ISTAT is an
+atomic read with a delay of 0. In my testing, I've found that this gives
+us the largest throughput, and it appears the random data is ready
+pretty much the moment we begin polling, as increasing the poll delay
+leads to a drop in throughput significant enough to not just be due to
+the poll interval missing the ideal timing by a microsecond or two.
+
+According to downstream, the IP should take 1024 clock cycles to
+generate 56 bits of random data, which at 150MHz should work out to
+6.8us. I did not test whether the data really does take 256/56*6.8us
+to arrive, though changing the readl to a __raw_readl makes no
+difference in throughput, and this data does pass the rngtest FIPS
+checks, so I'm not entirely sure what's going on but I presume it's got
+something to do with the AHB bus speed and the memory barriers that
+mainline's readl/writel functions insert.
+
+The only other current SoC that uses this new IP is the Rockchip RV1106,
+but that SoC does not have mainline support as of the time of writing,
+so we make no effort to declare it as supported for now.
+
+Co-developed-by: Lin Jinhan <troy.lin at rock-chips.com>
+Signed-off-by: Lin Jinhan <troy.lin at rock-chips.com>
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>
+---
+ drivers/char/hw_random/Kconfig | 3 +-
+ drivers/char/hw_random/rockchip-rng.c | 234 +++++++++++++++++++++++---
+ 2 files changed, 216 insertions(+), 21 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -580,7 +580,8 @@ config HW_RANDOM_ROCKCHIP
+ default HW_RANDOM
+ help
+ This driver provides kernel-side support for the True Random Number
+- Generator hardware found on some Rockchip SoC like RK3566 or RK3568.
++ Generator hardware found on some Rockchip SoCs like RK3566, RK3568
++ or RK3588.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rockchip-rng.
+--- a/drivers/char/hw_random/rockchip-rng.c
++++ b/drivers/char/hw_random/rockchip-rng.c
+@@ -1,12 +1,14 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /*
+- * rockchip-rng.c True Random Number Generator driver for Rockchip RK3568 SoC
++ * rockchip-rng.c True Random Number Generator driver for Rockchip SoCs
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd.
+ * Copyright (c) 2022, Aurelien Jarno
++ * Copyright (c) 2025, Collabora Ltd.
+ * Authors:
+ * Lin Jinhan <troy.lin at rock-chips.com>
+ * Aurelien Jarno <aurelien at aurel32.net>
++ * Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+ */
+ #include <linux/clk.h>
+ #include <linux/hw_random.h>
+@@ -32,6 +34,9 @@
+ */
+ #define RK_RNG_SAMPLE_CNT 1000
+
++/* after how many bytes of output TRNGv1 implementations should be reseeded */
++#define RK_TRNG_V1_AUTO_RESEED_CNT 16000
++
+ /* TRNG registers from RK3568 TRM-Part2, section 5.4.1 */
+ #define TRNG_RST_CTL 0x0004
+ #define TRNG_RNG_CTL 0x0400
+@@ -49,25 +54,85 @@
+ #define TRNG_RNG_SAMPLE_CNT 0x0404
+ #define TRNG_RNG_DOUT 0x0410
+
++/*
++ * TRNG V1 register definitions
++ * The TRNG V1 IP is a stand-alone TRNG implementation (not part of a crypto IP)
++ * and can be found in the Rockchip RK3588 SoC
++ */
++#define TRNG_V1_CTRL 0x0000
++#define TRNG_V1_CTRL_NOP 0x00
++#define TRNG_V1_CTRL_RAND 0x01
++#define TRNG_V1_CTRL_SEED 0x02
++
++#define TRNG_V1_STAT 0x0004
++#define TRNG_V1_STAT_SEEDED BIT(9)
++#define TRNG_V1_STAT_GENERATING BIT(30)
++#define TRNG_V1_STAT_RESEEDING BIT(31)
++
++#define TRNG_V1_MODE 0x0008
++#define TRNG_V1_MODE_128_BIT (0x00 << 3)
++#define TRNG_V1_MODE_256_BIT (0x01 << 3)
++
++/* Interrupt Enable register; unused because polling is faster */
++#define TRNG_V1_IE 0x0010
++#define TRNG_V1_IE_GLBL_EN BIT(31)
++#define TRNG_V1_IE_SEED_DONE_EN BIT(1)
++#define TRNG_V1_IE_RAND_RDY_EN BIT(0)
++
++#define TRNG_V1_ISTAT 0x0014
++#define TRNG_V1_ISTAT_RAND_RDY BIT(0)
++
++/* RAND0 ~ RAND7 */
++#define TRNG_V1_RAND0 0x0020
++#define TRNG_V1_RAND7 0x003C
++
++/* Auto Reseed Register */
++#define TRNG_V1_AUTO_RQSTS 0x0060
++
++#define TRNG_V1_VERSION 0x00F0
++#define TRNG_v1_VERSION_CODE 0x46bc
++/* end of TRNG_V1 register definitions */
++
++/* 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.");
++
+ struct rk_rng {
+ struct hwrng rng;
+ void __iomem *base;
+ int clk_num;
+ struct clk_bulk_data *clk_bulks;
++ const struct rk_rng_soc_data *soc_data;
+ struct device *dev;
+ };
+
++struct rk_rng_soc_data {
++ int (*rk_rng_init)(struct hwrng *rng);
++ int (*rk_rng_read)(struct hwrng *rng, void *buf, size_t max, bool wait);
++ void (*rk_rng_cleanup)(struct hwrng *rng);
++ unsigned short quality;
++ bool reset_optional;
++};
++
+ /* The mask in the upper 16 bits determines the bits that are updated */
+ static void rk_rng_write_ctl(struct rk_rng *rng, u32 val, u32 mask)
+ {
+ writel((mask << 16) | val, rng->base + TRNG_RNG_CTL);
+ }
+
+-static int rk_rng_init(struct hwrng *rng)
++static inline void rk_rng_writel(struct rk_rng *rng, u32 val, u32 offset)
+ {
+- struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
+- int ret;
++ writel(val, rng->base + offset);
++}
+
++static inline u32 rk_rng_readl(struct rk_rng *rng, u32 offset)
++{
++ return readl(rng->base + offset);
++}
++
++static int rk_rng_enable_clks(struct rk_rng *rk_rng)
++{
++ int ret;
+ /* start clocks */
+ ret = clk_bulk_prepare_enable(rk_rng->clk_num, rk_rng->clk_bulks);
+ if (ret < 0) {
+@@ -75,6 +140,18 @@ static int rk_rng_init(struct hwrng *rng
+ return ret;
+ }
+
++ return 0;
++}
++
++static int rk3568_rng_init(struct hwrng *rng)
++{
++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
++ int ret;
++
++ ret = rk_rng_enable_clks(rk_rng);
++ if (ret < 0)
++ return ret;
++
+ /* set the sample period */
+ writel(RK_RNG_SAMPLE_CNT, rk_rng->base + TRNG_RNG_SAMPLE_CNT);
+
+@@ -87,7 +164,7 @@ static int rk_rng_init(struct hwrng *rng
+ return 0;
+ }
+
+-static void rk_rng_cleanup(struct hwrng *rng)
++static void rk3568_rng_cleanup(struct hwrng *rng)
+ {
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
+
+@@ -98,7 +175,7 @@ static void rk_rng_cleanup(struct hwrng
+ clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks);
+ }
+
+-static int rk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
++static int rk3568_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, RK_RNG_MAX_BYTE);
+@@ -128,6 +205,114 @@ out:
+ 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);
++ u32 version, status, mask, istat;
++ int ret;
++
++ ret = rk_rng_enable_clks(rk_rng);
++ if (ret < 0)
++ return ret;
++
++ version = rk_rng_readl(rk_rng, TRNG_V1_VERSION);
++ if (version != TRNG_v1_VERSION_CODE) {
++ dev_err(rk_rng->dev,
++ "wrong trng version, expected = %08x, actual = %08x\n",
++ TRNG_V1_VERSION, version);
++ ret = -EFAULT;
++ goto err_disable_clk;
++ }
++
++ mask = TRNG_V1_STAT_SEEDED | TRNG_V1_STAT_GENERATING |
++ TRNG_V1_STAT_RESEEDING;
++ if (readl_poll_timeout(rk_rng->base + TRNG_V1_STAT, status,
++ (status & mask) == TRNG_V1_STAT_SEEDED,
++ RK_RNG_POLL_PERIOD_US, RK_RNG_POLL_TIMEOUT_US) < 0) {
++ dev_err(rk_rng->dev, "timed out waiting for hwrng to reseed\n");
++ ret = -ETIMEDOUT;
++ goto err_disable_clk;
++ }
++
++ /*
++ * clear ISTAT flag, downstream advises to do this to avoid
++ * auto-reseeding "on power on"
++ */
++ istat = rk_rng_readl(rk_rng, TRNG_V1_ISTAT);
++ rk_rng_writel(rk_rng, istat, TRNG_V1_ISTAT);
++
++ /* auto reseed after RK_TRNG_V1_AUTO_RESEED_CNT bytes */
++ rk_rng_writel(rk_rng, RK_TRNG_V1_AUTO_RESEED_CNT / 16, TRNG_V1_AUTO_RQSTS);
++
++ return 0;
++err_disable_clk:
++ clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks);
++ return ret;
++}
++
++static void rk3588_rng_cleanup(struct hwrng *rng)
++{
++ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
++
++ clk_bulk_disable_unprepare(rk_rng->clk_num, rk_rng->clk_bulks);
++}
++
++static int rk3588_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, RK_RNG_MAX_BYTE);
++ int ret = 0;
++ u32 reg;
++
++ ret = pm_runtime_resume_and_get(rk_rng->dev);
++ if (ret < 0)
++ return ret;
++
++ /* Clear ISTAT, even without interrupts enabled, this will be updated */
++ reg = rk_rng_readl(rk_rng, TRNG_V1_ISTAT);
++ rk_rng_writel(rk_rng, reg, TRNG_V1_ISTAT);
++
++ /* generate 256 bits of random data */
++ rk_rng_writel(rk_rng, TRNG_V1_MODE_256_BIT, TRNG_V1_MODE);
++ rk_rng_writel(rk_rng, TRNG_V1_CTRL_RAND, TRNG_V1_CTRL);
++
++ ret = readl_poll_timeout_atomic(rk_rng->base + TRNG_V1_ISTAT, reg,
++ (reg & TRNG_V1_ISTAT_RAND_RDY), 0,
++ RK_RNG_POLL_TIMEOUT_US);
++ if (ret < 0)
++ goto out;
++
++ /* Read random data that's in registers TRNG_V1_RAND0 through RAND7 */
++ memcpy_fromio(buf, rk_rng->base + TRNG_V1_RAND0, to_read);
++
++out:
++ /* Clear ISTAT */
++ rk_rng_writel(rk_rng, reg, TRNG_V1_ISTAT);
++ /* close the TRNG */
++ rk_rng_writel(rk_rng, TRNG_V1_CTRL_NOP, TRNG_V1_CTRL);
++
++ pm_runtime_mark_last_busy(rk_rng->dev);
++ pm_runtime_put_sync_autosuspend(rk_rng->dev);
++
++ return (ret < 0) ? ret : to_read;
++}
++
++static const struct rk_rng_soc_data rk3568_soc_data = {
++ .rk_rng_init = rk3568_rng_init,
++ .rk_rng_read = rk3568_rng_read,
++ .rk_rng_cleanup = rk3568_rng_cleanup,
++ .quality = 900,
++ .reset_optional = false,
++};
++
++static const struct rk_rng_soc_data rk3588_soc_data = {
++ .rk_rng_init = rk3588_rng_init,
++ .rk_rng_read = rk3588_rng_read,
++ .rk_rng_cleanup = rk3588_rng_cleanup,
++ .quality = 999, /* as determined by actual testing */
++ .reset_optional = true,
++};
++
+ static int rk_rng_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -139,6 +324,7 @@ static int rk_rng_probe(struct platform_
+ if (!rk_rng)
+ return -ENOMEM;
+
++ rk_rng->soc_data = of_device_get_match_data(dev);
+ rk_rng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rk_rng->base))
+ return PTR_ERR(rk_rng->base);
+@@ -148,24 +334,30 @@ static int rk_rng_probe(struct platform_
+ return dev_err_probe(dev, rk_rng->clk_num,
+ "Failed to get clks property\n");
+
+- rst = devm_reset_control_array_get_exclusive(dev);
+- if (IS_ERR(rst))
+- return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset property\n");
+-
+- reset_control_assert(rst);
+- udelay(2);
+- reset_control_deassert(rst);
++ if (rk_rng->soc_data->reset_optional)
++ rst = devm_reset_control_array_get_optional_exclusive(dev);
++ else
++ rst = devm_reset_control_array_get_exclusive(dev);
++
++ if (rst) {
++ if (IS_ERR(rst))
++ return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset property\n");
++
++ reset_control_assert(rst);
++ udelay(2);
++ reset_control_deassert(rst);
++ }
+
+ platform_set_drvdata(pdev, rk_rng);
+
+ rk_rng->rng.name = dev_driver_string(dev);
+ if (!IS_ENABLED(CONFIG_PM)) {
+- rk_rng->rng.init = rk_rng_init;
+- rk_rng->rng.cleanup = rk_rng_cleanup;
++ rk_rng->rng.init = rk_rng->soc_data->rk_rng_init;
++ rk_rng->rng.cleanup = rk_rng->soc_data->rk_rng_cleanup;
+ }
+- rk_rng->rng.read = rk_rng_read;
++ rk_rng->rng.read = rk_rng->soc_data->rk_rng_read;
+ rk_rng->dev = dev;
+- rk_rng->rng.quality = 900;
++ rk_rng->rng.quality = rk_rng->soc_data->quality;
+
+ pm_runtime_set_autosuspend_delay(dev, RK_RNG_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(dev);
+@@ -184,7 +376,7 @@ static int __maybe_unused rk_rng_runtime
+ {
+ struct rk_rng *rk_rng = dev_get_drvdata(dev);
+
+- rk_rng_cleanup(&rk_rng->rng);
++ rk_rng->soc_data->rk_rng_cleanup(&rk_rng->rng);
+
+ return 0;
+ }
+@@ -193,7 +385,7 @@ static int __maybe_unused rk_rng_runtime
+ {
+ struct rk_rng *rk_rng = dev_get_drvdata(dev);
+
+- return rk_rng_init(&rk_rng->rng);
++ return rk_rng->soc_data->rk_rng_init(&rk_rng->rng);
+ }
+
+ static const struct dev_pm_ops rk_rng_pm_ops = {
+@@ -204,7 +396,8 @@ static const struct dev_pm_ops rk_rng_pm
+ };
+
+ static const struct of_device_id rk_rng_dt_match[] = {
+- { .compatible = "rockchip,rk3568-rng", },
++ { .compatible = "rockchip,rk3568-rng", .data = (void *)&rk3568_soc_data },
++ { .compatible = "rockchip,rk3588-rng", .data = (void *)&rk3588_soc_data },
+ { /* sentinel */ },
+ };
+
+@@ -221,8 +414,9 @@ static struct platform_driver rk_rng_dri
+
+ module_platform_driver(rk_rng_driver);
+
+-MODULE_DESCRIPTION("Rockchip RK3568 True Random Number Generator driver");
++MODULE_DESCRIPTION("Rockchip True Random Number Generator driver");
+ MODULE_AUTHOR("Lin Jinhan <troy.lin at rock-chips.com>");
+ MODULE_AUTHOR("Aurelien Jarno <aurelien at aurel32.net>");
+ MODULE_AUTHOR("Daniel Golle <daniel at makrotopia.org>");
++MODULE_AUTHOR("Nicolas Frattaroli <nicolas.frattaroli at collabora.com>");
+ MODULE_LICENSE("GPL");
diff --git a/target/linux/rockchip/patches-6.12/057-09-v6.15-arm64-dts-rockchip-Add-rng-node-to-RK3588.patch b/target/linux/rockchip/patches-6.12/057-09-v6.15-arm64-dts-rockchip-Add-rng-node-to-RK3588.patch
new file mode 100644
index 0000000000..db2dcd27b7
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-09-v6.15-arm64-dts-rockchip-Add-rng-node-to-RK3588.patch
@@ -0,0 +1,34 @@
+From 6ee0b9ad3995ee5fa229035c69013b7dd0d3634b Mon Sep 17 00:00:00 2001
+From: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Date: Tue, 4 Feb 2025 16:35:51 +0100
+Subject: [PATCH] arm64: dts: rockchip: Add rng node to RK3588
+
+Add the RK3588's standalone hardware random number generator node to its
+device tree, and enable it.
+
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
+Link: https://lore.kernel.org/r/20250204-rk3588-trng-submission-v2-6-608172b6fd91@collabora.com
+[changed reset-id to its numeric value while the constant makes its
+ way through the crypto tree]
+Signed-off-by: Heiko Stuebner <heiko at sntech.de>
+---
+ arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+@@ -1878,6 +1878,14 @@
+ status = "disabled";
+ };
+
++ rng at fe378000 {
++ compatible = "rockchip,rk3588-rng";
++ reg = <0x0 0xfe378000 0x0 0x200>;
++ interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH 0>;
++ clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
++ resets = <&scmi_reset 48>;
++ };
++
+ i2s0_8ch: i2s at fe470000 {
+ compatible = "rockchip,rk3588-i2s-tdm";
+ reg = <0x0 0xfe470000 0x0 0x1000>;
diff --git a/target/linux/rockchip/patches-6.12/057-10-v6.15-arm64-dts-rockchip-change-rng-reset-id-back-to-its-c.patch b/target/linux/rockchip/patches-6.12/057-10-v6.15-arm64-dts-rockchip-change-rng-reset-id-back-to-its-c.patch
new file mode 100644
index 0000000000..bc6865475f
--- /dev/null
+++ b/target/linux/rockchip/patches-6.12/057-10-v6.15-arm64-dts-rockchip-change-rng-reset-id-back-to-its-c.patch
@@ -0,0 +1,25 @@
+From 55a43c346d24434e46ef7fcc09a9df8179c346e4 Mon Sep 17 00:00:00 2001
+From: Heiko Stuebner <heiko at sntech.de>
+Date: Sun, 16 Feb 2025 16:27:42 +0100
+Subject: [PATCH] arm64: dts: rockchip: change rng reset id back to its
+ constant value
+
+With the binding header now providing the SCMI_SRST_H_TRNG_NS constant,
+switch back to it from the temporary numeric value.
+
+Signed-off-by: Heiko Stuebner <heiko at sntech.de>
+---
+ arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+@@ -1883,7 +1883,7 @@
+ reg = <0x0 0xfe378000 0x0 0x200>;
+ interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
+- resets = <&scmi_reset 48>;
++ resets = <&scmi_reset SCMI_SRST_H_TRNG_NS>;
+ };
+
+ i2s0_8ch: i2s at fe470000 {
More information about the lede-commits
mailing list