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.
Unified · Split
| @@ -55,11 +55,25 @@ struct stm32_rng_data { · 54 unmodified lines | |||
| 55 | bool has_cond_reset; | 55 | bool has_cond_reset; |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | /** | ||
| 59 | * struct stm32_rng_config - RNG configuration data | ||
| 60 | * | ||
| 61 | * @cr: RNG configuration. 0 means default hardware RNG configuration | ||
| 62 | * @nscr: Noise sources control configuration. | ||
| 63 | * @htcr: Health tests configuration. | ||
| 64 | */ | ||
| 65 | struct stm32_rng_config { | ||
| 66 | u32 cr; | ||
| 67 | u32 nscr; | ||
| 68 | u32 htcr; | ||
| 69 | }; | ||
| 70 | |||
| 58 | struct stm32_rng_private { | 71 | struct stm32_rng_private { |
| 59 | struct hwrng rng; | 72 | struct hwrng rng; |
| 60 | void __iomem *base; | 73 | void __iomem *base; |
| 61 | struct clk *clk; | 74 | struct clk *clk; |
| 62 | struct reset_control *rst; | 75 | struct reset_control *rst; |
| 76 | struct stm32_rng_config pm_conf; | ||
| 63 | const struct stm32_rng_data *data; | 77 | const struct stm32_rng_data *data; |
| 64 | bool ced; | 78 | bool ced; |
| 65 | bool lock_conf; | 79 | bool lock_conf; |
| @@ -355,11 +369,10 @@ static int stm32_rng_remove(struct platform_device *ofdev) · 289 unmodified lines | |||
| 355 | return 0; | 369 | return 0; |
| 356 | } | 370 | } |
| 357 | 371 | ||
| 358 | #ifdef CONFIG_PM | 372 | static int __maybe_unused stm32_rng_runtime_suspend(struct device *dev) |
| 359 | static int stm32_rng_runtime_suspend(struct device *dev) | ||
| 360 | { | 373 | { |
| 361 | u32 reg; | ||
| 362 | struct stm32_rng_private *priv = dev_get_drvdata(dev); | 374 | struct stm32_rng_private *priv = dev_get_drvdata(dev); |
| 375 | u32 reg; | ||
| 363 | 376 | ||
| 364 | reg = readl_relaxed(priv->base + RNG_CR); | 377 | reg = readl_relaxed(priv->base + RNG_CR); |
| 365 | reg &= ~RNG_CR_RNGEN; | 378 | reg &= ~RNG_CR_RNGEN; |
| @@ -369,25 +382,98 @@ static int stm32_rng_runtime_suspend(struct device *dev) · 3 unmodified lines | |||
| 369 | return 0; | 382 | return 0; |
| 370 | } | 383 | } |
| 371 | 384 | ||
| 372 | static int stm32_rng_runtime_resume(struct device *dev) | 385 | static int __maybe_unused stm32_rng_suspend(struct device *dev) |
| 386 | { | ||
| 387 | struct stm32_rng_private *priv = dev_get_drvdata(dev); | ||
| 388 | |||
| 389 | if (priv->data->has_cond_reset) { | ||
| 390 | priv->pm_conf.nscr = readl_relaxed(priv->base + RNG_NSCR); | ||
| 391 | priv->pm_conf.htcr = readl_relaxed(priv->base + RNG_HTCR); | ||
| 392 | } | ||
| 393 | |||
| 394 | /* Do not save that RNG is enabled as it will be handled at resume */ | ||
| 395 | priv->pm_conf.cr = readl_relaxed(priv->base + RNG_CR) & ~RNG_CR_RNGEN; | ||
| 396 | |||
| 397 | writel_relaxed(priv->pm_conf.cr, priv->base + RNG_CR); | ||
| 398 | |||
| 399 | clk_disable_unprepare(priv->clk); | ||
| 400 | |||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | |||
| 404 | static int __maybe_unused stm32_rng_runtime_resume(struct device *dev) | ||
| 373 | { | 405 | { |
| 374 | u32 reg; | ||
| 375 | struct stm32_rng_private *priv = dev_get_drvdata(dev); | 406 | struct stm32_rng_private *priv = dev_get_drvdata(dev); |
| 407 | int err; | ||
| 408 | u32 reg; | ||
| 409 | |||
| 410 | err = clk_prepare_enable(priv->clk); | ||
| 411 | if (err) | ||
| 412 | return err; | ||
| 413 | |||
| 414 | /* Clean error indications */ | ||
| 415 | writel_relaxed(0, priv->base + RNG_SR); | ||
| 376 | 416 | ||
| 377 | clk_prepare_enable(priv->clk); | ||
| 378 | reg = readl_relaxed(priv->base + RNG_CR); | 417 | reg = readl_relaxed(priv->base + RNG_CR); |
| 379 | reg |= RNG_CR_RNGEN; | 418 | reg |= RNG_CR_RNGEN; |
| 380 | writel_relaxed(reg, priv->base + RNG_CR); | 419 | writel_relaxed(reg, priv->base + RNG_CR); |
| 381 | 420 | ||
| 382 | return 0; | 421 | return 0; |
| 383 | } | 422 | } |
| 384 | #endif | ||
| 385 | 423 | ||
| 386 | static const struct dev_pm_ops stm32_rng_pm_ops = { | 424 | static int __maybe_unused stm32_rng_resume(struct device *dev) |
| 425 | { | ||
| 426 | struct stm32_rng_private *priv = dev_get_drvdata(dev); | ||
| 427 | int err; | ||
| 428 | u32 reg; | ||
| 429 | |||
| 430 | err = clk_prepare_enable(priv->clk); | ||
| 431 | if (err) | ||
| 432 | return err; | ||
| 433 | |||
| 434 | /* Clean error indications */ | ||
| 435 | writel_relaxed(0, priv->base + RNG_SR); | ||
| 436 | |||
| 437 | if (priv->data->has_cond_reset) { | ||
| 438 | /* | ||
| 439 | * Correct configuration in bits [29:4] must be set in the same | ||
| 440 | * access that set RNG_CR_CONDRST bit. Else config setting is | ||
| 441 | * not taken into account. CONFIGLOCK bit must also be unset but | ||
| 442 | * it is not handled at the moment. | ||
| 443 | */ | ||
| 444 | writel_relaxed(priv->pm_conf.cr | RNG_CR_CONDRST, priv->base + RNG_CR); | ||
| 445 | |||
| 446 | writel_relaxed(priv->pm_conf.nscr, priv->base + RNG_NSCR); | ||
| 447 | writel_relaxed(priv->pm_conf.htcr, priv->base + RNG_HTCR); | ||
| 448 | |||
| 449 | reg = readl_relaxed(priv->base + RNG_CR); | ||
| 450 | reg |= RNG_CR_RNGEN; | ||
| 451 | reg &= ~RNG_CR_CONDRST; | ||
| 452 | writel_relaxed(reg, priv->base + RNG_CR); | ||
| 453 | |||
| 454 | err = readl_relaxed_poll_timeout_atomic(priv->base + RNG_CR, reg, | ||
| 455 | reg & ~RNG_CR_CONDRST, 10, 100000); | ||
| 456 | |||
| 457 | if (err) { | ||
| 458 | clk_disable_unprepare(priv->clk); | ||
| 459 | dev_err((struct device *)priv->rng.priv, | ||
| 460 | "%s: timeout:%x CR: %x!\n", __func__, err, reg); | ||
| 461 | return -EINVAL; | ||
| 462 | } | ||
| 463 | } else { | ||
| 464 | reg = priv->pm_conf.cr; | ||
| 465 | reg |= RNG_CR_RNGEN; | ||
| 466 | writel_relaxed(reg, priv->base + RNG_CR); | ||
| 467 | } | ||
| 468 | |||
| 469 | return 0; | ||
| 470 | } | ||
| 471 | |||
| 472 | static const struct dev_pm_ops __maybe_unused stm32_rng_pm_ops = { | ||
| 387 | SET_RUNTIME_PM_OPS(stm32_rng_runtime_suspend, | 473 | SET_RUNTIME_PM_OPS(stm32_rng_runtime_suspend, |
| 388 | stm32_rng_runtime_resume, NULL) | 474 | stm32_rng_runtime_resume, NULL) |
| 389 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | 475 | SET_SYSTEM_SLEEP_PM_OPS(stm32_rng_suspend, |
| 390 | pm_runtime_force_resume) | 476 | stm32_rng_resume) |
| 391 | }; | 477 | }; |
| 392 | 478 | ||
| 393 | static const struct stm32_rng_data stm32mp13_rng_data = { | 479 | static const struct stm32_rng_data stm32mp13_rng_data = { |
| @@ -467,7 +553,7 @@ static int stm32_rng_probe(struct platform_device *ofdev) · 73 unmodified lines | |||
| 467 | static struct platform_driver stm32_rng_driver = { | 553 | static struct platform_driver stm32_rng_driver = { |
| 468 | .driver = { | 554 | .driver = { |
| 469 | .name = "stm32-rng", | 555 | .name = "stm32-rng", |
| 470 | .pm = &stm32_rng_pm_ops, | 556 | .pm = pm_ptr(&stm32_rng_pm_ops), |
| 471 | .of_match_table = stm32_rng_match, | 557 | .of_match_table = stm32_rng_match, |
| 472 | }, | 558 | }, |
| 473 | .probe = stm32_rng_probe, | 559 | .probe = stm32_rng_probe, |