[PATCH v2 1/3] Uboot RNG Driver using Data Co-processor

Kshitiz Varshney kshitiz.varshney at nxp.com
Thu Dec 22 09:50:27 CET 2022


This commit introduces Random number generator to uboot. It uses DCP
driver for number generation.
RNG driver can be invoked by using below command on uboot prompt:-
           rng <number of bytes>

Signed-off-by: Kshitiz Varshney <kshitiz.varshney at nxp.com>
Reviewed-by: Ye Li <ye.li at nxp.com>
Reviewed-by: Simon Glass <sjg at chromium.org>
---
 drivers/crypto/fsl/Kconfig   |  10 ++
 drivers/crypto/fsl/Makefile  |   1 +
 drivers/crypto/fsl/dcp_rng.c | 182 +++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/crypto/fsl/dcp_rng.c

diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index b04c70183d..91a51cc5fe 100644
--- a/drivers/crypto/fsl/Kconfig
+++ b/drivers/crypto/fsl/Kconfig
@@ -73,3 +73,13 @@ config FSL_CAAM_RNG
 	  reseeded from the TRNG every time random data is generated.
 
 endif
+
+config FSL_DCP_RNG
+	bool "Enable Random Number Generator support"
+	depends on DM_RNG
+	default n
+	help
+	  Enable support for the hardware based random number generator
+	  module of the DCP. It uses the True Random Number Generator (TRNG)
+	  and a Pseudo-Random Number Generator (PRNG) to achieve a true
+	  randomness and cryptographic strength.
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index f9c3ccecfc..7a2543e16c 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -7,4 +7,5 @@ obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
 obj-$(CONFIG_CMD_BLOB)$(CONFIG_IMX_CAAM_DEK_ENCAP) += fsl_blob.o
 obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
 obj-$(CONFIG_FSL_CAAM_RNG) += rng.o
+obj-$(CONFIG_FSL_DCP_RNG) += dcp_rng.o
 obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o
diff --git a/drivers/crypto/fsl/dcp_rng.c b/drivers/crypto/fsl/dcp_rng.c
new file mode 100644
index 0000000000..3170696015
--- /dev/null
+++ b/drivers/crypto/fsl/dcp_rng.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RNG driver for Freescale RNGC
+ *
+ * Copyright 2022 NXP
+ *
+ * Based on RNGC driver in drivers/char/hw_random/imx-rngc.c in Linux
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <rng.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <dm/root.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+
+#define DCP_RNG_MAX_FIFO_STORE_SIZE	4
+#define RNGC_VER_ID			0x0
+#define RNGC_COMMAND			0x4
+#define RNGC_CONTROL			0x8
+#define RNGC_STATUS			0xC
+#define RNGC_ERROR			0x10
+#define RNGC_FIFO			0x14
+
+/* the fields in the ver id register */
+#define RNGC_TYPE_SHIFT			28
+
+/* the rng_type field */
+#define RNGC_TYPE_RNGB			0x1
+#define RNGC_TYPE_RNGC			0x2
+
+#define RNGC_CMD_CLR_ERR		0x20
+#define RNGC_CMD_SEED			0x2
+
+#define RNGC_CTRL_AUTO_SEED		0x10
+
+#define RNGC_STATUS_ERROR		0x10000
+#define RNGC_STATUS_FIFO_LEVEL_MASK	0xf00
+#define RNGC_STATUS_FIFO_LEVEL_SHIFT	8
+#define RNGC_STATUS_SEED_DONE		0x20
+#define RNGC_STATUS_ST_DONE		0x10
+
+#define RNGC_ERROR_STATUS_STAT_ERR	0x8
+
+#define RNGC_TIMEOUT			3000000U /* 3 sec */
+
+struct imx_rngc_priv {
+	unsigned long base;
+};
+
+static int rngc_read(struct udevice *dev, void *data, size_t len)
+{
+	struct imx_rngc_priv *priv = dev_get_priv(dev);
+	u8 buffer[DCP_RNG_MAX_FIFO_STORE_SIZE];
+	u32 status, level;
+	size_t size;
+
+	while (len) {
+		status = readl(priv->base + RNGC_STATUS);
+
+		/* is there some error while reading this random number? */
+		if (status & RNGC_STATUS_ERROR)
+			break;
+		/* how many random numbers are in FIFO? [0-16] */
+		level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >>
+			RNGC_STATUS_FIFO_LEVEL_SHIFT;
+
+		if (level) {
+			/* retrieve a random number from FIFO */
+			*(u32 *)buffer = readl(priv->base + RNGC_FIFO);
+			size = min(len, sizeof(u32));
+			memcpy(data, buffer, size);
+			data += size;
+			len -= size;
+		}
+	}
+
+	return len ? -EIO : 0;
+}
+
+static int rngc_init(struct imx_rngc_priv *priv)
+{
+	u32 cmd, ctrl, status, err_reg = 0;
+	unsigned long long timeval = 0;
+	unsigned long long timeout = RNGC_TIMEOUT;
+
+	/* clear error */
+	cmd = readl(priv->base + RNGC_COMMAND);
+	writel(cmd | RNGC_CMD_CLR_ERR, priv->base + RNGC_COMMAND);
+
+	/* create seed, repeat while there is some statistical error */
+	do {
+		/* seed creation */
+		cmd = readl(priv->base + RNGC_COMMAND);
+		writel(cmd | RNGC_CMD_SEED, priv->base + RNGC_COMMAND);
+
+		udelay(1);
+		timeval += 1;
+
+		status = readl(priv->base + RNGC_STATUS);
+		err_reg = readl(priv->base + RNGC_ERROR);
+
+		if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE))
+			break;
+
+		if (timeval > timeout) {
+			debug("rngc timed out\n");
+			return -ETIMEDOUT;
+		}
+	} while (err_reg == RNGC_ERROR_STATUS_STAT_ERR);
+
+	if (err_reg)
+		return -EIO;
+
+	/*
+	 * enable automatic seeding, the rngc creates a new seed automatically
+	 * after serving 2^20 random 160-bit words
+	 */
+	ctrl = readl(priv->base + RNGC_CONTROL);
+	ctrl |= RNGC_CTRL_AUTO_SEED;
+	writel(ctrl, priv->base + RNGC_CONTROL);
+	return 0;
+}
+
+static int rngc_probe(struct udevice *dev)
+{
+	struct imx_rngc_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	u32 ver_id;
+	u8  rng_type;
+	int ret;
+
+	addr = dev_read_addr(dev);
+	if (addr == FDT_ADDR_T_NONE) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	priv->base = addr;
+	ver_id = readl(priv->base + RNGC_VER_ID);
+	rng_type = ver_id >> RNGC_TYPE_SHIFT;
+	/*
+	 * This driver supports only RNGC and RNGB. (There's a different
+	 * driver for RNGA.)
+	 */
+	if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = rngc_init(priv);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	printf("%s error = %d\n", __func__, ret);
+	return ret;
+}
+
+static const struct dm_rng_ops rngc_ops = {
+	.read = rngc_read,
+};
+
+static const struct udevice_id rngc_dt_ids[] = {
+	{ .compatible = "fsl,imx25-rngb" },
+	{ }
+};
+
+U_BOOT_DRIVER(dcp_rng) = {
+	.name = "dcp_rng",
+	.id = UCLASS_RNG,
+	.of_match = rngc_dt_ids,
+	.ops = &rngc_ops,
+	.probe = rngc_probe,
+	.priv_auto  = sizeof(struct imx_rngc_priv),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
-- 
2.25.1



More information about the U-Boot mailing list