stm32mp1_rng.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2019, Linaro Limited
  4. */
  5. #define LOG_CATEGORY UCLASS_RNG
  6. #include <common.h>
  7. #include <clk.h>
  8. #include <dm.h>
  9. #include <log.h>
  10. #include <reset.h>
  11. #include <rng.h>
  12. #include <linux/bitops.h>
  13. #include <linux/delay.h>
  14. #include <asm/io.h>
  15. #include <linux/iopoll.h>
  16. #include <linux/kernel.h>
  17. #define RNG_CR 0x00
  18. #define RNG_CR_RNGEN BIT(2)
  19. #define RNG_CR_CED BIT(5)
  20. #define RNG_SR 0x04
  21. #define RNG_SR_SEIS BIT(6)
  22. #define RNG_SR_CEIS BIT(5)
  23. #define RNG_SR_SECS BIT(2)
  24. #define RNG_SR_DRDY BIT(0)
  25. #define RNG_DR 0x08
  26. struct stm32_rng_plat {
  27. fdt_addr_t base;
  28. struct clk clk;
  29. struct reset_ctl rst;
  30. };
  31. static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
  32. {
  33. int retval, i;
  34. u32 sr, count, reg;
  35. size_t increment;
  36. struct stm32_rng_plat *pdata = dev_get_plat(dev);
  37. while (len > 0) {
  38. retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
  39. sr & RNG_SR_DRDY, 10000);
  40. if (retval)
  41. return retval;
  42. if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
  43. /* As per SoC TRM */
  44. clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
  45. for (i = 0; i < 12; i++)
  46. readl(pdata->base + RNG_DR);
  47. if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
  48. log_err("RNG Noise");
  49. return -EIO;
  50. }
  51. /* start again */
  52. continue;
  53. }
  54. /*
  55. * Once the DRDY bit is set, the RNG_DR register can
  56. * be read four consecutive times.
  57. */
  58. count = 4;
  59. while (len && count) {
  60. reg = readl(pdata->base + RNG_DR);
  61. memcpy(data, &reg, min(len, sizeof(u32)));
  62. increment = min(len, sizeof(u32));
  63. data += increment;
  64. len -= increment;
  65. count--;
  66. }
  67. }
  68. return 0;
  69. }
  70. static int stm32_rng_init(struct stm32_rng_plat *pdata)
  71. {
  72. int err;
  73. err = clk_enable(&pdata->clk);
  74. if (err)
  75. return err;
  76. /* Disable CED */
  77. writel(RNG_CR_RNGEN | RNG_CR_CED, pdata->base + RNG_CR);
  78. /* clear error indicators */
  79. writel(0, pdata->base + RNG_SR);
  80. return 0;
  81. }
  82. static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
  83. {
  84. writel(0, pdata->base + RNG_CR);
  85. return clk_disable(&pdata->clk);
  86. }
  87. static int stm32_rng_probe(struct udevice *dev)
  88. {
  89. struct stm32_rng_plat *pdata = dev_get_plat(dev);
  90. reset_assert(&pdata->rst);
  91. udelay(20);
  92. reset_deassert(&pdata->rst);
  93. return stm32_rng_init(pdata);
  94. }
  95. static int stm32_rng_remove(struct udevice *dev)
  96. {
  97. struct stm32_rng_plat *pdata = dev_get_plat(dev);
  98. return stm32_rng_cleanup(pdata);
  99. }
  100. static int stm32_rng_of_to_plat(struct udevice *dev)
  101. {
  102. struct stm32_rng_plat *pdata = dev_get_plat(dev);
  103. int err;
  104. pdata->base = dev_read_addr(dev);
  105. if (!pdata->base)
  106. return -ENOMEM;
  107. err = clk_get_by_index(dev, 0, &pdata->clk);
  108. if (err)
  109. return err;
  110. err = reset_get_by_index(dev, 0, &pdata->rst);
  111. if (err)
  112. return err;
  113. return 0;
  114. }
  115. static const struct dm_rng_ops stm32_rng_ops = {
  116. .read = stm32_rng_read,
  117. };
  118. static const struct udevice_id stm32_rng_match[] = {
  119. {
  120. .compatible = "st,stm32-rng",
  121. },
  122. {},
  123. };
  124. U_BOOT_DRIVER(stm32_rng) = {
  125. .name = "stm32-rng",
  126. .id = UCLASS_RNG,
  127. .of_match = stm32_rng_match,
  128. .ops = &stm32_rng_ops,
  129. .probe = stm32_rng_probe,
  130. .remove = stm32_rng_remove,
  131. .plat_auto = sizeof(struct stm32_rng_plat),
  132. .of_to_plat = stm32_rng_of_to_plat,
  133. };