rng: nuvoton: Add NPCM7xx rng driver

Add Nuvoton BMC NPCM750 rng driver.

Signed-off-by: Jim Liu <JJLIU0@nuvoton.com>
This commit is contained in:
Jim Liu 2022-05-24 16:56:57 +08:00 committed by Tom Rini
parent b5d3625f27
commit 866eab1d28
3 changed files with 164 additions and 0 deletions

View file

@ -31,6 +31,13 @@ config RNG_MSM
This driver provides support for the Random Number This driver provides support for the Random Number
Generator hardware found on Qualcomm SoCs. Generator hardware found on Qualcomm SoCs.
config RNG_NPCM
bool "Nuvoton NPCM SoCs Random Number Generator support"
depends on DM_RNG
help
Enable random number generator on NPCM SoCs.
This unit can provide 750 to 1000 random bits per second
config RNG_OPTEE config RNG_OPTEE
bool "OP-TEE based Random Number Generator support" bool "OP-TEE based Random Number Generator support"
depends on DM_RNG && OPTEE depends on DM_RNG && OPTEE

View file

@ -7,6 +7,7 @@ obj-$(CONFIG_DM_RNG) += rng-uclass.o
obj-$(CONFIG_RNG_MESON) += meson-rng.o obj-$(CONFIG_RNG_MESON) += meson-rng.o
obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o
obj-$(CONFIG_RNG_MSM) += msm_rng.o obj-$(CONFIG_RNG_MSM) += msm_rng.o
obj-$(CONFIG_RNG_NPCM) += npcm_rng.o
obj-$(CONFIG_RNG_OPTEE) += optee_rng.o obj-$(CONFIG_RNG_OPTEE) += optee_rng.o
obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o
obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o

156
drivers/rng/npcm_rng.c Normal file
View file

@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2022 Nuvoton Technology Corp.
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <rng.h>
#include <uboot_aes.h>
#include <asm/io.h>
#define RNGCS_RNGE BIT(0)
#define RNGCS_DVALID BIT(1)
#define RNGCS_CLKP(range) ((0x0f & (range)) << 2)
#define RNGMODE_M1ROSEL_VAL (0x02) /* Ring Oscillator Select for Method I */
enum {
RNG_CLKP_80_100_MHZ = 0x00, /*default */
RNG_CLKP_60_80_MHZ = 0x01,
RNG_CLKP_50_60_MHZ = 0x02,
RNG_CLKP_40_50_MHZ = 0x03,
RNG_CLKP_30_40_MHZ = 0x04,
RNG_CLKP_25_30_MHZ = 0x05,
RNG_CLKP_20_25_MHZ = 0x06,
RNG_CLKP_5_20_MHZ = 0x07,
RNG_CLKP_2_15_MHZ = 0x08,
RNG_CLKP_9_12_MHZ = 0x09,
RNG_CLKP_7_9_MHZ = 0x0A,
RNG_CLKP_6_7_MHZ = 0x0B,
RNG_CLKP_5_6_MHZ = 0x0C,
RNG_CLKP_4_5_MHZ = 0x0D,
RNG_CLKP_3_4_MHZ = 0x0E,
RNG_NUM_OF_CLKP
};
struct npcm_rng_regs {
unsigned int rngcs;
unsigned int rngd;
unsigned int rngmode;
};
struct npcm_rng_priv {
struct npcm_rng_regs *regs;
};
static struct npcm_rng_priv *rng_priv;
void npcm_rng_init(void)
{
struct npcm_rng_regs *regs = rng_priv->regs;
int init;
/* check if rng enabled */
init = readb(&regs->rngcs);
if ((init & RNGCS_RNGE) == 0) {
/* init rng */
writeb(RNGCS_CLKP(RNG_CLKP_20_25_MHZ) | RNGCS_RNGE, &regs->rngcs);
writeb(RNGMODE_M1ROSEL_VAL, &regs->rngmode);
}
}
void npcm_rng_disable(void)
{
struct npcm_rng_regs *regs = rng_priv->regs;
/* disable rng */
writeb(0, &regs->rngcs);
writeb(0, &regs->rngmode);
}
void srand(unsigned int seed)
{
/* no need to seed for now */
}
int npcm_rng_read(struct udevice *dev, void *data, size_t max)
{
struct npcm_rng_regs *regs = rng_priv->regs;
int i;
int ret_val = 0;
char *buf = data;
npcm_rng_init();
printf("NPCM HW RNG\n");
/* Wait for RNG done (max bytes) */
for (i = 0; i < max; i++) {
/* wait until DVALID is set */
while ((readb(&regs->rngcs) & RNGCS_DVALID) == 0)
;
buf[i] = ((unsigned int)readb(&regs->rngd) & 0x000000FF);
}
return ret_val;
}
unsigned int rand_r(unsigned int *seedp)
{
struct npcm_rng_regs *regs = rng_priv->regs;
int i;
unsigned int ret_val = 0;
npcm_rng_init();
/* Wait for RNG done (4 bytes) */
for (i = 0; i < 4 ; i++) {
/* wait until DVALID is set */
while ((readb(&regs->rngcs) & RNGCS_DVALID) == 0)
;
ret_val |= (((unsigned int)readb(&regs->rngd) & 0x000000FF) << (i * 8));
}
return ret_val;
}
unsigned int rand(void)
{
return rand_r(NULL);
}
static int npcm_rng_bind(struct udevice *dev)
{
rng_priv = calloc(1, sizeof(struct npcm_rng_priv));
if (!rng_priv)
return -ENOMEM;
rng_priv->regs = dev_remap_addr_index(dev, 0);
if (!rng_priv->regs) {
printf("Cannot find rng reg address, binding failed\n");
return -EINVAL;
}
printf("RNG: NPCM RNG module bind OK\n");
return 0;
}
static const struct udevice_id npcm_rng_ids[] = {
{ .compatible = "nuvoton,npcm845-rng" },
{ .compatible = "nuvoton,npcm750-rng" },
{ }
};
static const struct dm_rng_ops npcm_rng_ops = {
.read = npcm_rng_read,
};
U_BOOT_DRIVER(npcm_rng) = {
.name = "npcm_rng",
.id = UCLASS_RNG,
.ops = &npcm_rng_ops,
.of_match = npcm_rng_ids,
.priv_auto = sizeof(struct npcm_rng_priv),
.bind = npcm_rng_bind,
};