qcom-rng.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2017-18 Linaro Limited
  3. //
  4. // Based on msm-rng.c and downstream driver
  5. #include <crypto/internal/rng.h>
  6. #include <linux/clk.h>
  7. #include <linux/crypto.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/platform_device.h>
  11. /* Device specific register offsets */
  12. #define PRNG_DATA_OUT 0x0000
  13. #define PRNG_STATUS 0x0004
  14. #define PRNG_LFSR_CFG 0x0100
  15. #define PRNG_CONFIG 0x0104
  16. /* Device specific register masks and config values */
  17. #define PRNG_LFSR_CFG_MASK 0x0000ffff
  18. #define PRNG_LFSR_CFG_CLOCKS 0x0000dddd
  19. #define PRNG_CONFIG_HW_ENABLE BIT(1)
  20. #define PRNG_STATUS_DATA_AVAIL BIT(0)
  21. #define WORD_SZ 4
  22. struct qcom_rng {
  23. struct mutex lock;
  24. void __iomem *base;
  25. struct clk *clk;
  26. };
  27. struct qcom_rng_ctx {
  28. struct qcom_rng *rng;
  29. };
  30. static struct qcom_rng *qcom_rng_dev;
  31. static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
  32. {
  33. unsigned int currsize = 0;
  34. u32 val;
  35. /* read random data from hardware */
  36. do {
  37. val = readl_relaxed(rng->base + PRNG_STATUS);
  38. if (!(val & PRNG_STATUS_DATA_AVAIL))
  39. break;
  40. val = readl_relaxed(rng->base + PRNG_DATA_OUT);
  41. if (!val)
  42. break;
  43. if ((max - currsize) >= WORD_SZ) {
  44. memcpy(data, &val, WORD_SZ);
  45. data += WORD_SZ;
  46. currsize += WORD_SZ;
  47. } else {
  48. /* copy only remaining bytes */
  49. memcpy(data, &val, max - currsize);
  50. break;
  51. }
  52. } while (currsize < max);
  53. return currsize;
  54. }
  55. static int qcom_rng_generate(struct crypto_rng *tfm,
  56. const u8 *src, unsigned int slen,
  57. u8 *dstn, unsigned int dlen)
  58. {
  59. struct qcom_rng_ctx *ctx = crypto_rng_ctx(tfm);
  60. struct qcom_rng *rng = ctx->rng;
  61. int ret;
  62. ret = clk_prepare_enable(rng->clk);
  63. if (ret)
  64. return ret;
  65. mutex_lock(&rng->lock);
  66. ret = qcom_rng_read(rng, dstn, dlen);
  67. mutex_unlock(&rng->lock);
  68. clk_disable_unprepare(rng->clk);
  69. return 0;
  70. }
  71. static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
  72. unsigned int slen)
  73. {
  74. return 0;
  75. }
  76. static int qcom_rng_enable(struct qcom_rng *rng)
  77. {
  78. u32 val;
  79. int ret;
  80. ret = clk_prepare_enable(rng->clk);
  81. if (ret)
  82. return ret;
  83. /* Enable PRNG only if it is not already enabled */
  84. val = readl_relaxed(rng->base + PRNG_CONFIG);
  85. if (val & PRNG_CONFIG_HW_ENABLE)
  86. goto already_enabled;
  87. val = readl_relaxed(rng->base + PRNG_LFSR_CFG);
  88. val &= ~PRNG_LFSR_CFG_MASK;
  89. val |= PRNG_LFSR_CFG_CLOCKS;
  90. writel(val, rng->base + PRNG_LFSR_CFG);
  91. val = readl_relaxed(rng->base + PRNG_CONFIG);
  92. val |= PRNG_CONFIG_HW_ENABLE;
  93. writel(val, rng->base + PRNG_CONFIG);
  94. already_enabled:
  95. clk_disable_unprepare(rng->clk);
  96. return 0;
  97. }
  98. static int qcom_rng_init(struct crypto_tfm *tfm)
  99. {
  100. struct qcom_rng_ctx *ctx = crypto_tfm_ctx(tfm);
  101. ctx->rng = qcom_rng_dev;
  102. return qcom_rng_enable(ctx->rng);
  103. }
  104. static struct rng_alg qcom_rng_alg = {
  105. .generate = qcom_rng_generate,
  106. .seed = qcom_rng_seed,
  107. .seedsize = 0,
  108. .base = {
  109. .cra_name = "stdrng",
  110. .cra_driver_name = "qcom-rng",
  111. .cra_flags = CRYPTO_ALG_TYPE_RNG,
  112. .cra_priority = 300,
  113. .cra_ctxsize = sizeof(struct qcom_rng_ctx),
  114. .cra_module = THIS_MODULE,
  115. .cra_init = qcom_rng_init,
  116. }
  117. };
  118. static int qcom_rng_probe(struct platform_device *pdev)
  119. {
  120. struct resource *res;
  121. struct qcom_rng *rng;
  122. int ret;
  123. rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
  124. if (!rng)
  125. return -ENOMEM;
  126. platform_set_drvdata(pdev, rng);
  127. mutex_init(&rng->lock);
  128. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  129. rng->base = devm_ioremap_resource(&pdev->dev, res);
  130. if (IS_ERR(rng->base))
  131. return PTR_ERR(rng->base);
  132. rng->clk = devm_clk_get(&pdev->dev, "core");
  133. if (IS_ERR(rng->clk))
  134. return PTR_ERR(rng->clk);
  135. qcom_rng_dev = rng;
  136. ret = crypto_register_rng(&qcom_rng_alg);
  137. if (ret) {
  138. dev_err(&pdev->dev, "Register crypto rng failed: %d\n", ret);
  139. qcom_rng_dev = NULL;
  140. }
  141. return ret;
  142. }
  143. static int qcom_rng_remove(struct platform_device *pdev)
  144. {
  145. crypto_unregister_rng(&qcom_rng_alg);
  146. qcom_rng_dev = NULL;
  147. return 0;
  148. }
  149. static const struct of_device_id qcom_rng_of_match[] = {
  150. { .compatible = "qcom,prng" },
  151. {}
  152. };
  153. MODULE_DEVICE_TABLE(of, qcom_rng_of_match);
  154. static struct platform_driver qcom_rng_driver = {
  155. .probe = qcom_rng_probe,
  156. .remove = qcom_rng_remove,
  157. .driver = {
  158. .name = KBUILD_MODNAME,
  159. .of_match_table = of_match_ptr(qcom_rng_of_match),
  160. }
  161. };
  162. module_platform_driver(qcom_rng_driver);
  163. MODULE_ALIAS("platform:" KBUILD_MODNAME);
  164. MODULE_DESCRIPTION("Qualcomm random number generator driver");
  165. MODULE_LICENSE("GPL v2");