git: 52f66bc3ff72 - stable/13 - arm64: Add support for bcm2838 RNG

Gordon Bergling gbe at FreeBSD.org
Sat Mar 20 10:12:31 UTC 2021


The branch stable/13 has been updated by gbe (doc committer):

URL: https://cgit.FreeBSD.org/src/commit/?id=52f66bc3ff72aa266a5dbe86913b0fee68861258

commit 52f66bc3ff72aa266a5dbe86913b0fee68861258
Author:     Gordon Bergling <gbe at FreeBSD.org>
AuthorDate: 2021-03-06 11:28:35 +0000
Commit:     Gordon Bergling <gbe at FreeBSD.org>
CommitDate: 2021-03-20 10:12:13 +0000

    arm64: Add support for bcm2838 RNG
    
    The hardware random number generator of the RPi4 differs slightly
    from the version found on the RPi3.
    
    This commit extends the existing bcm2835_rng driver to function on the RPi4.
    
    Submitted by:   James Mintram <me at jamesrm dot com>
    Reviewed by:    markm, cem, delphij
    Approved by:    csprng(cem, markm)
    Differential Revision:  https://reviews.freebsd.org/D22493
    
    (cherry picked from commit e797dc58bd29c5bc0873fc620fc11d5332f90e7f)
---
 sys/arm/broadcom/bcm2835/bcm2835_rng.c | 174 +++++++++++++++++++++++++--------
 1 file changed, 133 insertions(+), 41 deletions(-)

diff --git a/sys/arm/broadcom/bcm2835/bcm2835_rng.c b/sys/arm/broadcom/bcm2835/bcm2835_rng.c
index b73580c5eb53..c403bc3542e0 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_rng.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_rng.c
@@ -69,21 +69,26 @@ static device_probe_t bcm2835_rng_probe;
 #define	RNG_RBG2X		0x00000002	/*  RBG 2X SPEED */
 #define	RNG_RBGEN_BIT		0x00000001	/*  Enable RNG bit */
 
-#define	RNG_STATUS		0x04		/* RNG status register */
-#define	RND_VAL_SHIFT		24		/*  Shift for valid words */
-#define	RND_VAL_MASK		0x000000ff	/*  Number valid words mask */
-#define	RND_VAL_WARM_CNT	0x40000		/*  RNG Warm Up count */
-#define	RND_WARM_CNT		0xfffff		/*  RNG Warm Up Count mask */
+#define	BCM2835_RNG_STATUS	0x04		/* BCM2835 RNG status register */
+#define	BCM2838_RNG_STATUS	0x18		/* BCM2838 RNG status register */
 
-#define	RNG_DATA		0x08		/* RNG Data Register */
+#define	BCM2838_RNG_COUNT	0x24		/* How many values available */
+#define	BCM2838_COUNT_VAL_MASK	0x000000ff
+
+#define	BCM2835_RND_VAL_SHIFT	24		/*  Shift for valid words */
+#define	BCM2835_RND_VAL_MASK	0x000000ff	/*  Number valid words mask */
+#define	BCM2835_RND_VAL_WARM_CNT	0x40000		/*  RNG Warm Up count */
+#define	BCM2835_RND_WARM_CNT	0xfffff		/*  RNG Warm Up Count mask */
+
+#define	BCM2835_RNG_DATA	0x08		/* RNG Data Register */
+#define	BCM2838_RNG_DATA	0x20
 #define	RNG_FF_THRES		0x0c
 #define	RNG_FF_THRES_MASK	0x0000001f
 
-#define	RNG_INT_MASK		0x10
-#define	RNG_INT_OFF_BIT		0x00000001
+#define	BCM2835_RNG_INT_MASK		0x10
+#define	BCM2835_RNG_INT_OFF_BIT		0x00000001
 
 #define	RNG_FF_DEFAULT		0x10		/* FIFO threshold default */
