Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2015 Broadcom Corporation
3 : : *
4 : : * This program is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU General Public License as
6 : : * published by the Free Software Foundation version 2.
7 : : *
8 : : * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 : : * kind, whether express or implied; without even the implied warranty
10 : : * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 : : * GNU General Public License for more details.
12 : : */
13 : : /*
14 : : * DESCRIPTION: The Broadcom iProc RNG200 Driver
15 : : */
16 : :
17 : : #include <linux/hw_random.h>
18 : : #include <linux/init.h>
19 : : #include <linux/io.h>
20 : : #include <linux/kernel.h>
21 : : #include <linux/module.h>
22 : : #include <linux/of_address.h>
23 : : #include <linux/of_platform.h>
24 : : #include <linux/platform_device.h>
25 : : #include <linux/delay.h>
26 : :
27 : : /* Registers */
28 : : #define RNG_CTRL_OFFSET 0x00
29 : : #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
30 : : #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
31 : : #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
32 : : #define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13
33 : :
34 : : #define RNG_SOFT_RESET_OFFSET 0x04
35 : : #define RNG_SOFT_RESET 0x00000001
36 : :
37 : : #define RBG_SOFT_RESET_OFFSET 0x08
38 : : #define RBG_SOFT_RESET 0x00000001
39 : :
40 : : #define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C
41 : :
42 : : #define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10
43 : :
44 : : #define RNG_INT_STATUS_OFFSET 0x18
45 : : #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
46 : : #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
47 : : #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
48 : : #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
49 : :
50 : : #define RNG_INT_ENABLE_OFFSET 0x1C
51 : :
52 : : #define RNG_FIFO_DATA_OFFSET 0x20
53 : :
54 : : #define RNG_FIFO_COUNT_OFFSET 0x24
55 : : #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
56 : : #define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8
57 : :
58 : : struct iproc_rng200_dev {
59 : : struct hwrng rng;
60 : : void __iomem *base;
61 : : };
62 : :
63 : : #define to_rng_priv(rng) container_of(rng, struct iproc_rng200_dev, rng)
64 : :
65 : 0 : static void iproc_rng200_restart(void __iomem *rng_base)
66 : : {
67 : : uint32_t val;
68 : :
69 : : /* Disable RBG */
70 : : val = ioread32(rng_base + RNG_CTRL_OFFSET);
71 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK;
72 : : val |= RNG_CTRL_RNG_RBGEN_DISABLE;
73 : : iowrite32(val, rng_base + RNG_CTRL_OFFSET);
74 : :
75 : : /* Clear all interrupt status */
76 : 0 : iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
77 : :
78 : : /* Reset RNG and RBG */
79 : 0 : val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
80 : 0 : val |= RBG_SOFT_RESET;
81 : : iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
82 : :
83 : 0 : val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
84 : 0 : val |= RNG_SOFT_RESET;
85 : : iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
86 : :
87 : : val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET);
88 : 0 : val &= ~RNG_SOFT_RESET;
89 : : iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET);
90 : :
91 : : val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET);
92 : 0 : val &= ~RBG_SOFT_RESET;
93 : : iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET);
94 : :
95 : : /* Enable RBG */
96 : : val = ioread32(rng_base + RNG_CTRL_OFFSET);
97 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK;
98 : 0 : val |= RNG_CTRL_RNG_RBGEN_ENABLE;
99 : : iowrite32(val, rng_base + RNG_CTRL_OFFSET);
100 : 0 : }
101 : :
102 : 0 : static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max,
103 : : bool wait)
104 : : {
105 : : struct iproc_rng200_dev *priv = to_rng_priv(rng);
106 : : uint32_t num_remaining = max;
107 : : uint32_t status;
108 : :
109 : : #define MAX_RESETS_PER_READ 1
110 : : uint32_t num_resets = 0;
111 : :
112 : : #define MAX_IDLE_TIME (1 * HZ)
113 : 0 : unsigned long idle_endtime = jiffies + MAX_IDLE_TIME;
114 : :
115 [ # # # # ]: 0 : while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) {
116 : :
117 : : /* Is RNG sane? If not, reset it. */
118 : 0 : status = ioread32(priv->base + RNG_INT_STATUS_OFFSET);
119 [ # # ]: 0 : if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
120 : : RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
121 : :
122 [ # # ]: 0 : if (num_resets >= MAX_RESETS_PER_READ)
123 : 0 : return max - num_remaining;
124 : :
125 : 0 : iproc_rng200_restart(priv->base);
126 : 0 : num_resets++;
127 : : }
128 : :
129 : : /* Are there any random numbers available? */
130 [ # # ]: 0 : if ((ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
131 : : RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
132 : :
133 [ # # ]: 0 : if (num_remaining >= sizeof(uint32_t)) {
134 : : /* Buffer has room to store entire word */
135 : 0 : *(uint32_t *)buf = ioread32(priv->base +
136 : : RNG_FIFO_DATA_OFFSET);
137 : 0 : buf += sizeof(uint32_t);
138 : 0 : num_remaining -= sizeof(uint32_t);
139 : : } else {
140 : : /* Buffer can only store partial word */
141 : 0 : uint32_t rnd_number = ioread32(priv->base +
142 : : RNG_FIFO_DATA_OFFSET);
143 : 0 : memcpy(buf, &rnd_number, num_remaining);
144 : 0 : buf += num_remaining;
145 : : num_remaining = 0;
146 : : }
147 : :
148 : : /* Reset the IDLE timeout */
149 : 0 : idle_endtime = jiffies + MAX_IDLE_TIME;
150 : : } else {
151 [ # # ]: 0 : if (!wait)
152 : : /* Cannot wait, return immediately */
153 : 0 : return max - num_remaining;
154 : :
155 : : /* Can wait, give others chance to run */
156 : 0 : usleep_range(min(num_remaining * 10, 500U), 500);
157 : : }
158 : : }
159 : :
160 : 0 : return max - num_remaining;
161 : : }
162 : :
163 : 0 : static int iproc_rng200_init(struct hwrng *rng)
164 : : {
165 : : struct iproc_rng200_dev *priv = to_rng_priv(rng);
166 : : uint32_t val;
167 : :
168 : : /* Setup RNG. */
169 : 0 : val = ioread32(priv->base + RNG_CTRL_OFFSET);
170 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK;
171 : 0 : val |= RNG_CTRL_RNG_RBGEN_ENABLE;
172 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET);
173 : :
174 : 0 : return 0;
175 : : }
176 : :
177 : 0 : static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max,
178 : : bool wait)
179 : : {
180 : : struct iproc_rng200_dev *priv = to_rng_priv(rng);
181 : 0 : u32 max_words = max / sizeof(u32);
182 : : u32 num_words, count, val;
183 : :
184 : : /* ensure warm up period has elapsed */
185 : : while (1) {
186 : 0 : val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
187 [ # # ]: 0 : if (val > 16)
188 : : break;
189 : 0 : cpu_relax();
190 : 0 : }
191 : :
192 : : /* ensure fifo is not empty */
193 : : while (1) {
194 : 0 : num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
195 : : RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
196 [ # # ]: 0 : if (num_words)
197 : : break;
198 [ # # ]: 0 : if (!wait)
199 : : return 0;
200 : 0 : cpu_relax();
201 : 0 : }
202 : :
203 [ # # ]: 0 : if (num_words > max_words)
204 : : num_words = max_words;
205 : :
206 [ # # ]: 0 : for (count = 0; count < num_words; count++) {
207 : 0 : ((u32 *)buf)[count] = ioread32(priv->base +
208 : : RNG_FIFO_DATA_OFFSET);
209 : : }
210 : :
211 : 0 : return num_words * sizeof(u32);
212 : : }
213 : :
214 : 0 : static int bcm2711_rng200_init(struct hwrng *rng)
215 : : {
216 : : struct iproc_rng200_dev *priv = to_rng_priv(rng);
217 : : uint32_t val;
218 : :
219 [ # # ]: 0 : if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
220 : : return 0;
221 : :
222 : : /* initial numbers generated are "less random" so will be discarded */
223 : : val = 0x40000;
224 : 0 : iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
225 : : /* min fifo count to generate full interrupt */
226 : : val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
227 : 0 : iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
228 : : /* enable the rng - 1Mhz sample rate */
229 : : val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
230 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET);
231 : :
232 : 0 : return 0;
233 : : }
234 : :
235 : 0 : static void iproc_rng200_cleanup(struct hwrng *rng)
236 : : {
237 : : struct iproc_rng200_dev *priv = to_rng_priv(rng);
238 : : uint32_t val;
239 : :
240 : : /* Disable RNG hardware */
241 : 0 : val = ioread32(priv->base + RNG_CTRL_OFFSET);
242 : 0 : val &= ~RNG_CTRL_RNG_RBGEN_MASK;
243 : : val |= RNG_CTRL_RNG_RBGEN_DISABLE;
244 : 0 : iowrite32(val, priv->base + RNG_CTRL_OFFSET);
245 : 0 : }
246 : :
247 : 0 : static int iproc_rng200_probe(struct platform_device *pdev)
248 : : {
249 : : struct iproc_rng200_dev *priv;
250 : : struct resource *res;
251 : 0 : struct device *dev = &pdev->dev;
252 : : int ret;
253 : :
254 : : priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
255 [ # # ]: 0 : if (!priv)
256 : : return -ENOMEM;
257 : :
258 : : /* Map peripheral */
259 : 0 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
260 [ # # ]: 0 : if (!res) {
261 : 0 : dev_err(dev, "failed to get rng resources\n");
262 : 0 : return -EINVAL;
263 : : }
264 : :
265 : 0 : priv->base = devm_ioremap_resource(dev, res);
266 [ # # ]: 0 : if (IS_ERR(priv->base)) {
267 : 0 : dev_err(dev, "failed to remap rng regs\n");
268 : 0 : return PTR_ERR(priv->base);
269 : : }
270 : :
271 : 0 : priv->rng.name = pdev->name;
272 : 0 : priv->rng.cleanup = iproc_rng200_cleanup;
273 : :
274 [ # # ]: 0 : if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) {
275 : 0 : priv->rng.init = bcm2711_rng200_init;
276 : 0 : priv->rng.read = bcm2711_rng200_read;
277 : : } else {
278 : 0 : priv->rng.init = iproc_rng200_init;
279 : 0 : priv->rng.read = iproc_rng200_read;
280 : : }
281 : :
282 : : /* Register driver */
283 : 0 : ret = devm_hwrng_register(dev, &priv->rng);
284 [ # # ]: 0 : if (ret) {
285 : 0 : dev_err(dev, "hwrng registration failed\n");
286 : 0 : return ret;
287 : : }
288 : :
289 : 0 : dev_info(dev, "hwrng registered\n");
290 : :
291 : 0 : return 0;
292 : : }
293 : :
294 : : static const struct of_device_id iproc_rng200_of_match[] = {
295 : : { .compatible = "brcm,bcm2711-rng200", },
296 : : { .compatible = "brcm,bcm7211-rng200", },
297 : : { .compatible = "brcm,bcm7278-rng200", },
298 : : { .compatible = "brcm,iproc-rng200", },
299 : : {},
300 : : };
301 : : MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
302 : :
303 : : static struct platform_driver iproc_rng200_driver = {
304 : : .driver = {
305 : : .name = "iproc-rng200",
306 : : .of_match_table = iproc_rng200_of_match,
307 : : },
308 : : .probe = iproc_rng200_probe,
309 : : };
310 : 404 : module_platform_driver(iproc_rng200_driver);
311 : :
312 : : MODULE_AUTHOR("Broadcom");
313 : : MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver");
314 : : MODULE_LICENSE("GPL v2");
|