mtk-rng.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Driver for Mediatek Hardware Random Number Generator
  3. *
  4. * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #define MTK_RNG_DEV KBUILD_MODNAME
  17. #include <linux/clk.h>
  18. #include <linux/delay.h>
  19. #include <linux/err.h>
  20. #include <linux/hw_random.h>
  21. #include <linux/io.h>
  22. #include <linux/iopoll.h>
  23. #include <linux/kernel.h>
  24. #include <linux/module.h>
  25. #include <linux/of.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/pm_runtime.h>
  28. /* Runtime PM autosuspend timeout: */
  29. #define RNG_AUTOSUSPEND_TIMEOUT 100
  30. #define USEC_POLL 2
  31. #define TIMEOUT_POLL 20
  32. #define RNG_CTRL 0x00
  33. #define RNG_EN BIT(0)
  34. #define RNG_READY BIT(31)
  35. #define RNG_DATA 0x08
  36. #define to_mtk_rng(p) container_of(p, struct mtk_rng, rng)
  37. struct mtk_rng {
  38. void __iomem *base;
  39. struct clk *clk;
  40. struct hwrng rng;
  41. };
  42. static int mtk_rng_init(struct hwrng *rng)
  43. {
  44. struct mtk_rng *priv = to_mtk_rng(rng);
  45. u32 val;
  46. int err;
  47. err = clk_prepare_enable(priv->clk);
  48. if (err)
  49. return err;
  50. val = readl(priv->base + RNG_CTRL);
  51. val |= RNG_EN;
  52. writel(val, priv->base + RNG_CTRL);
  53. return 0;
  54. }
  55. static void mtk_rng_cleanup(struct hwrng *rng)
  56. {
  57. struct mtk_rng *priv = to_mtk_rng(rng);
  58. u32 val;
  59. val = readl(priv->base + RNG_CTRL);
  60. val &= ~RNG_EN;
  61. writel(val, priv->base + RNG_CTRL);
  62. clk_disable_unprepare(priv->clk);
  63. }
  64. static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait)
  65. {
  66. struct mtk_rng *priv = to_mtk_rng(rng);
  67. int ready;
  68. ready = readl(priv->base + RNG_CTRL) & RNG_READY;
  69. if (!ready && wait)
  70. readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
  71. ready & RNG_READY, USEC_POLL,
  72. TIMEOUT_POLL);
  73. return !!ready;
  74. }
  75. static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
  76. {
  77. struct mtk_rng *priv = to_mtk_rng(rng);
  78. int retval = 0;
  79. pm_runtime_get_sync((struct device *)priv->rng.priv);
  80. while (max >= sizeof(u32)) {
  81. if (!mtk_rng_wait_ready(rng, wait))
  82. break;
  83. *(u32 *)buf = readl(priv->base + RNG_DATA);
  84. retval += sizeof(u32);
  85. buf += sizeof(u32);
  86. max -= sizeof(u32);
  87. }
  88. pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
  89. pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
  90. return retval || !wait ? retval : -EIO;
  91. }
  92. static int mtk_rng_probe(struct platform_device *pdev)
  93. {
  94. struct resource *res;
  95. int ret;
  96. struct mtk_rng *priv;
  97. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  98. if (!res) {
  99. dev_err(&pdev->dev, "no iomem resource\n");
  100. return -ENXIO;
  101. }
  102. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  103. if (!priv)
  104. return -ENOMEM;
  105. priv->rng.name = pdev->name;
  106. #ifndef CONFIG_PM
  107. priv->rng.init = mtk_rng_init;
  108. priv->rng.cleanup = mtk_rng_cleanup;
  109. #endif
  110. priv->rng.read = mtk_rng_read;
  111. priv->rng.priv = (unsigned long)&pdev->dev;
  112. priv->rng.quality = 900;
  113. priv->clk = devm_clk_get(&pdev->dev, "rng");
  114. if (IS_ERR(priv->clk)) {
  115. ret = PTR_ERR(priv->clk);
  116. dev_err(&pdev->dev, "no clock for device: %d\n", ret);
  117. return ret;
  118. }
  119. priv->base = devm_ioremap_resource(&pdev->dev, res);
  120. if (IS_ERR(priv->base))
  121. return PTR_ERR(priv->base);
  122. ret = devm_hwrng_register(&pdev->dev, &priv->rng);
  123. if (ret) {
  124. dev_err(&pdev->dev, "failed to register rng device: %d\n",
  125. ret);
  126. return ret;
  127. }
  128. dev_set_drvdata(&pdev->dev, priv);
  129. pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT);
  130. pm_runtime_use_autosuspend(&pdev->dev);
  131. pm_runtime_enable(&pdev->dev);
  132. dev_info(&pdev->dev, "registered RNG driver\n");
  133. return 0;
  134. }
  135. #ifdef CONFIG_PM
  136. static int mtk_rng_runtime_suspend(struct device *dev)
  137. {
  138. struct mtk_rng *priv = dev_get_drvdata(dev);
  139. mtk_rng_cleanup(&priv->rng);
  140. return 0;
  141. }
  142. static int mtk_rng_runtime_resume(struct device *dev)
  143. {
  144. struct mtk_rng *priv = dev_get_drvdata(dev);
  145. return mtk_rng_init(&priv->rng);
  146. }
  147. static UNIVERSAL_DEV_PM_OPS(mtk_rng_pm_ops, mtk_rng_runtime_suspend,
  148. mtk_rng_runtime_resume, NULL);
  149. #define MTK_RNG_PM_OPS (&mtk_rng_pm_ops)
  150. #else /* CONFIG_PM */
  151. #define MTK_RNG_PM_OPS NULL
  152. #endif /* CONFIG_PM */
  153. static const struct of_device_id mtk_rng_match[] = {
  154. { .compatible = "mediatek,mt7623-rng" },
  155. {},
  156. };
  157. MODULE_DEVICE_TABLE(of, mtk_rng_match);
  158. static struct platform_driver mtk_rng_driver = {
  159. .probe = mtk_rng_probe,
  160. .driver = {
  161. .name = MTK_RNG_DEV,
  162. .pm = MTK_RNG_PM_OPS,
  163. .of_match_table = mtk_rng_match,
  164. },
  165. };
  166. module_platform_driver(mtk_rng_driver);
  167. MODULE_DESCRIPTION("Mediatek Random Number Generator Driver");
  168. MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
  169. MODULE_LICENSE("GPL");