xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_rng.c (revision 5bf5ca772c6de2d53344a78cf461447cc322ccea)
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);
541