/* * Extracts from the STM32 RNG specification when RNG supports CONDRST. * * When a noise source (or seed) error occurs, the RNG stops generating * random numbers and sets to “1” both SEIS and SECS bits to indicate * that a seed error occurred. (...) * * 1. Software reset by writing CONDRST at 1 and at 0 (see bitfield * description for details). This step is needed only if SECS is set. * Indeed, when SEIS is set and SECS is cleared it means RNG performed * the reset automatically (auto-reset). * 2. If SECS was set in step 1 (no auto-reset) wait for CONDRST * to be cleared in the RNG_CR register, then confirm that SEIS is * cleared in the RNG_SR register. Otherwise just clear SEIS bit in * the RNG_SR register. * 3. If SECS was set in step 1 (no auto-reset) wait for SECS to be * cleared by RNG. The random number generation is now back to normal.
*/ staticint stm32_rng_conceal_seed_error_cond_reset(struct stm32_rng_private *priv)
{ struct device *dev = priv->dev;
u32 sr = readl_relaxed(priv->base + RNG_SR);
u32 cr = readl_relaxed(priv->base + RNG_CR); int err;
/* * Extracts from the STM32 RNG specification, when CONDRST is not supported * * When a noise source (or seed) error occurs, the RNG stops generating * random numbers and sets to “1” both SEIS and SECS bits to indicate * that a seed error occurred. (...) * * The following sequence shall be used to fully recover from a seed * error after the RNG initialization: * 1. Clear the SEIS bit by writing it to “0”. * 2. Read out 12 words from the RNG_DR register, and discard each of * them in order to clean the pipeline. * 3. Confirm that SEIS is still cleared. Random number generation is * back to normal.
*/ staticint stm32_rng_conceal_seed_error_sw_reset(struct stm32_rng_private *priv)
{ unsignedint i = 0;
u32 sr = readl_relaxed(priv->base + RNG_SR);
retval = pm_runtime_resume_and_get(priv->dev); if (retval) return retval;
if (readl_relaxed(priv->base + RNG_SR) & RNG_SR_SEIS)
stm32_rng_conceal_seed_error(rng);
while (max >= sizeof(u32)) {
sr = readl_relaxed(priv->base + RNG_SR); /* * Manage timeout which is based on timer and take * care of initial delay time when enabling the RNG.
*/ if (!sr && wait) {
err = readl_relaxed_poll_timeout_atomic(priv->base
+ RNG_SR,
sr, sr,
10, 50000); if (err) {
dev_err(priv->dev, "%s: timeout %x!\n", __func__, sr); break;
}
} elseif (!sr) { /* The FIFO is being filled up */ break;
}
if (sr != RNG_SR_DRDY) { if (sr & RNG_SR_SEIS) {
err = stm32_rng_conceal_seed_error(rng);
i++; if (err && i > RNG_NB_RECOVER_TRIES) {
dev_err(priv->dev, "Couldn't recover from seed error\n");
retval = -ENOTRECOVERABLE; goto exit_rpm;
}
continue;
}
if (WARN_ONCE((sr & RNG_SR_CEIS), "RNG clock too slow - %x\n", sr))
writel_relaxed(0, priv->base + RNG_SR);
}
/* Late seed error case: DR being 0 is an error status */
*(u32 *)data = readl_relaxed(priv->base + RNG_DR); if (!*(u32 *)data) {
err = stm32_rng_conceal_seed_error(rng);
i++; if (err && i > RNG_NB_RECOVER_TRIES) {
dev_err(priv->dev, "Couldn't recover from seed error");
retval = -ENOTRECOVERABLE; goto exit_rpm;
}
continue;
}
i = 0;
retval += sizeof(u32);
data += sizeof(u32);
max -= sizeof(u32);
}
/* * 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++;
/* * Keep default RNG configuration if none was specified. * 0 is an invalid value as it disables all entropy sources.
*/ if (priv->data->has_cond_reset && priv->data->cr) {
uint clock_div = stm32_rng_clock_freq_restrain(rng);
if (priv->data->has_cond_reset) { /* * Correct configuration in bits [29:4] must be set in the same * access that set RNG_CR_CONDRST bit. Else config setting is * not taken into account. CONFIGLOCK bit must also be unset but * it is not handled at the moment.
*/
writel_relaxed(priv->pm_conf.cr | RNG_CR_CONDRST, priv->base + RNG_CR);
if (!priv->data->nb_clock || priv->data->nb_clock > 2) return -EINVAL;
ret = devm_clk_bulk_get_all(dev, &priv->clk_bulk); if (ret != priv->data->nb_clock) return dev_err_probe(dev, -EINVAL, "Failed to get clocks: %d\n", ret);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.