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: stable/11/sys/arm/broadcom/bcm2835/bcm2835_rng.c 331905 2018-04-03 03:41:55Z gonzo $");
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
54static device_attach_t bcm2835_rng_attach;
55static device_detach_t bcm2835_rng_detach;
56static 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
93struct 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
105static struct ofw_compat_data compat_data[] = {
106	{"broadcom,bcm2835-rng",	1},
107	{"brcm,bcm2835-rng",		1},
108	{NULL,				0}
109};
110
111static __inline void
112bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
113{
114
115	atomic_add_long(&sc->sc_underrun, 1);
116}
117
118static __inline uint32_t
119bcm2835_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
125static __inline void
126bcm2835_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
133static __inline void
134bcm2835_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
140static void
141bcm2835_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
199static void
200bcm2835_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
210static void
211bcm2835_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
229static void
230bcm2835_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
240static void
241bcm2835_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, cnt * NBBY / 2,
293		    RANDOM_PURE_BROADCOM);
294
295	callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, bcm2835_rng_harvest, sc);
296}
297
298static int
299sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
300{
301	struct bcm2835_rng_softc *sc = arg1;
302	int error, rbg2x;
303
304	rbg2x = sc->sc_rbg2x;
305	error = sysctl_handle_int(oidp, &rbg2x, 0, req);
306	if (error)
307		return (error);
308	if (req->newptr == NULL)
309		return (error);
310	if (rbg2x == sc->sc_rbg2x)
311		return (0);
312
313	/* Reset the RNG */
314	bcm2835_rng_stop(sc);
315	sc->sc_rbg2x = rbg2x;
316	bcm2835_rng_start(sc);
317
318	return (0);
319}
320
321#ifdef BCM2835_RNG_DEBUG_REGISTERS
322static int
323sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
324{
325	struct sbuf sb;
326	struct bcm2835_rng_softc *sc = arg1;
327	int error;
328
329	error = sysctl_wire_old_buffer(req, 0);
330	if (error != 0)
331		return (error);
332	sbuf_new_for_sysctl(&sb, NULL, 128, req);
333	bcm2835_rng_dump_registers(sc, &sb);
334        error = sbuf_finish(&sb);
335        sbuf_delete(&sb);
336        return (error);
337}
338#endif
339
340static int
341bcm2835_rng_probe(device_t dev)
342{
343
344	if (!ofw_bus_status_okay(dev))
345		return (ENXIO);
346
347	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
348		return (ENXIO);
349
350	device_set_desc(dev, "Broadcom BCM2835 RNG");
351
352	return (BUS_PROBE_DEFAULT);
353}
354
355static int
356bcm2835_rng_attach(device_t dev)
357{
358	struct bcm2835_rng_softc *sc;
359	struct sysctl_ctx_list *sysctl_ctx;
360	struct sysctl_oid *sysctl_tree;
361	int error, rid;
362
363	error = 0;
364	sc = device_get_softc(dev);
365	sc->sc_dev = dev;
366	sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
367
368	/* Initialize callout */
369	callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
370
371	TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
372	TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
373
374	/* Allocate memory resources */
375	rid = 0;
376	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
377	    RF_ACTIVE);
378	if (sc->sc_mem_res == NULL) {
379		bcm2835_rng_detach(dev);
380		return (ENXIO);
381	}
382
383	/* Start the RNG */
384	bcm2835_rng_start(sc);
385
386	/* Dump the registers if booting verbose */
387	if (bootverbose) {
388		struct sbuf sb;
389
390		(void) sbuf_new(&sb, NULL, 256,
391		    SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
392		bcm2835_rng_dump_registers(sc, &sb);
393		sbuf_trim(&sb);
394		error = sbuf_finish(&sb);
395		if (error == 0)
396			device_printf(dev, "%s", sbuf_data(&sb));
397		sbuf_delete(&sb);
398	}
399
400	sysctl_ctx = device_get_sysctl_ctx(dev);
401	sysctl_tree = device_get_sysctl_tree(dev);
402	SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
403	    "underrun", CTLFLAG_RD, &sc->sc_underrun,
404	    "Number of FIFO underruns");
405	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
406	    "2xspeed", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
407	    sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
408	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
409	    "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
410	    RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
411#ifdef BCM2835_RNG_DEBUG_REGISTERS
412	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
413	    "dumpregs", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
414	    sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
415#endif
416
417	/*
418	 * Schedule the initial harvesting one second from now, which should give the
419	 * hardware RNG plenty of time to generate the first random bytes.
420	 */
421	callout_reset(&sc->sc_rngto, hz, bcm2835_rng_harvest, sc);
422
423	return (0);
424}
425
426static int
427bcm2835_rng_detach(device_t dev)
428{
429	struct bcm2835_rng_softc *sc;
430
431	sc = device_get_softc(dev);
432
433	/* Stop the RNG */
434	bcm2835_rng_stop(sc);
435
436	/* Drain the callout it */
437	callout_drain(&sc->sc_rngto);
438
439	/* Release memory resource */
440	if (sc->sc_mem_res != NULL)
441		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
442
443	return (0);
444}
445
446static device_method_t bcm2835_rng_methods[] = {
447	/* Device interface */
448	DEVMETHOD(device_probe,		bcm2835_rng_probe),
449	DEVMETHOD(device_attach,	bcm2835_rng_attach),
450	DEVMETHOD(device_detach,	bcm2835_rng_detach),
451
452	DEVMETHOD_END
453};
454
455static driver_t bcm2835_rng_driver = {
456	"bcmrng",
457	bcm2835_rng_methods,
458	sizeof(struct bcm2835_rng_softc)
459};
460static devclass_t bcm2835_rng_devclass;
461
462DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver,
463    bcm2835_rng_devclass, 0, 0);
464DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, bcm2835_rng_devclass, 0,
465    0);
466MODULE_VERSION(bcm2835_rng, 1);
467MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);
468