-
 #define	RNG_FIFO_WORDS		(RNG_FF_DEFAULT / sizeof(uint32_t))
 
 #define	RNG_NUM_OSCILLATORS	6
@@ -91,11 +96,55 @@ static device_probe_t bcm2835_rng_probe;
 
 #define	RNG_CALLOUT_TICKS	(hz * 4)
 
+struct bcm_rng_conf {
+	bus_size_t		control_reg;
+	bus_size_t		status_reg;
+	bus_size_t		count_reg;
+	bus_size_t		data_reg;
+	bus_size_t		intr_mask_reg;
+	uint32_t		intr_disable_bit;
+	uint32_t		count_value_shift;
+	uint32_t		count_value_mask;
+	uint32_t		warmup_count;
+	bool			allow_2x_mode;
+	bool			can_diagnose;
+	/* XXX diag regs */
+};
+
+static const struct bcm_rng_conf bcm2835_rng_conf = {
+	.control_reg		= RNG_CTRL,
+	.status_reg		= BCM2835_RNG_STATUS,
+	.count_reg		= BCM2835_RNG_STATUS,	/* Same register */
+	.data_reg		= BCM2835_RNG_DATA,
+	.intr_mask_reg		= BCM2835_RNG_INT_MASK,
+	.intr_disable_bit	= BCM2835_RNG_INT_OFF_BIT,
+	.count_value_shift	= BCM2835_RND_VAL_SHIFT,
+	.count_value_mask	= BCM2835_RND_VAL_MASK,
+	.warmup_count		= BCM2835_RND_VAL_WARM_CNT,
+	.allow_2x_mode		= true,
+	.can_diagnose		= true
+};
+
+static const struct bcm_rng_conf bcm2838_rng_conf = {
+	.control_reg		= RNG_CTRL,
+	.status_reg		= BCM2838_RNG_STATUS,
+	.count_reg		= BCM2838_RNG_COUNT,
+	.data_reg		= BCM2838_RNG_DATA,
+	.intr_mask_reg		= 0,
+	.intr_disable_bit	= 0,
+	.count_value_shift	= 0,
+	.count_value_mask	= BCM2838_COUNT_VAL_MASK,
+	.warmup_count		= 0,
+	.allow_2x_mode		= false,
+	.can_diagnose		= false
+};
+
 struct bcm2835_rng_softc {
 	device_t		sc_dev;
 	struct resource *	sc_mem_res;
 	struct resource *	sc_irq_res;
 	void *			sc_intr_hdl;
+	struct bcm_rng_conf const*	conf;
 	uint32_t		sc_buf[RNG_FIFO_WORDS];
 	struct callout		sc_rngto;
 	int			sc_stall_count;
@@ -104,8 +153,15 @@ struct bcm2835_rng_softc {
 };
 
 static struct ofw_compat_data compat_data[] = {
-	{"broadcom,bcm2835-rng",	1},
-	{"brcm,bcm2835-rng",		1},
+	{"broadcom,bcm2835-rng",	(uintptr_t)&bcm2835_rng_conf},
+	{"brcm,bcm2835-rng",		(uintptr_t)&bcm2835_rng_conf},
+
+	{"brcm,bcm2711-rng200",		(uintptr_t)&bcm2838_rng_conf},
+	{"brcm,bcm2838-rng",		(uintptr_t)&bcm2838_rng_conf},
+	{"brcm,bcm2838-rng200",		(uintptr_t)&bcm2838_rng_conf},
+	{"brcm,bcm7211-rng",		(uintptr_t)&bcm2838_rng_conf},
+	{"brcm,bcm7278-rng",		(uintptr_t)&bcm2838_rng_conf},
+	{"brcm,iproc-rng200",		(uintptr_t)&bcm2838_rng_conf},
 	{NULL,				0}
 };
 
@@ -144,8 +200,12 @@ bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
 	uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
 	int i;
 
+	if (!sc->conf->can_diagnose)
+	    /* Not implemented. */
+	    return;
+
 	/* Display RNG control register contents */
-	val = bcm2835_rng_read4(sc, RNG_CTRL);
+	val = bcm2835_rng_read4(sc, sc->conf->control_reg);
 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
 
 	comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
@@ -181,20 +241,20 @@ bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
 		sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
 
 	/* Display RNG status register contents */
-	val = bcm2835_rng_read4(sc, RNG_STATUS);
+	val = bcm2835_rng_read4(sc, sc->conf->status_reg);
 	sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
 	sbuf_printf(sbp, "  RND_VAL: %02x\n",
-	    (val >> RND_VAL_SHIFT) & RND_VAL_MASK);
-	sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & RND_WARM_CNT);
+	    (val >> sc->conf->count_value_shift) & sc->conf->count_value_mask);
+	sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & sc->conf->warmup_count);
 
 	/* Display FIFO threshold register contents */
 	val = bcm2835_rng_read4(sc, RNG_FF_THRES);
 	sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
 
 	/* Display interrupt mask register contents */
