bcm74110-rng.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2024 Broadcom
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/module.h>
  7. #include <linux/mod_devicetable.h>
  8. #include <linux/kernel.h>
  9. #include <linux/io.h>
  10. #include <linux/delay.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/random.h>
  13. #include <linux/hw_random.h>
  14. #define HOST_REV_ID 0x00
  15. #define HOST_FIFO_DEPTH 0x04
  16. #define HOST_FIFO_COUNT 0x08
  17. #define HOST_FIFO_THRESHOLD 0x0c
  18. #define HOST_FIFO_DATA 0x10
  19. #define HOST_FIFO_COUNT_MASK 0xffff
  20. /* Delay range in microseconds */
  21. #define FIFO_DELAY_MIN_US 3
  22. #define FIFO_DELAY_MAX_US 7
  23. #define FIFO_DELAY_MAX_COUNT 10
  24. struct bcm74110_priv {
  25. void __iomem *base;
  26. };
  27. static inline int bcm74110_rng_fifo_count(void __iomem *mem)
  28. {
  29. return readl_relaxed(mem) & HOST_FIFO_COUNT_MASK;
  30. }
  31. static int bcm74110_rng_read(struct hwrng *rng, void *buf, size_t max,
  32. bool wait)
  33. {
  34. struct bcm74110_priv *priv = (struct bcm74110_priv *)rng->priv;
  35. void __iomem *fc_addr = priv->base + HOST_FIFO_COUNT;
  36. void __iomem *fd_addr = priv->base + HOST_FIFO_DATA;
  37. unsigned underrun_count = 0;
  38. u32 max_words = max / sizeof(u32);
  39. u32 num_words;
  40. unsigned i;
  41. /*
  42. * We need to check how many words are available in the RNG FIFO. If
  43. * there aren't any, we need to wait for some to become available.
  44. */
  45. while ((num_words = bcm74110_rng_fifo_count(fc_addr)) == 0) {
  46. if (!wait)
  47. return 0;
  48. /*
  49. * As a precaution, limit how long we wait. If the FIFO doesn't
  50. * refill within the allotted time, return 0 (=no data) to the
  51. * caller.
  52. */
  53. if (likely(underrun_count < FIFO_DELAY_MAX_COUNT))
  54. usleep_range(FIFO_DELAY_MIN_US, FIFO_DELAY_MAX_US);
  55. else
  56. return 0;
  57. underrun_count++;
  58. }
  59. if (num_words > max_words)
  60. num_words = max_words;
  61. /* Bail early if we run out of random numbers unexpectedly */
  62. for (i = 0; i < num_words && bcm74110_rng_fifo_count(fc_addr) > 0; i++)
  63. ((u32 *)buf)[i] = readl_relaxed(fd_addr);
  64. return i * sizeof(u32);
  65. }
  66. static struct hwrng bcm74110_hwrng = {
  67. .read = bcm74110_rng_read,
  68. };
  69. static int bcm74110_rng_probe(struct platform_device *pdev)
  70. {
  71. struct device *dev = &pdev->dev;
  72. struct bcm74110_priv *priv;
  73. int rc;
  74. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  75. if (!priv)
  76. return -ENOMEM;
  77. bcm74110_hwrng.name = pdev->name;
  78. bcm74110_hwrng.priv = (unsigned long)priv;
  79. priv->base = devm_platform_ioremap_resource(pdev, 0);
  80. if (IS_ERR(priv->base))
  81. return PTR_ERR(priv->base);
  82. rc = devm_hwrng_register(dev, &bcm74110_hwrng);
  83. if (rc)
  84. dev_err(dev, "hwrng registration failed (%d)\n", rc);
  85. else
  86. dev_info(dev, "hwrng registered\n");
  87. return rc;
  88. }
  89. static const struct of_device_id bcm74110_rng_match[] = {
  90. { .compatible = "brcm,bcm74110-rng", },
  91. {},
  92. };
  93. MODULE_DEVICE_TABLE(of, bcm74110_rng_match);
  94. static struct platform_driver bcm74110_rng_driver = {
  95. .driver = {
  96. .name = KBUILD_MODNAME,
  97. .of_match_table = bcm74110_rng_match,
  98. },
  99. .probe = bcm74110_rng_probe,
  100. };
  101. module_platform_driver(bcm74110_rng_driver);
  102. MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>");
  103. MODULE_DESCRIPTION("BCM 74110 Random Number Generator (RNG) driver");
  104. MODULE_LICENSE("GPL v2");