xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_rng.c (revision 63d1fd5970ec814904aa0f4580b10a0d302d08b2)
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 __inline void
113 bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
114 {
115 
116 	atomic_add_long(&sc->sc_underrun, 1);
117 }
118 
119 static __inline uint32_t
120 bcm2835_rng_read4(struct bcm2835_rng_softc *sc, bus_size_t off)
121 {
122 
123 	return bus_read_4(sc->sc_mem_res, off);
124 }
125 
126 static __inline void
127 bcm2835_rng_read_multi4(struct bcm2835_rng_softc *sc, bus_size_t off,
128     uint32_t *datap, bus_size_t count)
129 {
130 
131 	bus_read_multi_4(sc->sc_mem_res, off, datap, count);
132 }
133 
134 static __inline void
135 bcm2835_rng_write4(struct bcm2835_rng_softc *sc, bus_size_t off, uint32_t val)
136 {
137 
138 	bus_write_4(sc->sc_mem_res, off, val);
139 }
140 
141 static void
142 bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
143 {
144 	uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
145 	int i;
146 
147 	/* Display RNG control register contents */
148 	val = bcm2835_rng_read4(sc, RNG_CTRL);
149 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
150 
151 	comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
152 	sbuf_printf(sbp, "  RNG_COMBLK2_OSC (%02x)\n", comblk2_osc);
153 	for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
154 		if ((comblk2_osc & (1 << i)) == 0)
155 			sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
156 
157 	comblk1_osc = (val & RNG_COMBLK1_OSC) >> RNG_COMBLK1_OSC_SHIFT;
158 	sbuf_printf(sbp, "  RNG_COMBLK1_OSC (%02x)\n", comblk1_osc);
159 	for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
160 		if ((comblk1_osc & (1 << i)) == 0)
161 			sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
162 
163 	jclk_byp_div = (val & RNG_JCLK_BYP_DIV_CNT) >>
164 	    RNG_JCLK_BYP_DIV_CNT_SHIFT;
165 	sbuf_printf(sbp,
166 	    "  RNG_JCLK_BYP_DIV_CNT (%02x)\n    APB clock frequency / %d\n",
167 	    jclk_byp_div, 2 * (jclk_byp_div + 1));
168 
169 	sbuf_printf(sbp, "  RNG_JCLK_BYP_SRC:\n    %s\n",
170 	    (val & RNG_JCLK_BYP_SRC) ? "Use divided down APB clock" :
171 	    "Use RNG clock (APB clock)");
172 
173 	sbuf_printf(sbp, "  RNG_JCLK_BYP_SEL:\n    %s\n",
174 	    (val & RNG_JCLK_BYP_SEL) ? "Bypass internal jitter clock" :
175 	    "Use internal jitter clock");
176 
177 	if ((val & RNG_RBG2X) != 0)
178 		sbuf_cat(sbp, "  RNG_RBG2X: RNG 2X SPEED enabled\n");
179 
180 	if ((val & RNG_RBGEN_BIT) != 0)
181 		sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
182 
183 	/* Display RNG status register contents */
184 	val = bcm2835_rng_read4(sc, RNG_STATUS);
185 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
186 	sbuf_printf(sbp, "  RND_VAL: %02x\n",
187 	    (val >> RND_VAL_SHIFT) & RND_VAL_MASK);
188 	sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & RND_WARM_CNT);
189 
190 	/* Display FIFO threshold register contents */
191 	val = bcm2835_rng_read4(sc, RNG_FF_THRES);
192 	sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
193 
194 	/* Display interrupt mask register contents */
195 	val = bcm2835_rng_read4(sc, RNG_INT_MASK);
196 	sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
197 	     ((val & RNG_INT_OFF_BIT) != 0) ? "disabled" : "enabled");
198 }
199 
200 static void
201 bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
202 {
203 	uint32_t mask;
204 
205 	/* Set the interrupt off bit in the interrupt mask register */
206 	mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
207 	mask |= RNG_INT_OFF_BIT;
208         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
209 }
210 
211 #if defined(BCM2835_RNG_USE_INTERRUPT)
212 static void
213 bcm2835_rng_enable_intr(struct bcm2835_rng_softc *sc)
214 {
215 	uint32_t mask;
216 
217 	/* Clear the interrupt off bit in the interrupt mask register */
218 	mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
219 	mask &= ~RNG_INT_OFF_BIT;
220         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
221 }
222 #endif
223 
224 static void
225 bcm2835_rng_start(struct bcm2835_rng_softc *sc)
226 {
227 	uint32_t ctrl;
228 
229 	/* Disable the interrupt */
230 	bcm2835_rng_disable_intr(sc);
231 
232 	/* Set the warmup count */
233 	bcm2835_rng_write4(sc, RNG_STATUS, RND_VAL_WARM_CNT);
234 
235 	/* Enable the RNG */
236 	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
237 	ctrl |= RNG_RBGEN_BIT;
238 	if (sc->sc_rbg2x)
239 		ctrl |= RNG_RBG2X;
240 	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
241 
242 #if defined(BCM2835_RNG_USE_INTERRUPT)
243 	/* Enable the interrupt */
244 	bcm2835_rng_enable_intr(sc);
245 #endif
246 }
247 
248 static void
249 bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
250 {
251 	uint32_t ctrl;
252 
253 	/* Disable the RNG */
254 	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
255 	ctrl &= ~RNG_RBGEN_BIT;
256 	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
257 }
258 
259 static void
260 bcm2835_rng_harvest(struct bcm2835_rng_softc *sc)
261 {
262 	uint32_t *dest;
263 	uint32_t status;
264 	u_int cnt, nread, num_avail, num_words;
265 	int seen_underrun, num_stalls;
266 
267 	dest = sc->sc_buf;
268 	nread = num_words = 0;
269 	seen_underrun = num_stalls = 0;
270 	for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
271 	    cnt -= num_words) {
272 		/* Read status register to find out how many words available */
273 		status = bcm2835_rng_read4(sc, RNG_STATUS);
274 		num_avail = (status >> RND_VAL_SHIFT) & RND_VAL_MASK;
275 
276 		/* If we have none... */
277 		if (num_avail == 0) {
278 			bcm2835_rng_stat_inc_underrun(sc);
279 			if (++seen_underrun >= sc->sc_stall_count) {
280 				if (num_stalls++ > 0) {
281 					device_printf(sc->sc_dev,
282 					    "RNG stalled, disabling device\n");
283 					bcm2835_rng_stop(sc);
284 					break;
285 				} else {
286 					device_printf(sc->sc_dev,
287 					    "Too many underruns, resetting\n");
288 					bcm2835_rng_stop(sc);
289 					bcm2835_rng_start(sc);
290 					seen_underrun = 0;
291 				}
292 			}
293 			/* Try again */
294 			continue;
295 		}
296 
297 		CTR2(KTR_DEV, "%s: %d words available in RNG FIFO",
298 		    device_get_nameunit(sc->sc_dev), num_avail);
299 
300 		/* Pull MIN(num_avail, cnt) words from the FIFO */
301 		num_words = (num_avail > cnt) ? cnt : num_avail;
302 		bcm2835_rng_read_multi4(sc, RNG_DATA, dest,
303 		    num_words);
304 		dest += num_words;
305 		nread += num_words;
306 	}
307 
308 	cnt = nread * sizeof(uint32_t);
309 	if (cnt > 0)
310 		random_harvest_queue(sc->sc_buf, cnt, cnt * NBBY / 2,
311 		    RANDOM_PURE_BROADCOM);
312 
313 #if defined(BCM2835_RNG_USE_CALLOUT)
314 	callout_reset(&sc->sc_rngto, sc->sc_rnghz, bcm2835_rng_harvest, sc);
315 #endif
316 }
317 
318 static int
319 sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
320 {
321 	struct bcm2835_rng_softc *sc = arg1;
322 	int error, rbg2x;
323 
324 	rbg2x = sc->sc_rbg2x;
325 	error = sysctl_handle_int(oidp, &rbg2x, 0, req);
326 	if (error)
327 		return (error);
328 	if (req->newptr == NULL)
329 		return (error);
330 	if (rbg2x == sc->sc_rbg2x)
331 		return (0);
332 
333 	/* Reset the RNG */
334 	bcm2835_rng_stop(sc);
335 	sc->sc_rbg2x = rbg2x;
336 	bcm2835_rng_start(sc);
337 
338 	return (0);
339 }
340 
341 #ifdef BCM2835_RNG_DEBUG_REGISTERS
342 static int
343 sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
344 {
345 	struct sbuf sb;
346 	struct bcm2835_rng_softc *sc = arg1;
347 	int error;
348 
349 	error = sysctl_wire_old_buffer(req, 0);
350 	if (error != 0)
351 		return (error);
352 	sbuf_new_for_sysctl(&sb, NULL, 128, req);
353 	bcm2835_rng_dump_registers(sc, &sb);
354         error = sbuf_finish(&sb);
355         sbuf_delete(&sb);
356         return (error);
357 }
358 #endif
359 
360 static int
361 bcm2835_rng_probe(device_t dev)
362 {
363 
364 	if (!ofw_bus_status_okay(dev))
365 		return (ENXIO);
366 
367 	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-rng"))
368 		return (ENXIO);
369 
370 	device_set_desc(dev, "Broadcom BCM2835 RNG");
371 
372 	return (BUS_PROBE_DEFAULT);
373 }
374 
375 static int
376 bcm2835_rng_attach(device_t dev)
377 {
378 	struct bcm2835_rng_softc *sc;
379 	struct sysctl_ctx_list *sysctl_ctx;
380 	struct sysctl_oid *sysctl_tree;
381 	int error, rid;
382 
383 	error = 0;
384 	sc = device_get_softc(dev);
385 	sc->sc_dev = dev;
386 	sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
387 #ifdef BCM2835_RNG_USE_CALLOUT
388 	/* Initialize callout */
389 	callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
390 #endif
391 	TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
392 	TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
393 
394 	/* Allocate memory resources */
395 	rid = 0;
396 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
397 	    RF_ACTIVE);
398 	if (sc->sc_mem_res == NULL) {
399 		bcm2835_rng_detach(dev);
400 		return (ENXIO);
401 	}
402 
403 #if defined(BCM2835_RNG_USE_INTERRUPT)
404 	/* Allocate interrupt resource */
405 	rid = 0;
406 	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
407 	    RF_SHAREABLE | RF_ACTIVE);
408 	if (sc->sc_irq_res == NULL) {
409 		bcm2835_rng_detach(dev);
410 		return (ENXIO);
411 	}
412 
413 	/* Set up the interrupt handler */
414 	error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
415 	    NULL, (driver_intr_t *)bcm2835_rng_harvest, sc, &sc->sc_intr_hdl);
416 	if (error) {
417 		device_printf(dev, "Failed to set up IRQ\n");
418 		sc->sc_intr_hdl = NULL;
419 		bcm2835_rng_detach(dev);
420 		return (error);
421 	}
422 #endif
423 
424 	/* Start the RNG */
425 	bcm2835_rng_start(sc);
426 
427 	/* Dump the registers if booting verbose */
428 	if (bootverbose) {
429 		struct sbuf sb;
430 
431 		(void) sbuf_new(&sb, NULL, 256,
432 		    SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
433 		bcm2835_rng_dump_registers(sc, &sb);
434 		sbuf_trim(&sb);
435 		error = sbuf_finish(&sb);
436 		if (error == 0)
437 			device_printf(dev, "%s", sbuf_data(&sb));
438 		sbuf_delete(&sb);
439 	}
440 
441 	sysctl_ctx = device_get_sysctl_ctx(dev);
442 	sysctl_tree = device_get_sysctl_tree(dev);
443 	SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
444 	    "underrun", CTLFLAG_RD, &sc->sc_underrun,
445 	    "Number of FIFO underruns");
446 	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
447 	    "2xspeed", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
448 	    sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
449 	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
450 	    "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
451 	    RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
452 #ifdef BCM2835_RNG_DEBUG_REGISTERS
453 	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
454 	    "dumpregs", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
455 	    sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
456 #endif
457 
458 #if defined(BCM2835_RNG_USE_CALLOUT)
459 	/* Reset callout */
460 	if (hz >= 100)
461 		sc->sc_rnghz = hz / 100;
462 	else
463 		sc->sc_rnghz = 1;
464 	callout_reset(&sc->sc_rngto, sc->sc_rnghz, bcm2835_rng_harvest, sc);
465 #endif
466 
467 	return (0);
468 }
469 
470 static int
471 bcm2835_rng_detach(device_t dev)
472 {
473 	struct bcm2835_rng_softc *sc;
474 #if defined(BCM2835_RNG_USE_INTERRUPT)
475 	int error;
476 #endif
477 
478 	sc = device_get_softc(dev);
479 
480 	/* Stop the RNG */
481 	bcm2835_rng_stop(sc);
482 
483 	/* Drain the callout it */
484 #if defined(BCM2835_RNG_USE_CALLOUT)
485 	callout_drain(&sc->sc_rngto);
486 #endif
487 
488 #if defined(BCM2835_RNG_USE_INTERRUPT)
489 	/* Tear down the interrupt */
490 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
491 		error = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
492 		if (error != 0) {
493 			device_printf(dev, "could not tear down IRQ\n");
494 			return (error);
495 		}
496 		sc->sc_intr_hdl = NULL;
497 	}
498 
499 	/* Release interrupt resource */
500 	if (sc->sc_irq_res) {
501 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
502 		sc->sc_irq_res = NULL;
503 	}
504 #endif
505 
506 	/* Release memory resource */
507 	if (sc->sc_mem_res != NULL)
508 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
509 
510 	return (0);
511 }
512 
513 static device_method_t bcm2835_rng_methods[] = {
514 	/* Device interface */
515 	DEVMETHOD(device_probe,		bcm2835_rng_probe),
516 	DEVMETHOD(device_attach,	bcm2835_rng_attach),
517 	DEVMETHOD(device_detach,	bcm2835_rng_detach),
518 
519 	DEVMETHOD_END
520 };
521 
522 static driver_t bcm2835_rng_driver = {
523 	"bcmrng",
524 	bcm2835_rng_methods,
525 	sizeof(struct bcm2835_rng_softc)
526 };
527 static devclass_t bcm2835_rng_devclass;
528 
529 DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver,
530     bcm2835_rng_devclass, 0, 0);
531 DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, bcm2835_rng_devclass, 0,
532     0);
533 MODULE_VERSION(bcm2835_rng, 1);
534 MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);
535