On 2023/4/8 05:32, Chris Morgan wrote:
From: Chris Morgan <[email protected]>

This adds support for the TRNG found in the RK3588 SoC to the
rockchip_rng driver so that it can be used for things such as
seeding randomness to Linux.

This code was taken wholesale from the Rockchip BSP U-Boot source
located here:
https://github.com/rockchip-linux/u-boot/commit/09f31aed858c36a8a5ee20789712e65bb4762068

Tested on an Indiedroid Nova with an RK3588s.

This code info and test info should be present at cover letter instead of patch commit message, please update it.

otherwise

Reviewed-by: Kever Yang <[email protected]>

Thanks,
- Kever


Changes in V2:
  - Modified Kconfig to note that the Rockchip RNG driver supports all
    versions of the hardware (v1, v2, and the trng in the rk3588).

Signed-off-by: Lin Jinhan <[email protected]>
Signed-off-by: Chris Morgan <[email protected]>

---
  drivers/rng/Kconfig        |   5 +-
  drivers/rng/rockchip_rng.c | 120 ++++++++++++++++++++++++++++++++++---
  2 files changed, 114 insertions(+), 11 deletions(-)

diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index 5dcf68176a..5deb5db5b7 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -58,8 +58,9 @@ config RNG_ROCKCHIP
        bool "Enable random number generator for rockchip crypto rng"
        depends on ARCH_ROCKCHIP && DM_RNG
        help
-         Enable random number generator for rockchip.This driver is
-         support rng module of crypto v1 and crypto v2.
+         Enable random number generator for rockchip. This driver
+         supports the rng module of crypto v1, crypto v2, and the
+         trng module of the rk3588 series.
config RNG_IPROC200
        bool "Broadcom iProc RNG200 random number generator"
diff --git a/drivers/rng/rockchip_rng.c b/drivers/rng/rockchip_rng.c
index 800150f114..705b424cf3 100644
--- a/drivers/rng/rockchip_rng.c
+++ b/drivers/rng/rockchip_rng.c
@@ -43,9 +43,41 @@
  #define CRYPTO_V2_RNG_DOUT_0                  0x0410
  /* end of CRYPTO V2 register define */
+/* start of TRNG V1 register define */
+#define TRNG_V1_CTRL                           0x0000
+#define TRNG_V1_CTRL_NOP                       _SBF(0, 0x00)
+#define TRNG_V1_CTRL_RAND                      _SBF(0, 0x01)
+#define TRNG_V1_CTRL_SEED                      _SBF(0, 0x02)
+
+#define TRNG_V1_MODE                           0x0008
+#define TRNG_V1_MODE_128_BIT                   _SBF(3, 0x00)
+#define TRNG_V1_MODE_256_BIT                   _SBF(3, 0x01)
+
+#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
+
+#define TRNG_V1_AUTO_RQSTS                     0x0060
+
+#define TRNG_V1_VERSION                                0x00F0
+#define TRNG_v1_VERSION_CODE                   0x46BC
+/* end of TRNG V1 register define */
+
  #define RK_RNG_TIME_OUT       50000  /* max 50ms */
+#define trng_write(pdata, pos, val) writel(val, (pdata)->base + (pos))
+#define trng_read(pdata, pos)          readl((pdata)->base + (pos))
+
  struct rk_rng_soc_data {
+       int (*rk_rng_init)(struct udevice *dev);
        int (*rk_rng_read)(struct udevice *dev, void *data, size_t len);
  };
@@ -75,7 +107,7 @@ static int rk_rng_read_regs(fdt_addr_t addr, void *buf, size_t size)
        return 0;
  }
-static int rk_v1_rng_read(struct udevice *dev, void *data, size_t len)
+static int rk_cryptov1_rng_read(struct udevice *dev, void *data, size_t len)
  {
        struct rk_rng_plat *pdata = dev_get_priv(dev);
        u32 reg = 0;
@@ -106,7 +138,7 @@ exit:
        return 0;
  }
-static int rk_v2_rng_read(struct udevice *dev, void *data, size_t len)
+static int rk_cryptov2_rng_read(struct udevice *dev, void *data, size_t len)
  {
        struct rk_rng_plat *pdata = dev_get_priv(dev);
        u32 reg = 0;
@@ -140,6 +172,63 @@ exit:
        return retval;
  }
