Uboot RNG Driver using Data Co-processor
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@nxp.com> Reviewed-by: Ye Li <ye.li@nxp.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
cf7aa03543
commit
0d795c356a
@ -73,3 +73,13 @@ config FSL_CAAM_RNG
|
|||||||
reseeded from the TRNG every time random data is generated.
|
reseeded from the TRNG every time random data is generated.
|
||||||
|
|
||||||
endif
|
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.
|
||||||
|
@ -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_CMD_BLOB)$(CONFIG_IMX_CAAM_DEK_ENCAP) += fsl_blob.o
|
||||||
obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
|
obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
|
||||||
obj-$(CONFIG_FSL_CAAM_RNG) += rng.o
|
obj-$(CONFIG_FSL_CAAM_RNG) += rng.o
|
||||||
|
obj-$(CONFIG_FSL_DCP_RNG) += dcp_rng.o
|
||||||
obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o
|
obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o
|
||||||
|
182
drivers/crypto/fsl/dcp_rng.c
Normal file
182
drivers/crypto/fsl/dcp_rng.c
Normal file
@ -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,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user