rng: Add Qualcomm MSM PRNG driver
Add support for the hardware pseudo random number generator found in Qualcomm SoC-s. Signed-off-by: Robert Marko <robert.marko@sartura.hr> Cc: Luka Perkov <luka.perkov@sartura.hr>
This commit is contained in:
parent
5297341ab1
commit
033ec636fc
@ -243,6 +243,7 @@ F: drivers/reset/reset-ipq4019.c
|
|||||||
F: drivers/phy/phy-qcom-ipq4019-usb.c
|
F: drivers/phy/phy-qcom-ipq4019-usb.c
|
||||||
F: drivers/spi/spi-qup.c
|
F: drivers/spi/spi-qup.c
|
||||||
F: drivers/net/mdio-ipq4019.c
|
F: drivers/net/mdio-ipq4019.c
|
||||||
|
F: drivers/rng/msm_rng.c
|
||||||
|
|
||||||
ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K
|
ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K
|
||||||
M: Stefan Roese <sr@denx.de>
|
M: Stefan Roese <sr@denx.de>
|
||||||
|
@ -24,6 +24,13 @@ config RNG_SANDBOX
|
|||||||
Enable random number generator for sandbox. This is an
|
Enable random number generator for sandbox. This is an
|
||||||
emulation of a rng device.
|
emulation of a rng device.
|
||||||
|
|
||||||
|
config RNG_MSM
|
||||||
|
bool "Qualcomm SoCs Random Number Generator support"
|
||||||
|
depends on DM_RNG
|
||||||
|
help
|
||||||
|
This driver provides support for the Random Number
|
||||||
|
Generator hardware found on Qualcomm SoCs.
|
||||||
|
|
||||||
config RNG_STM32MP1
|
config RNG_STM32MP1
|
||||||
bool "Enable random number generator for STM32MP1"
|
bool "Enable random number generator for STM32MP1"
|
||||||
depends on ARCH_STM32MP
|
depends on ARCH_STM32MP
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
obj-$(CONFIG_DM_RNG) += rng-uclass.o
|
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_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
|
||||||
|
143
drivers/rng/msm_rng.c
Normal file
143
drivers/rng/msm_rng.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* PRNG driver for Qualcomm IPQ40xx
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Sartura Ltd.
|
||||||
|
*
|
||||||
|
* Author: Robert Marko <robert.marko@sartura.hr>
|
||||||
|
*
|
||||||
|
* Based on Linux driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <clk.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <rng.h>
|
||||||
|
|
||||||
|
/* Device specific register offsets */
|
||||||
|
#define PRNG_DATA_OUT 0x0000
|
||||||
|
#define PRNG_STATUS 0x0004
|
||||||
|
#define PRNG_LFSR_CFG 0x0100
|
||||||
|
#define PRNG_CONFIG 0x0104
|
||||||
|
|
||||||
|
/* Device specific register masks and config values */
|
||||||
|
#define PRNG_LFSR_CFG_MASK 0x0000ffff
|
||||||
|
#define PRNG_LFSR_CFG_CLOCKS 0x0000dddd
|
||||||
|
#define PRNG_CONFIG_HW_ENABLE BIT(1)
|
||||||
|
#define PRNG_STATUS_DATA_AVAIL BIT(0)
|
||||||
|
|
||||||
|
#define MAX_HW_FIFO_DEPTH 16
|
||||||
|
#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4)
|
||||||
|
#define WORD_SZ 4
|
||||||
|
|
||||||
|
struct msm_rng_priv {
|
||||||
|
phys_addr_t base;
|
||||||
|
struct clk clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int msm_rng_read(struct udevice *dev, void *data, size_t len)
|
||||||
|
{
|
||||||
|
struct msm_rng_priv *priv = dev_get_priv(dev);
|
||||||
|
size_t currsize = 0;
|
||||||
|
u32 *retdata = data;
|
||||||
|
size_t maxsize;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* calculate max size bytes to transfer back to caller */
|
||||||
|
maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, len);
|
||||||
|
|
||||||
|
/* read random data from hardware */
|
||||||
|
do {
|
||||||
|
val = readl_relaxed(priv->base + PRNG_STATUS);
|
||||||
|
if (!(val & PRNG_STATUS_DATA_AVAIL))
|
||||||
|
break;
|
||||||
|
|
||||||
|
val = readl_relaxed(priv->base + PRNG_DATA_OUT);
|
||||||
|
if (!val)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*retdata++ = val;
|
||||||
|
currsize += WORD_SZ;
|
||||||
|
|
||||||
|
/* make sure we stay on 32bit boundary */
|
||||||
|
if ((maxsize - currsize) < WORD_SZ)
|
||||||
|
break;
|
||||||
|
} while (currsize < maxsize);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm_rng_enable(struct msm_rng_priv *priv, int enable)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
/* Enable PRNG only if it is not already enabled */
|
||||||
|
val = readl_relaxed(priv->base + PRNG_CONFIG);
|
||||||
|
if (val & PRNG_CONFIG_HW_ENABLE) {
|
||||||
|
val = readl_relaxed(priv->base + PRNG_LFSR_CFG);
|
||||||
|
val &= ~PRNG_LFSR_CFG_MASK;
|
||||||
|
val |= PRNG_LFSR_CFG_CLOCKS;
|
||||||
|
writel(val, priv->base + PRNG_LFSR_CFG);
|
||||||
|
|
||||||
|
val = readl_relaxed(priv->base + PRNG_CONFIG);
|
||||||
|
val |= PRNG_CONFIG_HW_ENABLE;
|
||||||
|
writel(val, priv->base + PRNG_CONFIG);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val = readl_relaxed(priv->base + PRNG_CONFIG);
|
||||||
|
val &= ~PRNG_CONFIG_HW_ENABLE;
|
||||||
|
writel(val, priv->base + PRNG_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm_rng_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct msm_rng_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv->base = dev_read_addr(dev);
|
||||||
|
if (priv->base == FDT_ADDR_T_NONE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = clk_get_by_index(dev, 0, &priv->clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_enable(&priv->clk);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return msm_rng_enable(priv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm_rng_remove(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct msm_rng_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
return msm_rng_enable(priv, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dm_rng_ops msm_rng_ops = {
|
||||||
|
.read = msm_rng_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct udevice_id msm_rng_match[] = {
|
||||||
|
{ .compatible = "qcom,prng", },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(msm_rng) = {
|
||||||
|
.name = "msm-rng",
|
||||||
|
.id = UCLASS_RNG,
|
||||||
|
.of_match = msm_rng_match,
|
||||||
|
.ops = &msm_rng_ops,
|
||||||
|
.probe = msm_rng_probe,
|
||||||
|
.remove = msm_rng_remove,
|
||||||
|
.priv_auto_alloc_size = sizeof(struct msm_rng_priv),
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user