
-----Original Message----- From: U-Boot u-boot-bounces@lists.denx.de On Behalf Of Chanho Park Sent: Wednesday, November 1, 2023 8:55 AM To: Sughosh Ganu sughosh.ganu@linaro.org; Heinrich Schuchardt xypron.glpk@gmx.de; Rick Chen rick@andestech.com; Leo ycliang@andestech.com; u-boot@lists.denx.de Cc: Chanho Park chanho61.park@samsung.com Subject: [PATCH v2 3/5] rng: Add StarFive JH7110 RNG driver
Adds to support JH7110 TRNG driver which is based on linux kernel's jh7110-trng.c. This can support to generate 256-bit random numbers and 128-bit but this makes 256-bit default for convenience.
Signed-off-by: Chanho Park chanho61.park@samsung.com
drivers/rng/Kconfig | 6 + drivers/rng/Makefile | 1 + drivers/rng/jh7110_rng.c | 258 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 drivers/rng/jh7110_rng.c
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index 994cc35b2744..0dba1e06b429 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -91,4 +91,10 @@ config TPM_RNG functionality. Enable random number generator on TPM devices.
+config RNG_JH7110
- bool "StarFive JH7110 Random Number Generator support"
- depends on DM_RNG && STARFIVE_JH7110
- help
Enable True Random Number Generator in StarFive JH7110 SoCs.
endif diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index 47b323e61ee3..9de762c8a1c3 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o obj-$(CONFIG_RNG_ARM_RNDR) += arm_rndr.o obj-$(CONFIG_TPM_RNG) += tpm_rng.o +obj-$(CONFIG_RNG_JH7110) += jh7110_rng.o diff --git a/drivers/rng/jh7110_rng.c b/drivers/rng/jh7110_rng.c new file mode 100644 index 000000000000..37ea8cc39945 --- /dev/null +++ b/drivers/rng/jh7110_rng.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- TRNG driver for the StarFive JH7110 SoC
- */
+#include <clk.h> +#include <dm.h> +#include <reset.h> +#include <rng.h> +#include <asm/io.h> +#include <linux/iopoll.h>
+/* trng register offset */ +#define STARFIVE_CTRL 0x00 +#define STARFIVE_STAT 0x04 +#define STARFIVE_MODE 0x08 +#define STARFIVE_SMODE 0x0C +#define STARFIVE_IE 0x10 +#define STARFIVE_ISTAT 0x14 +#define STARFIVE_RAND0 0x20 +#define STARFIVE_RAND1 0x24 +#define STARFIVE_RAND2 0x28 +#define STARFIVE_RAND3 0x2C +#define STARFIVE_RAND4 0x30 +#define STARFIVE_RAND5 0x34 +#define STARFIVE_RAND6 0x38 +#define STARFIVE_RAND7 0x3C +#define STARFIVE_AUTO_RQSTS 0x60 +#define STARFIVE_AUTO_AGE 0x64
+/* CTRL CMD */ +#define STARFIVE_CTRL_EXEC_NOP 0x0 +#define STARFIVE_CTRL_GENE_RANDNUM 0x1 +#define STARFIVE_CTRL_EXEC_RANDRESEED 0x2
+/* STAT */ +#define STARFIVE_STAT_NONCE_MODE BIT(2) +#define STARFIVE_STAT_R256 BIT(3) +#define STARFIVE_STAT_MISSION_MODE BIT(8) +#define STARFIVE_STAT_SEEDED BIT(9) +#define STARFIVE_STAT_LAST_RESEED(x) ((x) << 16) +#define STARFIVE_STAT_SRVC_RQST BIT(27) +#define STARFIVE_STAT_RAND_GENERATING BIT(30) +#define STARFIVE_STAT_RAND_SEEDING BIT(31) +#define STARFIVE_STAT_RUNNING (STARFIVE_STAT_RAND_GENERATING | \
STARFIVE_STAT_RAND_SEEDING)
+/* MODE */ +#define STARFIVE_MODE_R256 BIT(3)
+/* SMODE */ +#define STARFIVE_SMODE_NONCE_MODE BIT(2) +#define STARFIVE_SMODE_MISSION_MODE BIT(8) +#define STARFIVE_SMODE_MAX_REJECTS(x) ((x) << 16)
+/* IE */ +#define STARFIVE_IE_RAND_RDY_EN BIT(0) +#define STARFIVE_IE_SEED_DONE_EN BIT(1) +#define STARFIVE_IE_LFSR_LOCKUP_EN BIT(4) +#define STARFIVE_IE_GLBL_EN BIT(31)
+#define STARFIVE_IE_ALL (STARFIVE_IE_GLBL_EN | \
STARFIVE_IE_RAND_RDY_EN | \
STARFIVE_IE_SEED_DONE_EN | \
STARFIVE_IE_LFSR_LOCKUP_EN)
+/* ISTAT */ +#define STARFIVE_ISTAT_RAND_RDY BIT(0) +#define STARFIVE_ISTAT_SEED_DONE BIT(1) +#define STARFIVE_ISTAT_LFSR_LOCKUP BIT(4)
+#define STARFIVE_RAND_LEN sizeof(u32)
+enum mode {
- PRNG_128BIT,
- PRNG_256BIT,
+};
+struct starfive_trng_plat {
- void *base;
- struct clk *hclk;
- struct clk *ahb;
- struct reset_ctl *rst;
- u32 mode;
+};
+static inline int starfive_trng_wait_idle(struct starfive_trng_plat *trng) +{
- u32 stat;
- return readl_relaxed_poll_timeout(trng->base + STARFIVE_STAT, stat,
!(stat & STARFIVE_STAT_RUNNING),
100000);
+}
+static inline void starfive_trng_irq_mask_clear(struct starfive_trng_plat *trng) +{
- /* clear register: ISTAT */
- u32 data = readl(trng->base + STARFIVE_ISTAT);
- writel(data, trng->base + STARFIVE_ISTAT);
+}
+static int starfive_trng_cmd(struct starfive_trng_plat *trng, u32 cmd) +{
- u32 stat, flg;
- int ret;
- switch (cmd) {
- case STARFIVE_CTRL_GENE_RANDNUM:
writel(cmd, trng->base + STARFIVE_CTRL);
flg = STARFIVE_ISTAT_RAND_RDY;
break;
- case STARFIVE_CTRL_EXEC_RANDRESEED:
writel(cmd, trng->base + STARFIVE_CTRL);
flg = STARFIVE_ISTAT_SEED_DONE;
break;
- default:
return -EINVAL;
- }
- ret = readl_relaxed_poll_timeout(trng->base + STARFIVE_ISTAT, stat,
(stat & flg), 1000);
- writel(flg, trng->base + STARFIVE_ISTAT);
- return ret;
+}
+static int starfive_trng_read(struct udevice *dev, void *data, size_t len) +{
- struct starfive_trng_plat *trng = dev_get_plat(dev);
- u8 *buffer = data;
- int iter_mask;
- if (trng->mode == PRNG_256BIT)
iter_mask = 7;
- else
iter_mask = 3;
- for (int i = 0; len; ++i, i &= iter_mask) {
u32 val;
size_t step;
int ret;
ret = starfive_trng_cmd(trng, STARFIVE_CTRL_GENE_RANDNUM);
if (ret)
return ret;
val = readl(trng->base + STARFIVE_RAND0 +
(i * STARFIVE_RAND_LEN));
step = min_t(size_t, len, STARFIVE_RAND_LEN);
memcpy(buffer, &val, step);
buffer += step;
len -= step;
- }
- return 0;
+}
+static int starfive_trng_init(struct starfive_trng_plat *trng) +{
- u32 mode, intr = 0;
- /* setup Auto Request/Age register */
- writel(0, trng->base + STARFIVE_AUTO_AGE);
- writel(0, trng->base + STARFIVE_AUTO_RQSTS);
- /* clear register: ISTAT */
- starfive_trng_irq_mask_clear(trng);
- intr |= STARFIVE_IE_ALL;
- writel(intr, trng->base + STARFIVE_IE);
- mode = readl(trng->base + STARFIVE_MODE);
- switch (trng->mode) {
- case PRNG_128BIT:
mode &= ~STARFIVE_MODE_R256;
break;
- case PRNG_256BIT:
mode |= STARFIVE_MODE_R256;
break;
- default:
mode |= STARFIVE_MODE_R256;
break;
- }
- writel(mode, trng->base + STARFIVE_MODE);
- return starfive_trng_cmd(trng, STARFIVE_CTRL_EXEC_RANDRESEED);
+}
+static int starfive_trng_probe(struct udevice *dev) +{
- struct starfive_trng_plat *pdata = dev_get_plat(dev);
- int err;
- err = clk_enable(pdata->hclk);
- if (err)
return err;
- err = clk_enable(pdata->ahb);
- if (err)
Doesn't need to disable the previous clk about pdata->hclk?
return err;
- err = reset_deassert(pdata->rst);
- if (err)
Ditto about clocks of hclk and ahb?
How about handle error?
err = clk_enable(pdata->hclk); if (err) ...
err = clk_enable(pdata->ahb); if (err) goto err_ahb;
...
Return starfive_tring_init(pdata);
goto_err_reset: clk_disable(pdata->ahb); goto err_ahb: clk_disable(pdata->hclk);
return err;
return err;
- pdata->mode = PRNG_256BIT;
- return starfive_trng_init(pdata);
+}
+static int starfive_trng_of_to_plat(struct udevice *dev) +{
- struct starfive_trng_plat *pdata = dev_get_plat(dev);
- pdata->base = (void *)dev_read_addr(dev);
- if (!pdata->base)
return -ENODEV;
- pdata->hclk = devm_clk_get(dev, "hclk");
- if (IS_ERR(pdata->hclk))
return -ENODEV;
- pdata->ahb = devm_clk_get(dev, "ahb");
- if (IS_ERR(pdata->ahb))
return -ENODEV;
- pdata->rst = devm_reset_control_get(dev, NULL);
- if (IS_ERR(pdata->rst))
return -ENODEV;
- return 0;
+}
+static const struct dm_rng_ops starfive_trng_ops = {
- .read = starfive_trng_read,
+};
+static const struct udevice_id starfive_trng_match[] = {
- {
.compatible = "starfive,jh7110-trng",
- },
- {},
+};
+U_BOOT_DRIVER(starfive_trng) = {
- .name = "jh7110-trng",
- .id = UCLASS_RNG,
- .of_match = starfive_trng_match,
- .probe = starfive_trng_probe,
- .ops = &starfive_trng_ops,
- .plat_auto = sizeof(struct starfive_trng_plat),
- .of_to_plat = starfive_trng_of_to_plat,
+};
2.39.2