Implement stm32_rng_suspend()/stm32_rng_resume() low-power APIs
called when the hardware block context will be lost.
There is no need to save the RNG_CR register in
stm32_rng_runtime_suspend() as the context is not lost. Therefore,
only enable/disable the RNG in the runtime sequences.
Signed-off-by: Gatien Chevallier <gatien.chevallier@foss.st.com>
---
drivers/char/hw_random/stm32-rng.c | 100 +++++++++++++++++++++++++++--
1 file changed, 93 insertions(+), 7 deletions(-)
diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c
index 0243b889ac54..3ac6712324c7 100644
--- a/drivers/char/hw_random/stm32-rng.c
+++ b/drivers/char/hw_random/stm32-rng.c
@@ -55,11 +55,25 @@ struct stm32_rng_data {
bool has_cond_reset;
};
+/**
+ * struct stm32_rng_config - RNG configuration data
+ *
+ * @cr: RNG configuration. 0 means default hardware RNG configuration
+ * @nscr: Noise sources control configuration.
+ * @htcr: Health tests configuration.
+ */
+struct stm32_rng_config {
+ u32 cr;
+ u32 nscr;
+ u32 htcr;
+};
+
struct stm32_rng_private {
struct hwrng rng;
void __iomem *base;
struct clk *clk;
struct reset_control *rst;
+ struct stm32_rng_config pm_conf;
const struct stm32_rng_data *data;
bool ced;
bool lock_conf;
@@ -355,11 +369,10 @@ static int stm32_rng_remove(struct platform_device *ofdev)
return 0;
}
-#ifdef CONFIG_PM
static int stm32_rng_runtime_suspend(struct device *dev)
{
- u32 reg;
struct stm32_rng_private *priv = dev_get_drvdata(dev);
+ u32 reg;
reg = readl_relaxed(priv->base + RNG_CR);
reg &= ~RNG_CR_RNGEN;
@@ -369,25 +382,98 @@ static int stm32_rng_runtime_suspend(struct device *dev)
return 0;
}
+static int __maybe_unused stm32_rng_suspend(struct device *dev)
+{
+ struct stm32_rng_private *priv = dev_get_drvdata(dev);
+
+ if (priv->data->has_cond_reset) {
+ priv->pm_conf.nscr = readl_relaxed(priv->base + RNG_NSCR);
+ priv->pm_conf.htcr = readl_relaxed(priv->base + RNG_HTCR);
+ }
+
+ /* Do not save that RNG is enabled as it will be handled at resume */
+ priv->pm_conf.cr = readl_relaxed(priv->base + RNG_CR) & ~RNG_CR_RNGEN;
+
+ writel_relaxed(priv->pm_conf.cr, priv->base + RNG_CR);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
static int stm32_rng_runtime_resume(struct device *dev)
{
- u32 reg;
struct stm32_rng_private *priv = dev_get_drvdata(dev);
+ int err;
+ u32 reg;
+
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ return err;
+
+ /* Clean error indications */
+ writel_relaxed(0, priv->base + RNG_SR);
- clk_prepare_enable(priv->clk);
reg = readl_relaxed(priv->base + RNG_CR);
reg |= RNG_CR_RNGEN;
writel_relaxed(reg, priv->base + RNG_CR);
return 0;
}
-#endif
+
+static int __maybe_unused stm32_rng_resume(struct device *dev)
+{
+ struct stm32_rng_private *priv = dev_get_drvdata(dev);
+ int err;
+ u32 reg;
+
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ return err;
+
+ /* Clean error indications */
+ writel_relaxed(0, priv->base + RNG_SR);
+
+ 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);
+
+ writel_relaxed(priv->pm_conf.nscr, priv->base + RNG_NSCR);
+ writel_relaxed(priv->pm_conf.htcr, priv->base + RNG_HTCR);
+
+ reg = readl_relaxed(priv->base + RNG_CR);
+ reg |= RNG_CR_RNGEN;
+ reg &= ~RNG_CR_CONDRST;
+ writel_relaxed(reg, priv->base + RNG_CR);
+
+ err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, reg,
+ reg & ~RNG_CR_CONDRST, 10, 100000);
+
+ if (err) {
+ clk_disable_unprepare(priv->clk);
+ dev_err((struct device *)priv->rng.priv,
+ "%s: timeout:%x CR: %x!\n", __func__, err, reg);
+ return -EINVAL;
+ }
+ } else {
+ reg = priv->pm_conf.cr;
+ reg |= RNG_CR_RNGEN;
+ writel_relaxed(reg, priv->base + RNG_CR);
+ }
+
+ return 0;
+}
static const struct dev_pm_ops stm32_rng_pm_ops = {
SET_RUNTIME_PM_OPS(stm32_rng_runtime_suspend,
stm32_rng_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(stm32_rng_suspend,
+ stm32_rng_resume)
};
static const struct stm32_rng_data stm32mp13_rng_data = {
--
2.25.1
Hi Gatien,
kernel test robot noticed the following build warnings:
[auto build test WARNING on atorgue-stm32/stm32-next]
[also build test WARNING on robh/for-next herbert-crypto-2.6/master herbert-cryptodev-2.6/master linus/master v6.5 next-20230908]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Gatien-Chevallier/dt-bindings-rng-introduce-new-compatible-for-STM32MP13x/20230909-005611
base: https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
patch link: https://lore.kernel.org/r/20230908165120.730867-10-gatien.chevallier%40foss.st.com
patch subject: [PATCH 09/10] hwrng: stm32 - rework power management sequences
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230909/202309090255.4Ttcm8zy-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230909/202309090255.4Ttcm8zy-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202309090255.4Ttcm8zy-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/char/hw_random/stm32-rng.c:403:12: warning: 'stm32_rng_runtime_resume' defined but not used [-Wunused-function]
403 | static int stm32_rng_runtime_resume(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/char/hw_random/stm32-rng.c:371:12: warning: 'stm32_rng_runtime_suspend' defined but not used [-Wunused-function]
371 | static int stm32_rng_runtime_suspend(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~~~~~~~
vim +/stm32_rng_runtime_resume +403 drivers/char/hw_random/stm32-rng.c
af0d4442dd6813 Lionel Debieve 2019-04-01 370
c6a97c42e399ad Daniel Thompson 2015-10-12 @371 static int stm32_rng_runtime_suspend(struct device *dev)
c6a97c42e399ad Daniel Thompson 2015-10-12 372 {
d6ba06b8b9a947 Daniel Thompson 2015-10-14 373 struct stm32_rng_private *priv = dev_get_drvdata(dev);
f81a08733f43ae Gatien Chevallier 2023-09-08 374 u32 reg;
c6a97c42e399ad Daniel Thompson 2015-10-12 375
d9494cfe524b05 Gatien Chevallier 2023-09-08 376 reg = readl_relaxed(priv->base + RNG_CR);
d9494cfe524b05 Gatien Chevallier 2023-09-08 377 reg &= ~RNG_CR_RNGEN;
d9494cfe524b05 Gatien Chevallier 2023-09-08 378 writel_relaxed(reg, priv->base + RNG_CR);
d9494cfe524b05 Gatien Chevallier 2023-09-08 379 clk_disable_unprepare(priv->clk);
c6a97c42e399ad Daniel Thompson 2015-10-12 380
c6a97c42e399ad Daniel Thompson 2015-10-12 381 return 0;
c6a97c42e399ad Daniel Thompson 2015-10-12 382 }
c6a97c42e399ad Daniel Thompson 2015-10-12 383
f81a08733f43ae Gatien Chevallier 2023-09-08 384 static int __maybe_unused stm32_rng_suspend(struct device *dev)
f81a08733f43ae Gatien Chevallier 2023-09-08 385 {
f81a08733f43ae Gatien Chevallier 2023-09-08 386 struct stm32_rng_private *priv = dev_get_drvdata(dev);
f81a08733f43ae Gatien Chevallier 2023-09-08 387
f81a08733f43ae Gatien Chevallier 2023-09-08 388 if (priv->data->has_cond_reset) {
f81a08733f43ae Gatien Chevallier 2023-09-08 389 priv->pm_conf.nscr = readl_relaxed(priv->base + RNG_NSCR);
f81a08733f43ae Gatien Chevallier 2023-09-08 390 priv->pm_conf.htcr = readl_relaxed(priv->base + RNG_HTCR);
f81a08733f43ae Gatien Chevallier 2023-09-08 391 }
f81a08733f43ae Gatien Chevallier 2023-09-08 392
f81a08733f43ae Gatien Chevallier 2023-09-08 393 /* Do not save that RNG is enabled as it will be handled at resume */
f81a08733f43ae Gatien Chevallier 2023-09-08 394 priv->pm_conf.cr = readl_relaxed(priv->base + RNG_CR) & ~RNG_CR_RNGEN;
f81a08733f43ae Gatien Chevallier 2023-09-08 395
f81a08733f43ae Gatien Chevallier 2023-09-08 396 writel_relaxed(priv->pm_conf.cr, priv->base + RNG_CR);
f81a08733f43ae Gatien Chevallier 2023-09-08 397
f81a08733f43ae Gatien Chevallier 2023-09-08 398 clk_disable_unprepare(priv->clk);
f81a08733f43ae Gatien Chevallier 2023-09-08 399
f81a08733f43ae Gatien Chevallier 2023-09-08 400 return 0;
f81a08733f43ae Gatien Chevallier 2023-09-08 401 }
f81a08733f43ae Gatien Chevallier 2023-09-08 402
c6a97c42e399ad Daniel Thompson 2015-10-12 @403 static int stm32_rng_runtime_resume(struct device *dev)
c6a97c42e399ad Daniel Thompson 2015-10-12 404 {
f81a08733f43ae Gatien Chevallier 2023-09-08 405 struct stm32_rng_private *priv = dev_get_drvdata(dev);
f81a08733f43ae Gatien Chevallier 2023-09-08 406 int err;
d9494cfe524b05 Gatien Chevallier 2023-09-08 407 u32 reg;
f81a08733f43ae Gatien Chevallier 2023-09-08 408
f81a08733f43ae Gatien Chevallier 2023-09-08 409 err = clk_prepare_enable(priv->clk);
f81a08733f43ae Gatien Chevallier 2023-09-08 410 if (err)
f81a08733f43ae Gatien Chevallier 2023-09-08 411 return err;
f81a08733f43ae Gatien Chevallier 2023-09-08 412
f81a08733f43ae Gatien Chevallier 2023-09-08 413 /* Clean error indications */
f81a08733f43ae Gatien Chevallier 2023-09-08 414 writel_relaxed(0, priv->base + RNG_SR);
f81a08733f43ae Gatien Chevallier 2023-09-08 415
f81a08733f43ae Gatien Chevallier 2023-09-08 416 reg = readl_relaxed(priv->base + RNG_CR);
f81a08733f43ae Gatien Chevallier 2023-09-08 417 reg |= RNG_CR_RNGEN;
f81a08733f43ae Gatien Chevallier 2023-09-08 418 writel_relaxed(reg, priv->base + RNG_CR);
f81a08733f43ae Gatien Chevallier 2023-09-08 419
f81a08733f43ae Gatien Chevallier 2023-09-08 420 return 0;
f81a08733f43ae Gatien Chevallier 2023-09-08 421 }
f81a08733f43ae Gatien Chevallier 2023-09-08 422
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.