1 /* $OpenBSD: mvrng.c,v 1.2 2018/04/28 15:44:59 jasper 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/rndvar.h> 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/fdt.h> 29 30 /* Registers */ 31 #define RNG_OUTPUT0 0x0000 32 #define RNG_OUTPUT1 0x0004 33 #define RNG_OUTPUT2 0x0008 34 #define RNG_OUTPUT3 0x000c 35 #define RNG_STATUS 0x0010 36 #define RNG_STATUS_READY (1 << 0) 37 #define RNG_STATUS_SHUTDOWN (1 << 1) 38 #define RNG_CONTROL 0x0014 39 #define RNG_CONTROL_TRNG_EN (1 << 10) 40 #define RNG_CONFIG 0x0018 41 #define RNG_CONFIG_MIN_CYCLES_SHIFT 0 42 #define RNG_CONFIG_MAX_CYCLES_SHIFT 16 43 #define RNG_FROENABLE 0x0020 44 #define RNG_FROENABLE_MASK 0xffffff 45 #define RNG_FRODETUNE 0x0024 46 #define RNG_ALARMMASK 0x0028 47 #define RNG_ALARMSTOP 0x002c 48 49 #define HREAD4(sc, reg) \ 50 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 51 #define HWRITE4(sc, reg, val) \ 52 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 53 #define HSET4(sc, reg, bits) \ 54 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 55 #define HCLR4(sc, reg, bits) \ 56 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 57 58 struct mvrng_softc { 59 struct device sc_dev; 60 bus_space_tag_t sc_iot; 61 bus_space_handle_t sc_ioh; 62 63 struct timeout sc_to; 64 }; 65 66 int mvrng_match(struct device *, void *, void *); 67 void mvrng_attach(struct device *, struct device *, void *); 68 69 struct cfattach mvrng_ca = { 70 sizeof (struct mvrng_softc), mvrng_match, mvrng_attach 71 }; 72 73 struct cfdriver mvrng_cd = { 74 NULL, "mvrng", DV_DULL 75 }; 76 77 void mvrng_rnd(void *); 78 79 int 80 mvrng_match(struct device *parent, void *match, void *aux) 81 { 82 struct fdt_attach_args *faa = aux; 83 84 return OF_is_compatible(faa->fa_node, "marvell,armada-8k-rng"); 85 } 86 87 void 88 mvrng_attach(struct device *parent, struct device *self, void *aux) 89 { 90 struct mvrng_softc *sc = (struct mvrng_softc *)self; 91 struct fdt_attach_args *faa = aux; 92 93 if (faa->fa_nreg < 1) { 94 printf(": no registers\n"); 95 return; 96 } 97 98 sc->sc_iot = faa->fa_iot; 99 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 100 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 101 printf(": can't map registers\n"); 102 return; 103 } 104 105 printf("\n"); 106 107 /* Configure and enable the RNG. */ 108 HWRITE4(sc, RNG_CONFIG, 0x5 << RNG_CONFIG_MIN_CYCLES_SHIFT | 109 0x22 << RNG_CONFIG_MAX_CYCLES_SHIFT); 110 HWRITE4(sc, RNG_FRODETUNE, 0); 111 HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK); 112 HSET4(sc, RNG_CONTROL, RNG_CONTROL_TRNG_EN); 113 114 timeout_set(&sc->sc_to, mvrng_rnd, sc); 115 mvrng_rnd(sc); 116 } 117 118 void 119 mvrng_rnd(void *arg) 120 { 121 struct mvrng_softc *sc = arg; 122 uint32_t status, detune; 123 124 status = HREAD4(sc, RNG_STATUS); 125 if (status & RNG_STATUS_SHUTDOWN) { 126 /* Clear alarms. */ 127 HWRITE4(sc, RNG_ALARMMASK, 0); 128 HWRITE4(sc, RNG_ALARMSTOP, 0); 129 130 /* Detune FROs that are shutdown. */ 131 detune = ~HREAD4(sc, RNG_FROENABLE) & RNG_FROENABLE_MASK; 132 HSET4(sc, RNG_FRODETUNE, detune); 133 134 /* Re-enable them. */ 135 HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK); 136 HWRITE4(sc, RNG_STATUS, RNG_STATUS_SHUTDOWN); 137 } 138 if (status & RNG_STATUS_READY) { 139 enqueue_randomness(HREAD4(sc, RNG_OUTPUT0)); 140 enqueue_randomness(HREAD4(sc, RNG_OUTPUT1)); 141 enqueue_randomness(HREAD4(sc, RNG_OUTPUT2)); 142 enqueue_randomness(HREAD4(sc, RNG_OUTPUT3)); 143 HWRITE4(sc, RNG_STATUS, RNG_STATUS_READY); 144 } 145 146 timeout_add_sec(&sc->sc_to, 1); 147 } 148