The branch main has been updated by gbe (doc committer):

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

commit e797dc58bd29c5bc0873fc620fc11d5332f90e7f
Author:     Gordon Bergling <g...@freebsd.org>
AuthorDate: 2021-03-06 11:28:35 +0000
Commit:     Gordon Bergling <g...@freebsd.org>
CommitDate: 2021-03-06 11:28:35 +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)
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D22493
---
 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.
         */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to