+static int rk_trngv1_init(struct udevice *dev)
+{
+       u32 status, version;
+       u32 auto_reseed_cnt = 1000;
+       struct rk_rng_plat *pdata = dev_get_priv(dev);
+
+       version = trng_read(pdata, TRNG_V1_VERSION);
+       if (version != TRNG_v1_VERSION_CODE) {
+               printf("wrong trng version, expected = %08x, actual = %08x",
+                      TRNG_V1_VERSION, version);
+               return -EFAULT;
+       }
+
+       /* wait in case of RND_RDY triggered at firs power on */
+       readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, status,
+                          (status & TRNG_V1_ISTAT_RAND_RDY),
+                          RK_RNG_TIME_OUT);
+
+       /* clear RAND_RDY flag for first power on */
+       trng_write(pdata, TRNG_V1_ISTAT, status);
+
+       /* auto reseed after (auto_reseed_cnt * 16) byte rand generate */
+       trng_write(pdata, TRNG_V1_AUTO_RQSTS, auto_reseed_cnt);
+
+       return 0;
+}
+
+static int rk_trngv1_rng_read(struct udevice *dev, void *data, size_t len)
+{
+       struct rk_rng_plat *pdata = dev_get_priv(dev);
+       u32 reg = 0;
+       int retval;
+
+       if (len > RK_HW_RNG_MAX)
+               return -EINVAL;
+
+       trng_write(pdata, TRNG_V1_MODE, TRNG_V1_MODE_256_BIT);
+       trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_RAND);
+
+       retval = readl_poll_timeout(pdata->base + TRNG_V1_ISTAT, reg,
+                                   (reg & TRNG_V1_ISTAT_RAND_RDY),
+                                   RK_RNG_TIME_OUT);
+       /* clear ISTAT */
+       trng_write(pdata, TRNG_V1_ISTAT, reg);
+
+       if (retval)
+               goto exit;
+
+       rk_rng_read_regs(pdata->base + TRNG_V1_RAND0, data, len);
+
+exit:
+       /* close TRNG */
+       trng_write(pdata, TRNG_V1_CTRL, TRNG_V1_CTRL_NOP);
+
+       return retval;
+}
+
  static int rockchip_rng_read(struct udevice *dev, void *data, size_t len)
  {
        unsigned char *buf = data;
@@ -184,18 +273,27 @@ static int rockchip_rng_of_to_plat(struct udevice *dev)
  static int rockchip_rng_probe(struct udevice *dev)
  {
        struct rk_rng_plat *pdata = dev_get_priv(dev);
+       int ret = 0;
pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev); - return 0;
+       if (pdata->soc_data->rk_rng_init)
+               ret = pdata->soc_data->rk_rng_init(dev);
+
+       return ret;
  }
-static const struct rk_rng_soc_data rk_rng_v1_soc_data = {
-       .rk_rng_read = rk_v1_rng_read,
+static const struct rk_rng_soc_data rk_cryptov1_soc_data = {
+       .rk_rng_read = rk_cryptov1_rng_read,
+};
+
+static const struct rk_rng_soc_data rk_cryptov2_soc_data = {
+       .rk_rng_read = rk_cryptov2_rng_read,
  };
-static const struct rk_rng_soc_data rk_rng_v2_soc_data = {
-       .rk_rng_read = rk_v2_rng_read,
+static const struct rk_rng_soc_data rk_trngv1_soc_data = {
+       .rk_rng_init = rk_trngv1_init,
+       .rk_rng_read = rk_trngv1_rng_read,
  };
static const struct dm_rng_ops rockchip_rng_ops = {
@@ -205,11 +303,15 @@ static const struct dm_rng_ops rockchip_rng_ops = {
  static const struct udevice_id rockchip_rng_match[] = {
        {
                .compatible = "rockchip,cryptov1-rng",
-               .data = (ulong)&rk_rng_v1_soc_data,
+               .data = (ulong)&rk_cryptov1_soc_data,
        },
        {
                .compatible = "rockchip,cryptov2-rng",
-               .data = (ulong)&rk_rng_v2_soc_data,
+               .data = (ulong)&rk_cryptov2_soc_data,
+       },
+       {
+               .compatible = "rockchip,trngv1",
+               .data = (ulong)&rk_trngv1_soc_data,
        },
        {},
  };

Reply via email to