-	val = bcm2835_rng_read4(sc, RNG_INT_MASK);
+	val = bcm2835_rng_read4(sc, sc->conf->intr_mask_reg);
 	sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
-	     ((val & RNG_INT_OFF_BIT) != 0) ? "disabled" : "enabled");
+	     ((val & sc->conf->intr_disable_bit) != 0) ? "disabled" : "enabled");
 }
 
 static void
@@ -203,9 +263,9 @@ bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
 	uint32_t mask;
 
 	/* Set the interrupt off bit in the interrupt mask register */
-	mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
-	mask |= RNG_INT_OFF_BIT;
-        bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
+	mask = bcm2835_rng_read4(sc, sc->conf->intr_mask_reg);
+	mask |= sc->conf->intr_disable_bit;
+	bcm2835_rng_write4(sc, sc->conf->intr_mask_reg, mask);
 }
 
 static void
@@ -214,17 +274,20 @@ bcm2835_rng_start(struct bcm2835_rng_softc *sc)
 	uint32_t ctrl;
 
 	/* Disable the interrupt */
-	bcm2835_rng_disable_intr(sc);
+	if (sc->conf->intr_mask_reg)
+	    bcm2835_rng_disable_intr(sc);
 
 	/* Set the warmup count */
-	bcm2835_rng_write4(sc, RNG_STATUS, RND_VAL_WARM_CNT);
+	if (sc->conf->warmup_count > 0)
+	    bcm2835_rng_write4(sc, sc->conf->status_reg,
+		    sc->conf->warmup_count);
 
 	/* Enable the RNG */
-	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
+	ctrl = bcm2835_rng_read4(sc, sc->conf->control_reg);
 	ctrl |= RNG_RBGEN_BIT;
-	if (sc->sc_rbg2x)
+	if (sc->sc_rbg2x && sc->conf->allow_2x_mode)
 		ctrl |= RNG_RBG2X;
-	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
+	bcm2835_rng_write4(sc, sc->conf->control_reg, ctrl);
 }
 
 static void
@@ -233,16 +296,39 @@ bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
 	uint32_t ctrl;
 
 	/* Disable the RNG */
-	ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
+	ctrl = bcm2835_rng_read4(sc, sc->conf->control_reg);
 	ctrl &= ~RNG_RBGEN_BIT;
-	bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
+	bcm2835_rng_write4(sc, sc->conf->control_reg, ctrl);
+}
+
+static void
+bcm2835_rng_enqueue_harvest(struct bcm2835_rng_softc *sc, uint32_t nread)
+{
+	char *sc_buf_chunk;
+	uint32_t chunk_size;
+	uint32_t cnt;
+
+	chunk_size = sizeof(((struct harvest_event *)0)->he_entropy);
+	cnt = nread * sizeof(uint32_t);
+	sc_buf_chunk = (void*)sc->sc_buf;
+
+	while (cnt > 0) {
+		uint32_t size;
+
+		size = MIN(cnt, chunk_size);
+
+		random_harvest_queue(sc_buf_chunk, size, RANDOM_PURE_BROADCOM);
+
+		sc_buf_chunk += size;
+		cnt -= size;
+	}
 }
 
 static void
 bcm2835_rng_harvest(void *arg)
 {
 	uint32_t *dest;
-	uint32_t status;
+	uint32_t hwcount;
 	u_int cnt, nread, num_avail, num_words;
 	int seen_underrun, num_stalls;
 	struct bcm2835_rng_softc *sc = arg;
@@ -250,11 +336,13 @@ bcm2835_rng_harvest(void *arg)
 	dest = sc->sc_buf;
 	nread = num_words = 0;
 	seen_underrun = num_stalls = 0;
+
 	for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
 	    cnt -= num_words) {
-		/* Read status register to find out how many words available */
-		status = bcm2835_rng_read4(sc, RNG_STATUS);
-		num_avail = (status >> RND_VAL_SHIFT) & RND_VAL_MASK;
+		/* Read count register to find out how many words available */
+		hwcount = bcm2835_rng_read4(sc, sc->conf->count_reg);
+		num_avail = (hwcount >> sc->conf->count_value_shift) &
+		    sc->conf->count_value_mask;
 
 		/* If we have none... */
 		if (num_avail == 0) {
@@ -282,15 +370,13 @@ bcm2835_rng_harvest(void *arg)
 
 		/* Pull MIN(num_avail, cnt) words from the FIFO */
 		num_words = (num_avail > cnt) ? cnt : num_avail;
-		bcm2835_rng_read_multi4(sc, RNG_DATA, dest,
+		bcm2835_rng_read_multi4(sc, sc->conf->data_reg, dest,
 		    num_words);
 		dest += num_words;
 		nread += num_words;
 	}
 
-	cnt = nread * sizeof(uint32_t);
-	if (cnt > 0)
-		random_harvest_queue(sc->sc_buf, cnt, RANDOM_PURE_BROADCOM);
+	bcm2835_rng_enqueue_harvest(sc, nread);
 
 	callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, bcm2835_rng_harvest, sc);
 }
@@ -347,7 +433,7 @@ bcm2835_rng_probe(device_t dev)
 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 		return (ENXIO);
 
-	device_set_desc(dev, "Broadcom BCM2835 RNG");
+	device_set_desc(dev, "Broadcom BCM2835/BCM2838 RNG");
 
 	return (BUS_PROBE_DEFAULT);
 }
@@ -363,13 +449,18 @@ bcm2835_rng_attach(device_t dev)
 	error = 0;
 	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
+
+	sc->conf = (void const*)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	KASSERT(sc->conf != NULL, ("bcm2835_rng_attach: sc->conf == NULL"));
+
 	sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
 
 	/* Initialize callout */
 	callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
 
-	TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
 	TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
+	if (sc->conf->allow_2x_mode)
+	    TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
 
 	/* Allocate memory resources */
 	rid = 0;
@@ -402,9 +493,10 @@ bcm2835_rng_attach(device_t dev)
 	SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
 	    "underrun", CTLFLAG_RD, &sc->sc_underrun,
 	    "Number of FIFO underruns");
-	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
-	    "2xspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
-	    sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
+	if (sc->conf->allow_2x_mode)
+		SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
+			"2xspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
+			sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
 	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
 	    "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
 	    RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
@@ -414,7 +506,7 @@ bcm2835_rng_attach(device_t dev)
 	    sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
 #endif
 
-	/* 
+	/*
 	 * Schedule the initial harvesting one second from now, which should give the
 	 * hardware RNG plenty of time to generate the first random bytes.
 	 */


More information about the dev-commits-src-all mailing list