Commit 28d13f3f authored by Gatien Chevallier's avatar Gatien Chevallier Committed by Herbert Xu

hwrng: stm32 - restrain RNG noise source clock

For NIST certification the noise source sampling may need to be
restrained.

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 "max_clock_rate" maximum.

As it is platform-specific, implement it as a compat data.
Signed-off-by: default avatarGatien Chevallier <gatien.chevallier@foss.st.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent b17bc6eb
...@@ -23,11 +23,13 @@ ...@@ -23,11 +23,13 @@
#define RNG_CR_CONFIG1 GENMASK(11, 8) #define RNG_CR_CONFIG1 GENMASK(11, 8)
#define RNG_CR_NISTC BIT(12) #define RNG_CR_NISTC BIT(12)
#define RNG_CR_CONFIG2 GENMASK(15, 13) #define RNG_CR_CONFIG2 GENMASK(15, 13)
#define RNG_CR_CLKDIV_SHIFT 16
#define RNG_CR_CLKDIV GENMASK(19, 16)
#define RNG_CR_CONFIG3 GENMASK(25, 20) #define RNG_CR_CONFIG3 GENMASK(25, 20)
#define RNG_CR_CONDRST BIT(30) #define RNG_CR_CONDRST BIT(30)
#define RNG_CR_CONFLOCK BIT(31) #define RNG_CR_CONFLOCK BIT(31)
#define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3) #define RNG_CR_ENTROPY_SRC_MASK (RNG_CR_CONFIG1 | RNG_CR_NISTC | RNG_CR_CONFIG2 | RNG_CR_CONFIG3)
#define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED) #define RNG_CR_CONFIG_MASK (RNG_CR_ENTROPY_SRC_MASK | RNG_CR_CED | RNG_CR_CLKDIV)
#define RNG_SR 0x04 #define RNG_SR 0x04
#define RNG_SR_DRDY BIT(0) #define RNG_SR_DRDY BIT(0)
...@@ -46,6 +48,7 @@ ...@@ -46,6 +48,7 @@
#define RNG_NB_RECOVER_TRIES 3 #define RNG_NB_RECOVER_TRIES 3
struct stm32_rng_data { struct stm32_rng_data {
uint max_clock_rate;
u32 cr; u32 cr;
u32 nscr; u32 nscr;
u32 htcr; u32 htcr;
...@@ -238,6 +241,28 @@ static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) ...@@ -238,6 +241,28 @@ static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
return retval || !wait ? retval : -EIO; 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) > priv->data->max_clock_rate)
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) static int stm32_rng_init(struct hwrng *rng)
{ {
struct stm32_rng_private *priv = struct stm32_rng_private *priv =
...@@ -259,8 +284,11 @@ static int stm32_rng_init(struct hwrng *rng) ...@@ -259,8 +284,11 @@ static int stm32_rng_init(struct hwrng *rng)
* 0 is an invalid value as it disables all entropy sources. * 0 is an invalid value as it disables all entropy sources.
*/ */
if (priv->data->has_cond_reset && priv->data->cr) { if (priv->data->has_cond_reset && priv->data->cr) {
uint clock_div = stm32_rng_clock_freq_restrain(rng);
reg &= ~RNG_CR_CONFIG_MASK; reg &= ~RNG_CR_CONFIG_MASK;
reg |= RNG_CR_CONDRST | (priv->data->cr & RNG_CR_ENTROPY_SRC_MASK); reg |= RNG_CR_CONDRST | (priv->data->cr & RNG_CR_ENTROPY_SRC_MASK) |
(clock_div << RNG_CR_CLKDIV_SHIFT);
if (priv->ced) if (priv->ced)
reg &= ~RNG_CR_CED; reg &= ~RNG_CR_CED;
else else
...@@ -360,6 +388,7 @@ static const struct dev_pm_ops stm32_rng_pm_ops = { ...@@ -360,6 +388,7 @@ static const struct dev_pm_ops stm32_rng_pm_ops = {
static const struct stm32_rng_data stm32mp13_rng_data = { static const struct stm32_rng_data stm32mp13_rng_data = {
.has_cond_reset = true, .has_cond_reset = true,
.max_clock_rate = 48000000,
.cr = 0x00F00D00, .cr = 0x00F00D00,
.nscr = 0x2B5BB, .nscr = 0x2B5BB,
.htcr = 0x969D, .htcr = 0x969D,
...@@ -367,6 +396,7 @@ static const struct stm32_rng_data stm32mp13_rng_data = { ...@@ -367,6 +396,7 @@ static const struct stm32_rng_data stm32mp13_rng_data = {
static const struct stm32_rng_data stm32_rng_data = { static const struct stm32_rng_data stm32_rng_data = {
.has_cond_reset = false, .has_cond_reset = false,
.max_clock_rate = 3000000,
}; };
static const struct of_device_id stm32_rng_match[] = { static const struct of_device_id stm32_rng_match[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment