1 /* $OpenBSD: mvrng.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/timeout.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/fdt.h> 28 29 /* Registers */ 30 #define RNG_OUTPUT0 0x0000 31 #define RNG_OUTPUT1 0x0004 32 #define RNG_OUTPUT2 0x0008 33 #define RNG_OUTPUT3 0x000c 34 #define RNG_STATUS 0x0010 35 #define RNG_STATUS_READY (1 << 0) 36 #define RNG_STATUS_SHUTDOWN (1 << 1) 37 #define RNG_CONTROL 0x0014 38 #define RNG_CONTROL_TRNG_EN (1 << 10) 39 #define RNG_CONFIG 0x0018 40 #define RNG_CONFIG_MIN_CYCLES_SHIFT 0 41 #define RNG_CONFIG_MAX_CYCLES_SHIFT 16 42 #define RNG_FROENABLE 0x0020 43 #define RNG_FROENABLE_MASK 0xffffff 44 #define RNG_FRODETUNE 0x0024 45 #define RNG_ALARMMASK 0x0028 46 #define RNG_ALARMSTOP 0x002c 47 48 #define HREAD4(sc, reg) \ 49 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 50 #define HWRITE4(sc, reg, val) \ 51 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 52 #define HSET4(sc, reg, bits) \ 53 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 54 #define HCLR4(sc, reg, bits) \ 55 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 56 57 struct mvrng_softc { 58 struct device sc_dev; 59 bus_space_tag_t sc_iot; 60 bus_space_handle_t sc_ioh; 61 62 struct timeout sc_to; 63 }; 64 65 int mvrng_match(struct device *, void *, void *); 66 void mvrng_attach(struct device *, struct device *, void *); 67 68 const struct cfattach mvrng_ca = { 69 sizeof (struct mvrng_softc), mvrng_match, mvrng_attach 70 }; 71 72 struct cfdriver mvrng_cd = { 73 NULL, "mvrng", DV_DULL 74 }; 75 76 void mvrng_rnd(void *); 77 78 int 79 mvrng_match(struct device *parent, void *match, void *aux) 80 { 81 struct fdt_attach_args *faa = aux; 82 83 return OF_is_compatible(faa->fa_node, "marvell,armada-8k-rng"); 84 } 85 86 void 87 mvrng_attach(struct device *parent, struct device *self, void *aux) 88 { 89 struct mvrng_softc *sc = (struct mvrng_softc *)self; 90 struct fdt_attach_args *faa = aux; 91 92 if (faa->fa_nreg < 1) { 93 printf(": no registers\n"); 94 return; 95 } 96 97 sc->sc_iot = faa->fa_iot; 98 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 99 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 100 printf(": can't map registers\n"); 101 return; 102 } 103 104 printf("\n"); 105 106 /* Configure and enable the RNG. */ 107 HWRITE4(sc, RNG_CONFIG, 0x5 << RNG_CONFIG_MIN_CYCLES_SHIFT | 108 0x22 << RNG_CONFIG_MAX_CYCLES_SHIFT); 109 HWRITE4(sc, RNG_FRODETUNE, 0); 110 HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK); 111 HSET4(sc, RNG_CONTROL, RNG_CONTROL_TRNG_EN); 112 113 timeout_set(&sc->sc_to, mvrng_rnd, sc); 114 mvrng_rnd(sc); 115 } 116 117 void 118 mvrng_rnd(void *arg) 119 { 120 struct mvrng_softc *sc = arg; 121 uint32_t status, detune; 122 123 status = HREAD4(sc, RNG_STATUS); 124 if (status & RNG_STATUS_SHUTDOWN) { 125 /* Clear alarms. */ 126 HWRITE4(sc, RNG_ALARMMASK, 0); 127 HWRITE4(sc, RNG_ALARMSTOP, 0); 128 129 /* Detune FROs that are shutdown. */ 130 detune = ~HREAD4(sc, RNG_FROENABLE) & RNG_FROENABLE_MASK; 131 HSET4(sc, RNG_FRODETUNE, detune); 132 133 /* Re-enable them. */ 134 HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK); 135 HWRITE4(sc, RNG_STATUS, RNG_STATUS_SHUTDOWN); 136 } 137 if (status & RNG_STATUS_READY) { 138 enqueue_randomness(HREAD4(sc, RNG_OUTPUT0)); 139 enqueue_randomness(HREAD4(sc, RNG_OUTPUT1)); 140 enqueue_randomness(HREAD4(sc, RNG_OUTPUT2)); 141 enqueue_randomness(HREAD4(sc, RNG_OUTPUT3)); 142 HWRITE4(sc, RNG_STATUS, RNG_STATUS_READY); 143 } 144 145 timeout_add_sec(&sc->sc_to, 1); 146 } 147