hwrng: stm32 - restrain RNG noise source clock under 3MHz

For NIST certification the noise source sampling must be 3 MHz or
less.

This change implements an algorithm that gets the rate of the RNG
clock and apply the correct value in CLKDIV field in RNG_CR register
to force the RNG clock rate to be 3MHz maximum.

Signed-off-by: Gatien Chevallier <gatien.chevallier@foss.st.com>
Change-Id: I0446f818d589b1a96f9d9145aff9b723ff985030
Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/linux-stm32/+/261071
Tested-by: Gatien CHEVALLIER <gatien.chevallier@st.com>
Reviewed-by: CITOOLS <MDG-smet-aci-reviews@list.st.com>
Reviewed-by: CIBUILD <MDG-smet-aci-builds@list.st.com>
Reviewed-by: Etienne CARRIERE <etienne.carriere@foss.st.com>
Reviewed-by: Gatien CHEVALLIER <gatien.chevallier@st.com>
This commit is contained in:
Gatien Chevallier
2022-07-19 15:03:56 +02:00
committed by Eric Fourmont
parent 4db5bfdeae
commit 9e41f30a36

View File

@ -33,6 +33,8 @@
#define RNG_NIST_CONFIG_B 0x1801000
#define RNG_NIST_CONFIG_MASK GENMASK(25, 8)
#define RNG_MAX_NOISE_CLK_FREQ 3000000
struct stm32_rng_data {
bool has_cond_reset;
};
@ -90,6 +92,28 @@ static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
return retval || !wait ? retval : -EIO;
}
static uint stm32_rng_clock_freq_restrain(struct hwrng *rng)
{
struct stm32_rng_private *priv =
container_of(rng, struct stm32_rng_private, rng);
unsigned long clock_rate = 0;
uint clock_div = 0;
clock_rate = clk_get_rate(priv->clk);
/*
* Get the exponent to apply on the CLKDIV field in RNG_CR register
* No need to handle the case when clock-div > 0xF as it is physically
* impossible
*/
while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ)
clock_div++;
pr_debug("RNG clk rate : %lu\n", clk_get_rate(priv->clk) >> clock_div);
return clock_div;
}
static int stm32_rng_init(struct hwrng *rng)
{
struct stm32_rng_private *priv =
@ -106,8 +130,10 @@ static int stm32_rng_init(struct hwrng *rng)
if (!priv->ced) {
reg |= RNG_CR_CED;
if (priv->data->has_cond_reset) {
uint clock_div = stm32_rng_clock_freq_restrain(rng);
reg &= ~RNG_NIST_CONFIG_MASK;
reg |= RNG_CR_CONDRST | RNG_NIST_CONFIG_B;
reg |= RNG_CR_CONDRST | RNG_NIST_CONFIG_B | clock_div;
writel_relaxed(reg, priv->base + RNG_CR);
reg &= ~RNG_CR_CONDRST;
reg |= RNG_CR_CONFLOCK;