]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_rng.c
dts: Update our device tree sources file fomr Linux 4.13
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2835_rng.c
1 /*
2  * Copyright (c) 2015, 2016, Stephen J. Kiernan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/random.h>
37 #include <sys/sbuf.h>
38 #include <sys/sysctl.h>
39 #include <sys/selinfo.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/rman.h>
43
44 #include <machine/bus.h>
45 #include <machine/resource.h>
46
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <dev/random/randomdev.h>
52 #include <dev/random/random_harvestq.h>
53
54 #if !defined(BCM2835_RNG_USE_CALLOUT)
55 #define BCM2835_RNG_USE_INTERRUPT
56 #endif
57
58 static device_attach_t bcm2835_rng_attach;
59 static device_detach_t bcm2835_rng_detach;
60 static device_probe_t bcm2835_rng_probe;
61
62 #define RNG_CTRL                0x00            /* RNG Control Register */
63 #define RNG_COMBLK1_OSC         0x003f0000      /*  Combiner Blk 1 Oscillator */
64 #define RNG_COMBLK1_OSC_SHIFT   16
65 #define RNG_COMBLK2_OSC         0x0fc00000      /*  Combiner Blk 2 Oscillator */
66 #define RNG_COMBLK2_OSC_SHIFT   22
67 #define RNG_JCLK_BYP_DIV_CNT    0x0000ff00      /*  Jitter clk bypass divider
68                                                     count */
69 #define RNG_JCLK_BYP_DIV_CNT_SHIFT 8
70 #define RNG_JCLK_BYP_SRC        0x00000020      /*  Jitter clk bypass source */
71 #define RNG_JCLK_BYP_SEL        0x00000010      /*  Jitter clk bypass select */
72 #define RNG_RBG2X               0x00000002      /*  RBG 2X SPEED */
73 #define RNG_RBGEN_BIT           0x00000001      /*  Enable RNG bit */
74
75 #define RNG_STATUS              0x04            /* RNG status register */
76 #define RND_VAL_SHIFT           24              /*  Shift for valid words */
77 #define RND_VAL_MASK            0x000000ff      /*  Number valid words mask */
78 #define RND_VAL_WARM_CNT        0x40000         /*  RNG Warm Up count */
79 #define RND_WARM_CNT            0xfffff         /*  RNG Warm Up Count mask */
80
81 #define RNG_DATA                0x08            /* RNG Data Register */
82 #define RNG_FF_THRES            0x0c
83 #define RNG_FF_THRES_MASK       0x0000001f
84
85 #define RNG_INT_MASK            0x10
86 #define RNG_INT_OFF_BIT         0x00000001
87
88 #define RNG_FF_DEFAULT          0x10            /* FIFO threshold default */
89
90 #define RNG_FIFO_WORDS          (RNG_FF_DEFAULT / sizeof(uint32_t))
91
92 #define RNG_NUM_OSCILLATORS     6
93 #define RNG_STALL_COUNT_DEFAULT 10
94
95 struct bcm2835_rng_softc {
96         device_t                sc_dev;
97         struct resource *       sc_mem_res;
98         struct resource *       sc_irq_res;
99         void *                  sc_intr_hdl;
100 #if defined(BCM2835_RNG_USE_CALLOUT) || defined(BCM2835_RNG_USE_INTERRUPT)
101         uint32_t                sc_buf[RNG_FIFO_WORDS];
102 #endif
103 #if defined(BCM2835_RNG_USE_CALLOUT)
104         struct callout          sc_rngto;
105         int                     sc_rnghz;
106 #endif
107         int                     sc_stall_count;
108         int                     sc_rbg2x;
109         long                    sc_underrun;
110 };
111
112 static struct ofw_compat_data compat_data[] = {
113         {"broadcom,bcm2835-rng",        1},
114         {"brcm,bcm2835-rng",            1},
115         {NULL,                          0}
116 };
117
118 static __inline void
119 bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
120 {
121
122         atomic_add_long(&sc->sc_underrun, 1);
123 }
124
125 static __inline uint32_t
126 bcm2835_rng_read4(struct bcm2835_rng_softc *sc, bus_size_t off)
127 {
128
129         return bus_read_4(sc->sc_mem_res, off);
130 }
131
132 static __inline void
133 bcm2835_rng_read_multi4(struct bcm2835_rng_softc *sc, bus_size_t off,
134     uint32_t *datap, bus_size_t count)
135 {
136
137         bus_read_multi_4(sc->sc_mem_res, off, datap, count);
138 }
139
140 static __inline void
141 bcm2835_rng_write4(struct bcm2835_rng_softc *sc, bus_size_t off, uint32_t val)
142 {
143
144         bus_write_4(sc->sc_mem_res, off, val);
145 }
146
147 static void
148 bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
149 {
150         uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
151         int i;
152
153         /* Display RNG control register contents */
154         val = bcm2835_rng_read4(sc, RNG_CTRL);
155         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
156
157         comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
158         sbuf_printf(sbp, "  RNG_COMBLK2_OSC (%02x)\n", comblk2_osc);
159         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
160                 if ((comblk2_osc & (1 << i)) == 0)
161                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
162
163         comblk1_osc = (val & RNG_COMBLK1_OSC) >> RNG_COMBLK1_OSC_SHIFT;
164         sbuf_printf(sbp, "  RNG_COMBLK1_OSC (%02x)\n", comblk1_osc);
165         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
166                 if ((comblk1_osc & (1 << i)) == 0)
167                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
168
169         jclk_byp_div = (val & RNG_JCLK_BYP_DIV_CNT) >>
170             RNG_JCLK_BYP_DIV_CNT_SHIFT;
171         sbuf_printf(sbp,
172             "  RNG_JCLK_BYP_DIV_CNT (%02x)\n    APB clock frequency / %d\n",
173             jclk_byp_div, 2 * (jclk_byp_div + 1));
174
175         sbuf_printf(sbp, "  RNG_JCLK_BYP_SRC:\n    %s\n",
176             (val & RNG_JCLK_BYP_SRC) ? "Use divided down APB clock" :
177             "Use RNG clock (APB clock)");
178
179         sbuf_printf(sbp, "  RNG_JCLK_BYP_SEL:\n    %s\n",
180             (val & RNG_JCLK_BYP_SEL) ? "Bypass internal jitter clock" :
181             "Use internal jitter clock");
182
183         if ((val & RNG_RBG2X) != 0)
184                 sbuf_cat(sbp, "  RNG_RBG2X: RNG 2X SPEED enabled\n");
185
186         if ((val & RNG_RBGEN_BIT) != 0)
187                 sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
188
189         /* Display RNG status register contents */
190         val = bcm2835_rng_read4(sc, RNG_STATUS);
191         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
192         sbuf_printf(sbp, "  RND_VAL: %02x\n",
193             (val >> RND_VAL_SHIFT) & RND_VAL_MASK);
194         sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & RND_WARM_CNT);
195
196         /* Display FIFO threshold register contents */
197         val = bcm2835_rng_read4(sc, RNG_FF_THRES);
198         sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
199
200         /* Display interrupt mask register contents */
201         val = bcm2835_rng_read4(sc, RNG_INT_MASK);
202         sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
203              ((val & RNG_INT_OFF_BIT) != 0) ? "disabled" : "enabled");
204 }
205
206 static void
207 bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
208 {
209         uint32_t mask;
210
211         /* Set the interrupt off bit in the interrupt mask register */
212         mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
213         mask |= RNG_INT_OFF_BIT;
214         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
215 }
216
217 #if defined(BCM2835_RNG_USE_INTERRUPT)
218 static void
219 bcm2835_rng_enable_intr(struct bcm2835_rng_softc *sc)
220 {
221         uint32_t mask;
222
223         /* Clear the interrupt off bit in the interrupt mask register */
224         mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
225         mask &= ~RNG_INT_OFF_BIT;
226         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
227 }
228 #endif
229
230 static void
231 bcm2835_rng_start(struct bcm2835_rng_softc *sc)
232 {
233         uint32_t ctrl;
234
235         /* Disable the interrupt */
236         bcm2835_rng_disable_intr(sc);
237
238         /* Set the warmup count */
239         bcm2835_rng_write4(sc, RNG_STATUS, RND_VAL_WARM_CNT);
240
241         /* Enable the RNG */
242         ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
243         ctrl |= RNG_RBGEN_BIT;
244         if (sc->sc_rbg2x)
245                 ctrl |= RNG_RBG2X;
246         bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
247
248 #if defined(BCM2835_RNG_USE_INTERRUPT)
249         /* Enable the interrupt */
250         bcm2835_rng_enable_intr(sc);
251 #endif
252 }
253
254 static void
255 bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
256 {
257         uint32_t ctrl;
258
259         /* Disable the RNG */
260         ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
261         ctrl &= ~RNG_RBGEN_BIT;
262         bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
263 }
264
265 static void
266 bcm2835_rng_harvest(struct bcm2835_rng_softc *sc)
267 {
268         uint32_t *dest;
269         uint32_t status;
270         u_int cnt, nread, num_avail, num_words;
271         int seen_underrun, num_stalls;
272
273         dest = sc->sc_buf;
274         nread = num_words = 0;
275         seen_underrun = num_stalls = 0;
276         for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
277             cnt -= num_words) {
278                 /* Read status register to find out how many words available */
279                 status = bcm2835_rng_read4(sc, RNG_STATUS);
280                 num_avail = (status >> RND_VAL_SHIFT) & RND_VAL_MASK;
281
282                 /* If we have none... */
283                 if (num_avail == 0) {
284                         bcm2835_rng_stat_inc_underrun(sc);
285                         if (++seen_underrun >= sc->sc_stall_count) {
286                                 if (num_stalls++ > 0) {
287                                         device_printf(sc->sc_dev,
288                                             "RNG stalled, disabling device\n");
289                                         bcm2835_rng_stop(sc);
290                                         break;
291                                 } else {
292                                         device_printf(sc->sc_dev,
293                                             "Too many underruns, resetting\n");
294                                         bcm2835_rng_stop(sc);
295                                         bcm2835_rng_start(sc);
296                                         seen_underrun = 0;
297                                 }
298                         }
299                         /* Try again */
300                         continue;
301                 }
302
303                 CTR2(KTR_DEV, "%s: %d words available in RNG FIFO",
304                     device_get_nameunit(sc->sc_dev), num_avail);
305
306                 /* Pull MIN(num_avail, cnt) words from the FIFO */
307                 num_words = (num_avail > cnt) ? cnt : num_avail;
308                 bcm2835_rng_read_multi4(sc, RNG_DATA, dest,
309                     num_words);
310                 dest += num_words;
311                 nread += num_words;
312         }
313
314         cnt = nread * sizeof(uint32_t);
315         if (cnt > 0)
316                 random_harvest_queue(sc->sc_buf, cnt, cnt * NBBY / 2,
317                     RANDOM_PURE_BROADCOM);
318
319 #if defined(BCM2835_RNG_USE_CALLOUT)
320         callout_reset(&sc->sc_rngto, sc->sc_rnghz, bcm2835_rng_harvest, sc);
321 #endif
322 }
323
324 static int
325 sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
326 {
327         struct bcm2835_rng_softc *sc = arg1;
328         int error, rbg2x;
329
330         rbg2x = sc->sc_rbg2x;
331         error = sysctl_handle_int(oidp, &rbg2x, 0, req);
332         if (error)
333                 return (error);
334         if (req->newptr == NULL)
335                 return (error);
336         if (rbg2x == sc->sc_rbg2x)
337                 return (0);
338
339         /* Reset the RNG */
340         bcm2835_rng_stop(sc);
341         sc->sc_rbg2x = rbg2x;
342         bcm2835_rng_start(sc);
343
344         return (0);
345 }
346
347 #ifdef BCM2835_RNG_DEBUG_REGISTERS
348 static int
349 sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
350 {
351         struct sbuf sb;
352         struct bcm2835_rng_softc *sc = arg1;
353         int error;
354
355         error = sysctl_wire_old_buffer(req, 0);
356         if (error != 0)
357                 return (error);
358         sbuf_new_for_sysctl(&sb, NULL, 128, req);
359         bcm2835_rng_dump_registers(sc, &sb);
360         error = sbuf_finish(&sb);
361         sbuf_delete(&sb);
362         return (error);
363 }
364 #endif
365
366 static int
367 bcm2835_rng_probe(device_t dev)
368 {
369
370         if (!ofw_bus_status_okay(dev))
371                 return (ENXIO);
372
373         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
374                 return (ENXIO);
375
376         device_set_desc(dev, "Broadcom BCM2835 RNG");
377
378         return (BUS_PROBE_DEFAULT);
379 }
380
381 static int
382 bcm2835_rng_attach(device_t dev)
383 {
384         struct bcm2835_rng_softc *sc;
385         struct sysctl_ctx_list *sysctl_ctx;
386         struct sysctl_oid *sysctl_tree;
387         int error, rid;
388
389         error = 0;
390         sc = device_get_softc(dev);
391         sc->sc_dev = dev;
392         sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
393 #ifdef BCM2835_RNG_USE_CALLOUT
394         /* Initialize callout */
395         callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
396 #endif
397         TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
398         TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
399
400         /* Allocate memory resources */
401         rid = 0;
402         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
403             RF_ACTIVE);
404         if (sc->sc_mem_res == NULL) {
405                 bcm2835_rng_detach(dev);
406                 return (ENXIO);
407         }
408
409 #if defined(BCM2835_RNG_USE_INTERRUPT)
410         /* Allocate interrupt resource */
411         rid = 0;
412         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
413             RF_SHAREABLE | RF_ACTIVE);
414         if (sc->sc_irq_res == NULL) {
415                 bcm2835_rng_detach(dev);
416                 return (ENXIO);
417         }
418
419         /* Set up the interrupt handler */
420         error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
421             NULL, (driver_intr_t *)bcm2835_rng_harvest, sc, &sc->sc_intr_hdl);
422         if (error) {
423                 device_printf(dev, "Failed to set up IRQ\n");
424                 sc->sc_intr_hdl = NULL;
425                 bcm2835_rng_detach(dev);
426                 return (error);
427         }
428 #endif
429
430         /* Start the RNG */
431         bcm2835_rng_start(sc);
432
433         /* Dump the registers if booting verbose */
434         if (bootverbose) {
435                 struct sbuf sb;
436
437                 (void) sbuf_new(&sb, NULL, 256,
438                     SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
439                 bcm2835_rng_dump_registers(sc, &sb);
440                 sbuf_trim(&sb);
441                 error = sbuf_finish(&sb);
442                 if (error == 0)
443                         device_printf(dev, "%s", sbuf_data(&sb));
444                 sbuf_delete(&sb);
445         }
446
447         sysctl_ctx = device_get_sysctl_ctx(dev);
448         sysctl_tree = device_get_sysctl_tree(dev);
449         SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
450             "underrun", CTLFLAG_RD, &sc->sc_underrun,
451             "Number of FIFO underruns");
452         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
453             "2xspeed", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
454             sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
455         SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
456             "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
457             RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
458 #ifdef BCM2835_RNG_DEBUG_REGISTERS
459         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
460             "dumpregs", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
461             sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
462 #endif
463
464 #if defined(BCM2835_RNG_USE_CALLOUT)
465         /* Reset callout */
466         if (hz >= 100)
467                 sc->sc_rnghz = hz / 100;
468         else
469                 sc->sc_rnghz = 1;
470         callout_reset(&sc->sc_rngto, sc->sc_rnghz, bcm2835_rng_harvest, sc);
471 #endif
472
473         return (0);
474 }
475
476 static int
477 bcm2835_rng_detach(device_t dev)
478 {
479         struct bcm2835_rng_softc *sc;
480 #if defined(BCM2835_RNG_USE_INTERRUPT)
481         int error;
482 #endif
483
484         sc = device_get_softc(dev);
485
486         /* Stop the RNG */
487         bcm2835_rng_stop(sc);
488
489         /* Drain the callout it */
490 #if defined(BCM2835_RNG_USE_CALLOUT)
491         callout_drain(&sc->sc_rngto);
492 #endif
493
494 #if defined(BCM2835_RNG_USE_INTERRUPT)
495         /* Tear down the interrupt */
496         if (sc->sc_irq_res && sc->sc_intr_hdl) {
497                 error = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
498                 if (error != 0) {
499                         device_printf(dev, "could not tear down IRQ\n");
500                         return (error);
501                 }
502                 sc->sc_intr_hdl = NULL;
503         }
504
505         /* Release interrupt resource */
506         if (sc->sc_irq_res) {
507                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
508                 sc->sc_irq_res = NULL;
509         }
510 #endif
511
512         /* Release memory resource */
513         if (sc->sc_mem_res != NULL)
514                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
515
516         return (0);
517 }
518
519 static device_method_t bcm2835_rng_methods[] = {
520         /* Device interface */
521         DEVMETHOD(device_probe,         bcm2835_rng_probe),
522         DEVMETHOD(device_attach,        bcm2835_rng_attach),
523         DEVMETHOD(device_detach,        bcm2835_rng_detach),
524
525         DEVMETHOD_END
526 };
527
528 static driver_t bcm2835_rng_driver = {
529         "bcmrng",
530         bcm2835_rng_methods,
531         sizeof(struct bcm2835_rng_softc)
532 };
533 static devclass_t bcm2835_rng_devclass;
534
535 DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver,
536     bcm2835_rng_devclass, 0, 0);
537 DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, bcm2835_rng_devclass, 0,
538     0);
539 MODULE_VERSION(bcm2835_rng, 1);
540 MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);