xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_rng.c (revision 6829dae12bb055451fa467da4589c43bd03b1e64)
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 static device_attach_t bcm2835_rng_attach;
55 static device_detach_t bcm2835_rng_detach;
56 static device_probe_t bcm2835_rng_probe;
57 
58 #define	RNG_CTRL		0x00		/* RNG Control Register */
59 #define	RNG_COMBLK1_OSC		0x003f0000	/*  Combiner Blk 1 Oscillator */
60 #define	RNG_COMBLK1_OSC_SHIFT	16
61 #define	RNG_COMBLK2_OSC		0x0fc00000	/*  Combiner Blk 2 Oscillator */
62 #define	RNG_COMBLK2_OSC_SHIFT	22
63 #define	RNG_JCLK_BYP_DIV_CNT	0x0000ff00	/*  Jitter clk bypass divider
64 						    count */
65 #define	RNG_JCLK_BYP_DIV_CNT_SHIFT 8
66 #define	RNG_JCLK_BYP_SRC	0x00000020	/*  Jitter clk bypass source */
67 #define	RNG_JCLK_BYP_SEL	0x00000010	/*  Jitter clk bypass select */
68 #define	RNG_RBG2X		0x00000002	/*  RBG 2X SPEED */
69 #define	RNG_RBGEN_BIT		0x00000001	/*  Enable RNG bit */
70 
71 #define	RNG_STATUS		0x04		/* RNG status register */
72 #define	RND_VAL_SHIFT		24		/*  Shift for valid words */
73 #define	RND_VAL_MASK		0x000000ff	/*  Number valid words mask */
74 #define	RND_VAL_WARM_CNT	0x40000		/*  RNG Warm Up count */
75 #define	RND_WARM_CNT		0xfffff		/*  RNG Warm Up Count mask */
76 
77 #define	RNG_DATA		0x08		/* RNG Data Register */
78 #define	RNG_FF_THRES		0x0c
79 #define	RNG_FF_THRES_MASK	0x0000001f
80 
81 #define	RNG_INT_MASK		0x10
82 #define	RNG_INT_OFF_BIT		0x00000001
83 
84 #define	RNG_FF_DEFAULT		0x10		/* FIFO threshold default */
85 
86 #define	RNG_FIFO_WORDS		(RNG_FF_DEFAULT / sizeof(uint32_t))
87 
88 #define	RNG_NUM_OSCILLATORS	6
89 #define	RNG_STALL_COUNT_DEFAULT	10
90 
91 #define	RNG_CALLOUT_TICKS	(hz * 4)
92 
93 struct bcm2835_rng_softc {
94 	device_t		sc_dev;
95 	struct resource *	sc_mem_res;
96 	struct resource *	sc_irq_res;
97 	void *			sc_intr_hdl;
98 	uint32_t		sc_buf[RNG_FIFO_WORDS];
99 	struct callout		sc_rngto;
100 	int			sc_stall_count;
101 	int			sc_rbg2x;
102 	long			sc_underrun;
103 };
104 
105 static struct ofw_compat_data compat_data[] = {
106 	{"broadcom,bcm2835-rng",	1},
107 	{"brcm,bcm2835-rng",		1},
108 	{NULL,				0}
109 };
110 
111 static __inline void
112 bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
113 {
114 
115 	atomic_add_long(&sc->sc_underrun, 1);
116 }
117 
118 static __inline uint32_t
119 bcm2835_rng_read4(struct bcm2835_rng_softc *sc, bus_size_t off)
120 {
121 
122 	return bus_read_4(sc->sc_mem_res, off);
123 }
124 
125 static __inline void
126 bcm2835_rng_read_multi4(struct bcm2835_rng_softc *sc, bus_size_t off,
127     uint32_t *datap, bus_size_t count)
128 {
129 
130 	bus_read_multi_4(sc->sc_mem_res, off, datap, count);
131 }
132 
133 static __inline void
134 bcm2835_rng_write4(struct bcm2835_rng_softc *sc, bus_size_t off, uint32_t val)
135 {
136 
137 	bus_write_4(sc->sc_mem_res, off, val);
138 }
139 
140 static void
141 bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
142 {
143 	uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
144 	int i;
145 
146 	/* Display RNG control register contents */
147 	val = bcm2835_rng_read4(sc, RNG_CTRL);
148 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
149 
150 	comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
151 	sbuf_printf(sbp, "  RNG_COMBLK2_OSC (%02x)\n", comblk2_osc);
152 	for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
153 		if ((comblk2_osc & (1 << i)) == 0)
154 			sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
155 
156 	comblk1_osc = (val & RNG_COMBLK1_OSC) >> RNG_COMBLK1_OSC_SHIFT;
157 	sbuf_printf(sbp, "  RNG_COMBLK1_OSC (%02x)\n", comblk1_osc);
158 	for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
159 		if ((comblk1_osc & (1 << i)) == 0)
160 			sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
161 
162 	jclk_byp_div = (val & RNG_JCLK_BYP_DIV_CNT) >>
163 	    RNG_JCLK_BYP_DIV_CNT_SHIFT;
164 	sbuf_printf(sbp,
165 	    "  RNG_JCLK_BYP_DIV_CNT (%02x)\n    APB clock frequency / %d\n",
166 	    jclk_byp_div, 2 * (jclk_byp_div + 1));
167 
168 	sbuf_printf(sbp, "  RNG_JCLK_BYP_SRC:\n    %s\n",
169 	    (val & RNG_JCLK_BYP_SRC) ? "Use divided down APB clock" :
170 	    "Use RNG clock (APB clock)");
171 
172 	sbuf_printf(sbp, "  RNG_JCLK_BYP_SEL:\n    %s\n",
173 	    (val & RNG_JCLK_BYP_SEL) ? "Bypass internal jitter clock" :
174 	    "Use internal jitter clock");
175 
176 	if ((val & RNG_RBG2X) != 0)
177 		sbuf_cat(sbp, "  RNG_RBG2X: RNG 2X SPEED enabled\n");
178 
179 	if ((val & RNG_RBGEN_BIT) != 0)
180 		sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
181 
182 	/* Display RNG status register contents */
183 	val = bcm2835_rng_read4(sc, RNG_STATUS);
184 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
185 	sbuf_printf(sbp, "  RND_VAL: %02x\n",
186 	    (val >> RND_VAL_SHIFT) & RND_VAL_MASK);
187 	sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & RND_WARM_CNT);
188 
189 	/* Display FIFO threshold register contents */
190 	val = bcm2835_rng_read4(sc, RNG_FF_THRES);
191 	sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
192 
193 	/* Display interrupt mask register contents */
194 	val = bcm2835_rng_read4(sc, RNG_INT_MASK);
195 	sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
196 	     ((val & RNG_INT_OFF_BIT) != 0) ? "disabled" : "enabled");
197 }
198 
199 static void
200 bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
201 {
202 	uint32_t mask;
203 
204 	/* Set the interrupt off bit in the interrupt mask register */
205 	mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
206 	mask |= RNG_INT_OFF_BIT;
207         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
208 }
209 
210 static void
211 bcm2835_rng_start(struct bcm2835_rng_softc *sc)
212 {
213 	uint32_t ctrl;
214 
215 	/* Disable the interrupt */
216 	bcm2835_rng_disable_intr(sc);
217 
218 	/* Set the warmup count */
219 	bcm2835_rng_write4(sc, RNG_STATUS, RND_VAL_WARM_CNT);
220 
221 	/* Enable the RNG */
222 	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
223 	ctrl |= RNG_RBGEN_BIT;
224 	if (sc->sc_rbg2x)
225 		ctrl |= RNG_RBG2X;
226 	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
227 }
228 
229 static void
230 bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
231 {
232 	uint32_t ctrl;
233 
234 	/* Disable the RNG */
235 	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
236 	ctrl &= ~RNG_RBGEN_BIT;
237 	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
238 }
239 
240 static void
241 bcm2835_rng_harvest(void *arg)
242 {
243 	uint32_t *dest;
244 	uint32_t status;
245 	u_int cnt, nread, num_avail, num_words;
246 	int seen_underrun, num_stalls;
247 	struct bcm2835_rng_softc *sc = arg;
248 
249 	dest = sc->sc_buf;
250 	nread = num_words = 0;
251 	seen_underrun = num_stalls = 0;
252 	for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
253 	    cnt -= num_words) {
254 		/* Read status register to find out how many words available */
255 		status = bcm2835_rng_read4(sc, RNG_STATUS);
256 		num_avail = (status >> RND_VAL_SHIFT) & RND_VAL_MASK;
257 
258 		/* If we have none... */
259 		if (num_avail == 0) {
260 			bcm2835_rng_stat_inc_underrun(sc);
261 			if (++seen_underrun >= sc->sc_stall_count) {
262 				if (num_stalls++ > 0) {
263 					device_printf(sc->sc_dev,
264 					    "RNG stalled, disabling device\n");
265 					bcm2835_rng_stop(sc);
266 					break;
267 				} else {
268 					device_printf(sc->sc_dev,
269 					    "Too many underruns, resetting\n");
270 					bcm2835_rng_stop(sc);
271 					bcm2835_rng_start(sc);
272 					seen_underrun = 0;
273 				}
274 			}
275 			/* Try again */
276 			continue;
277 		}
278 
279 		CTR2(KTR_DEV, "%s: %d words available in RNG FIFO",
280 		    device_get_nameunit(sc->sc_dev), num_avail);
281 
282 		/* Pull MIN(num_avail, cnt) words from the FIFO */
283 		num_words = (num_avail > cnt) ? cnt : num_avail;
284 		bcm2835_rng_read_multi4(sc, RNG_DATA, dest,
285 		    num_words);
286 		dest += num_words;
287 		nread += num_words;
288 	}
289 
290 	cnt = nread * sizeof(uint32_t);
291 	if (cnt > 0)
292 		random_harvest_queue(sc->sc_buf, cnt, RANDOM_PURE_BROADCOM);
293 
294 	callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, bcm2835_rng_harvest, sc);
295 }
296 
297 static int
298 sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
299 {
300 	struct bcm2835_rng_softc *sc = arg1;
301 	int error, rbg2x;
302 
303 	rbg2x = sc->sc_rbg2x;
304 	error = sysctl_handle_int(oidp, &rbg2x, 0, req);
305 	if (error)
306 		return (error);
307 	if (req->newptr == NULL)
308 		return (error);
309 	if (rbg2x == sc->sc_rbg2x)
310 		return (0);
311 
312 	/* Reset the RNG */
313 	bcm2835_rng_stop(sc);
314 	sc->sc_rbg2x = rbg2x;
315 	bcm2835_rng_start(sc);
316 
317 	return (0);
318 }
319 
320 #ifdef BCM2835_RNG_DEBUG_REGISTERS
321 static int
322 sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
323 {
324 	struct sbuf sb;
325 	struct bcm2835_rng_softc *sc = arg1;
326 	int error;
327 
328 	error = sysctl_wire_old_buffer(req, 0);
329 	if (error != 0)
330 		return (error);
331 	sbuf_new_for_sysctl(&sb, NULL, 128, req);
332 	bcm2835_rng_dump_registers(sc, &sb);
333         error = sbuf_finish(&sb);
334         sbuf_delete(&sb);
335         return (error);
336 }
337 #endif
338 
339 static int
340 bcm2835_rng_probe(device_t dev)
341 {
342 
343 	if (!ofw_bus_status_okay(dev))
344 		return (ENXIO);
345 
346 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
347 		return (ENXIO);
348 
349 	device_set_desc(dev, "Broadcom BCM2835 RNG");
350 
351 	return (BUS_PROBE_DEFAULT);
352 }
353 
354 static int
355 bcm2835_rng_attach(device_t dev)
356 {
357 	struct bcm2835_rng_softc *sc;
358 	struct sysctl_ctx_list *sysctl_ctx;
359 	struct sysctl_oid *sysctl_tree;
360 	int error, rid;
361 
362 	error = 0;
363 	sc = device_get_softc(dev);
364 	sc->sc_dev = dev;
365 	sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
366 
367 	/* Initialize callout */
368 	callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
369 
370 	TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
371 	TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
372 
373 	/* Allocate memory resources */
374 	rid = 0;
375 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
376 	    RF_ACTIVE);
377 	if (sc->sc_mem_res == NULL) {
378 		bcm2835_rng_detach(dev);
379 		return (ENXIO);
380 	}
381 
382 	/* Start the RNG */
383 	bcm2835_rng_start(sc);
384 
385 	/* Dump the registers if booting verbose */
386 	if (bootverbose) {
387 		struct sbuf sb;
388 
389 		(void) sbuf_new(&sb, NULL, 256,
390 		    SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
391 		bcm2835_rng_dump_registers(sc, &sb);
392 		sbuf_trim(&sb);
393 		error = sbuf_finish(&sb);
394 		if (error == 0)
395 			device_printf(dev, "%s", sbuf_data(&sb));
396 		sbuf_delete(&sb);
397 	}
398 
399 	sysctl_ctx = device_get_sysctl_ctx(dev);
400 	sysctl_tree = device_get_sysctl_tree(dev);
401 	SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
402 	    "underrun", CTLFLAG_RD, &sc->sc_underrun,
403 	    "Number of FIFO underruns");
404 	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
405 	    "2xspeed", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
406 	    sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
407 	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
408 	    "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
409 	    RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
410 #ifdef BCM2835_RNG_DEBUG_REGISTERS
411 	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
412 	    "dumpregs", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
413 	    sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
414 #endif
415 
416 	/*
417 	 * Schedule the initial harvesting one second from now, which should give the
418 	 * hardware RNG plenty of time to generate the first random bytes.
419 	 */
420 	callout_reset(&sc->sc_rngto, hz, bcm2835_rng_harvest, sc);
421 
422 	return (0);
423 }
424 
425 static int
426 bcm2835_rng_detach(device_t dev)
427 {
428 	struct bcm2835_rng_softc *sc;
429 
430 	sc = device_get_softc(dev);
431 
432 	/* Stop the RNG */
433 	bcm2835_rng_stop(sc);
434 
435 	/* Drain the callout it */
436 	callout_drain(&sc->sc_rngto);
437 
438 	/* Release memory resource */
439 	if (sc->sc_mem_res != NULL)
440 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
441 
442 	return (0);
443 }
444 
445 static device_method_t bcm2835_rng_methods[] = {
446 	/* Device interface */
447 	DEVMETHOD(device_probe,		bcm2835_rng_probe),
448 	DEVMETHOD(device_attach,	bcm2835_rng_attach),
449 	DEVMETHOD(device_detach,	bcm2835_rng_detach),
450 
451 	DEVMETHOD_END
452 };
453 
454 static driver_t bcm2835_rng_driver = {
455 	"bcmrng",
456 	bcm2835_rng_methods,
457 	sizeof(struct bcm2835_rng_softc)
458 };
459 static devclass_t bcm2835_rng_devclass;
460 
461 DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver,
462     bcm2835_rng_devclass, 0, 0);
463 DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, bcm2835_rng_devclass, 0,
464     0);
465 MODULE_VERSION(bcm2835_rng, 1);
466 MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);
467