trng_ip_76.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
  3. *
  4. * Based on Linux kernel omap-rng.c - RNG driver for TI OMAP CPU family
  5. *
  6. * Author: Deepak Saxena <dsaxena@plexity.net>
  7. *
  8. * Copyright 2005 (c) MontaVista Software, Inc.
  9. *
  10. * Mostly based on original driver:
  11. *
  12. * Copyright (C) 2005 Nokia Corporation
  13. * Author: Juha Yrjölä <juha.yrjola@nokia.com>
  14. *
  15. * SPDX-License-Identifier: BSD-3-Clause
  16. */
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <string.h>
  20. #include <common/debug.h>
  21. #include <drivers/delay_timer.h>
  22. #include <drivers/rambus/trng_ip_76.h>
  23. #include <lib/mmio.h>
  24. #include <lib/spinlock.h>
  25. #include <lib/utils.h>
  26. #define RNG_REG_STATUS_RDY (1 << 0)
  27. #define RNG_REG_INTACK_RDY_MASK (1 << 0)
  28. #define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
  29. #define RNG_CONFIG_NOISE_BLOCKS(val) ((0xff & (val)) << 0)
  30. #define RNG_CONFIG_NOISE_BLK_VAL 0x5
  31. #define RNG_CONFIG_SAMPLE_CYCLES(val) ((0xff & (val)) << 16)
  32. #define RNG_CONFIG_SAMPLE_CYCLES_VAL 0x22
  33. #define RNG_REG_FRO_ENABLE_MASK 0xffffff
  34. #define RNG_REG_FRO_DETUNE_MASK 0x0
  35. #define EIP76_RNG_OUTPUT_SIZE 0x10
  36. #define EIP76_RNG_WAIT_ROUNDS 10
  37. #define RNG_HW_IS_EIP76(ver) ((ver) & (0xff == 0x4C))
  38. #define RNG_HW_VER_MAJOR(ver) (((ver) & (0xf << 24)) >> 24)
  39. #define RNG_HW_VER_MINOR(ver) (((ver) & (0xf << 20)) >> 20)
  40. #define RNG_HW_VER_PATCH(ver) (((ver) & (0xf << 16)) >> 16)
  41. enum {
  42. RNG_OUTPUT_0_REG = 0,
  43. RNG_OUTPUT_1_REG,
  44. RNG_OUTPUT_2_REG,
  45. RNG_OUTPUT_3_REG,
  46. RNG_STATUS_REG,
  47. RNG_INTMASK_REG,
  48. RNG_INTACK_REG,
  49. RNG_CONTROL_REG,
  50. RNG_CONFIG_REG,
  51. RNG_ALARMCNT_REG,
  52. RNG_FROENABLE_REG,
  53. RNG_FRODETUNE_REG,
  54. RNG_ALARMMASK_REG,
  55. RNG_ALARMSTOP_REG,
  56. RNG_REV_REG
  57. };
  58. static uint16_t reg_map_eip76[] = {
  59. [RNG_OUTPUT_0_REG] = 0x0,
  60. [RNG_OUTPUT_1_REG] = 0x4,
  61. [RNG_OUTPUT_2_REG] = 0x8,
  62. [RNG_OUTPUT_3_REG] = 0xc,
  63. [RNG_STATUS_REG] = 0x10,
  64. [RNG_INTACK_REG] = 0x10,
  65. [RNG_CONTROL_REG] = 0x14,
  66. [RNG_CONFIG_REG] = 0x18,
  67. [RNG_ALARMCNT_REG] = 0x1c,
  68. [RNG_FROENABLE_REG] = 0x20,
  69. [RNG_FRODETUNE_REG] = 0x24,
  70. [RNG_ALARMMASK_REG] = 0x28,
  71. [RNG_ALARMSTOP_REG] = 0x2c,
  72. [RNG_REV_REG] = 0x7c,
  73. };
  74. struct eip76_rng_dev {
  75. uintptr_t base;
  76. uint16_t *regs;
  77. };
  78. /* Locals */
  79. static struct eip76_rng_dev eip76_dev;
  80. static spinlock_t rng_lock;
  81. static inline uint32_t eip76_rng_read(struct eip76_rng_dev *dev, uint16_t reg)
  82. {
  83. return mmio_read_32(dev->base + dev->regs[reg]);
  84. }
  85. static inline void eip76_rng_write(struct eip76_rng_dev *dev,
  86. uint16_t reg, uint32_t val)
  87. {
  88. mmio_write_32(dev->base + dev->regs[reg], val);
  89. }
  90. static void eip76_rng_init(struct eip76_rng_dev *dev)
  91. {
  92. uint32_t val;
  93. /* Return if RNG is already running. */
  94. if (eip76_rng_read(dev, RNG_CONTROL_REG) &
  95. RNG_CONTROL_ENABLE_TRNG_MASK) {
  96. return;
  97. }
  98. /* This field sets the number of 512-bit blocks of raw Noise Source
  99. * output data that must be processed by either the Conditioning
  100. * Function or the SP 800-90 DRBG ‘BC_DF’ functionality to yield
  101. * a ‘full entropy’ output value. As according to [SP 800-90B draft]
  102. * the amount of entropy input to this functionality must be twice
  103. * the amount that is output and the 8-bit samples output by the Noise
  104. * Source are supposed to have one bit of entropy each, the settings
  105. * for this field are as follows:
  106. * - SHA-1 Conditioning Function:
  107. * generates 160 bits output, requiring 2560 sample bits,
  108. * equivalent to 5 blocks of raw Noise Source input.
  109. * - SHA-256 Conditioning Function:
  110. * generates 256 bits output, requiring 4096 sample bits, equivalent
  111. * to 8 blocks of raw Noise Source input. Note that two blocks of 256
  112. * bits are needed to start or re-seed the SP 800-90 DRBG
  113. * (in the EIP-76d-*-SHA2 configurations)
  114. * - SP 800-90 DRBG ‘BC_DF’ functionality:
  115. * generates 384 bits output, requiring 6144 sample bits, equivalent
  116. * to 12 blocks of raw Noise Source input.
  117. * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
  118. * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
  119. * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 256 blocks
  120. * of 512 bits to be processed.
  121. */
  122. val = RNG_CONFIG_NOISE_BLOCKS(RNG_CONFIG_NOISE_BLK_VAL);
  123. /* This field sets the number of FRO samples that are XOR-ed together
  124. * into one bit to be shifted into the main shift register.
  125. * This value must be such that there is at least one bit of entropy
  126. * (in total) in each 8 bits that are shifted.
  127. * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
  128. * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
  129. * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 65536 FRO
  130. * samples to be XOR-ed together
  131. */
  132. val |= RNG_CONFIG_SAMPLE_CYCLES(RNG_CONFIG_SAMPLE_CYCLES_VAL);
  133. eip76_rng_write(dev, RNG_CONFIG_REG, val);
  134. /* Enable all available FROs */
  135. eip76_rng_write(dev, RNG_FRODETUNE_REG, RNG_REG_FRO_DETUNE_MASK);
  136. eip76_rng_write(dev, RNG_FROENABLE_REG, RNG_REG_FRO_ENABLE_MASK);
  137. /* Enable TRNG */
  138. eip76_rng_write(dev, RNG_CONTROL_REG, RNG_CONTROL_ENABLE_TRNG_MASK);
  139. }
  140. int32_t eip76_rng_read_rand_buf(void *data, bool wait)
  141. {
  142. uint32_t i, present;
  143. if (!eip76_dev.base) /* not initialized */
  144. return -1;
  145. for (i = 0; i < EIP76_RNG_WAIT_ROUNDS; i++) {
  146. present = eip76_rng_read(&eip76_dev, RNG_STATUS_REG) &
  147. RNG_REG_STATUS_RDY;
  148. if (present || !wait) {
  149. break;
  150. }
  151. udelay(10);
  152. }
  153. if (present != 0U) {
  154. return 0;
  155. }
  156. memcpy(data,
  157. (void *)(eip76_dev.base + eip76_dev.regs[RNG_OUTPUT_0_REG]),
  158. EIP76_RNG_OUTPUT_SIZE);
  159. eip76_rng_write(&eip76_dev, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
  160. return EIP76_RNG_OUTPUT_SIZE;
  161. }
  162. int32_t eip76_rng_probe(uintptr_t base_addr)
  163. {
  164. uint32_t ver;
  165. eip76_dev.base = base_addr;
  166. eip76_dev.regs = reg_map_eip76;
  167. eip76_rng_init(&eip76_dev);
  168. ver = eip76_rng_read(&eip76_dev, RNG_REV_REG);
  169. INFO("%s Random Number Generator HW ver. %01x.%01x.%01x\n",
  170. RNG_HW_IS_EIP76(ver) ? "TRNG-IP-76" : "Unknown",
  171. RNG_HW_VER_MAJOR(ver), RNG_HW_VER_MINOR(ver),
  172. RNG_HW_VER_PATCH(ver));
  173. return 0;
  174. }
  175. int32_t eip76_rng_get_random(uint8_t *data, uint32_t len)
  176. {
  177. static uint8_t rand[EIP76_RNG_OUTPUT_SIZE];
  178. static uint8_t pos;
  179. uint32_t i;
  180. int32_t ret = 0;
  181. if (!data)
  182. return -1;
  183. spin_lock(&rng_lock);
  184. for (i = 0; i < len; i++) {
  185. if (pos >= EIP76_RNG_OUTPUT_SIZE) {
  186. pos = 0;
  187. }
  188. if (pos != 0U) {
  189. ret = eip76_rng_read_rand_buf(rand, true);
  190. }
  191. /* Only advance FIFO index if it is non zero or
  192. * the update from TRNG HW was successful
  193. */
  194. if (pos || ret > 0) {
  195. data[i] = rand[pos++];
  196. ret = 0;
  197. } else {
  198. ret = -1;
  199. break;
  200. }
  201. }
  202. spin_unlock(&rng_lock);
  203. return ret;
  204. }