1/* $OpenBSD: rkrng.c,v 1.6 2024/02/17 13:29:25 kettenis Exp $ */ 2/* 3 * Copyright (c) 2020 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/ofw_clock.h> 28#include <dev/ofw/fdt.h> 29 30/* Registers */ 31 32/* V1 */ 33#define RNG_CTRL 0x0008 34#define RNG_CTRL_START (1 << 8) 35#define RNG_TRNG_CTRL 0x0200 36#define RNG_TRNG_CTRL_OSC_ENABLE (1 << 16) 37#define RNG_TRNG_CTRL_SAMPLE_PERIOD(x) (x) 38#define RNG_DATA0 0x0204 39 40/* True Random Number Generator (TRNG) */ 41#define TRNG_RST_CTL 0x0004 42#define TRNG_RST_CTL_SW_RNG_RESET (0x1U << 1) 43#define TRNG_CTL 0x0400 44#define TRNG_CTL_RNG_START (0x1U << 0) 45#define TRNG_CTL_RNG_ENABLE (0x1U << 1) 46#define TRNG_CTL_RING_SEL_MASK (0x3U << 2) 47#define TRNG_CTL_RING_SEL_SLOWEST (0x0U << 2) 48#define TRNG_CTL_RING_SEL_SLOW (0x1U << 2) 49#define TRNG_CTL_RING_SEL_FAST (0x2U << 2) 50#define TRNG_CTL_RING_SEL_FASTEST (0x3U << 2) 51#define TRNG_CTL_RNG_LEN_MASK (0x3U << 4) 52#define TRNG_CTL_RNG_LEN_64BIT (0x0U << 4) 53#define TRNG_CTL_RNG_LEN_128BIT (0x1U << 4) 54#define TRNG_CTL_RNG_LEN_192BIT (0x2U << 4) 55#define TRNG_CTL_RNG_LEN_256BIT (0x3U << 4) 56#define TRNG_SAMPLE_CNT 0x0404 57#define TRNG_DOUT_BASE 0x0410 58 59#define HREAD4(sc, reg) \ 60 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 61#define HWRITE4(sc, reg, val) \ 62 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 63 64struct rkrng_v; 65 66struct rkrng_softc { 67 struct device sc_dev; 68 const struct rkrng_v *sc_v; 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_ioh; 71 72 struct timeout sc_to; 73 int sc_started; 74}; 75 76struct rkrng_v { 77 unsigned int version; 78 void (*start)(struct rkrng_softc *sc); 79 int (*starting)(struct rkrng_softc *sc); 80 void (*stop)(struct rkrng_softc *sc); 81 bus_size_t dout; 82}; 83 84int rkrng_match(struct device *, void *, void *); 85void rkrng_attach(struct device *, struct device *, void *); 86 87const struct cfattach rkrng_ca = { 88 sizeof (struct rkrng_softc), rkrng_match, rkrng_attach 89}; 90 91struct cfdriver rkrng_cd = { 92 NULL, "rkrng", DV_DULL 93}; 94 95void rkrng_rnd(void *); 96 97void rkrng_v1_start(struct rkrng_softc *); 98int rkrng_v1_starting(struct rkrng_softc *); 99void rkrng_v1_stop(struct rkrng_softc *); 100 101static const struct rkrng_v rkrnv_v1 = { 102 .version = 1, 103 .start = rkrng_v1_start, 104 .starting = rkrng_v1_starting, 105 .stop = rkrng_v1_stop, 106 .dout = RNG_DATA0, 107}; 108 109void rkrng_v2_start(struct rkrng_softc *); 110int rkrng_v2_starting(struct rkrng_softc *); 111void rkrng_v2_stop(struct rkrng_softc *); 112 113static const struct rkrng_v rkrnv_v2 = { 114 .version = 2, 115 .start = rkrng_v2_start, 116 .starting = rkrng_v2_starting, 117 .stop = rkrng_v2_stop, 118 .dout = TRNG_DOUT_BASE, 119}; 120 121int 122rkrng_match(struct device *parent, void *match, void *aux) 123{ 124 struct fdt_attach_args *faa = aux; 125 126 return OF_is_compatible(faa->fa_node, "rockchip,cryptov1-rng") || 127 OF_is_compatible(faa->fa_node, "rockchip,rk3288-crypto") || 128 OF_is_compatible(faa->fa_node, "rockchip,rk3328-crypto") || 129 OF_is_compatible(faa->fa_node, "rockchip,rk3399-crypto") || 130 OF_is_compatible(faa->fa_node, "rockchip,cryptov2-rng"); 131} 132 133void 134rkrng_attach(struct device *parent, struct device *self, void *aux) 135{ 136 struct rkrng_softc *sc = (struct rkrng_softc *)self; 137 struct fdt_attach_args *faa = aux; 138 139 if (OF_is_compatible(faa->fa_node, "rockchip,cryptov1-rng") || 140 OF_is_compatible(faa->fa_node, "rockchip,rk3288-crypto") || 141 OF_is_compatible(faa->fa_node, "rockchip,rk3328-crypto") || 142 OF_is_compatible(faa->fa_node, "rockchip,rk3399-crypto")) 143 sc->sc_v = &rkrnv_v1; 144 else if (OF_is_compatible(faa->fa_node, "rockchip,cryptov2-rng")) 145 sc->sc_v = &rkrnv_v2; 146 else { 147 printf(": unhandled version\n"); 148 return; 149 } 150 151 if (faa->fa_nreg < 1) { 152 printf(": no registers\n"); 153 return; 154 } 155 156 sc->sc_iot = faa->fa_iot; 157 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 158 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 159 printf(": can't map registers\n"); 160 return; 161 } 162 163 printf(": ver %u\n", sc->sc_v->version); 164 165 clock_set_assigned(faa->fa_node); 166 clock_enable_all(faa->fa_node); 167 168 timeout_set(&sc->sc_to, rkrng_rnd, sc); 169 rkrng_rnd(sc); 170} 171 172void 173rkrng_v1_start(struct rkrng_softc *sc) 174{ 175 HWRITE4(sc, RNG_TRNG_CTRL, RNG_TRNG_CTRL_OSC_ENABLE | 176 RNG_TRNG_CTRL_SAMPLE_PERIOD(100)); 177 HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | RNG_CTRL_START); 178} 179 180int 181rkrng_v1_starting(struct rkrng_softc *sc) 182{ 183 return (HREAD4(sc, RNG_CTRL) & RNG_CTRL_START); 184} 185 186void 187rkrng_v1_stop(struct rkrng_softc *sc) 188{ 189 HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | 0); 190} 191 192void 193rkrng_v2_start(struct rkrng_softc *sc) 194{ 195 uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE | 196 TRNG_CTL_RING_SEL_MASK | TRNG_CTL_RNG_LEN_MASK; 197 uint32_t ctl_v = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE | 198 TRNG_CTL_RING_SEL_SLOW | TRNG_CTL_RNG_LEN_256BIT; 199 200 HWRITE4(sc, TRNG_SAMPLE_CNT, 100); 201 HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | ctl_v); 202} 203 204int 205rkrng_v2_starting(struct rkrng_softc *sc) 206{ 207 return (HREAD4(sc, TRNG_CTL) & TRNG_CTL_RNG_START); 208} 209 210void 211rkrng_v2_stop(struct rkrng_softc *sc) 212{ 213 uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE; 214 215 HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | 0); 216} 217 218void 219rkrng_rnd(void *arg) 220{ 221 struct rkrng_softc *sc = arg; 222 bus_size_t off; 223 224 if (!sc->sc_started) { 225 sc->sc_v->start(sc); 226 sc->sc_started = 1; 227 timeout_add_usec(&sc->sc_to, 100); 228 return; 229 } 230 231 if (sc->sc_v->starting(sc)) { 232 timeout_add_usec(&sc->sc_to, 100); 233 return; 234 } 235 236 for (off = 0; off < 32; off += 4) 237 enqueue_randomness(HREAD4(sc, sc->sc_v->dout + off)); 238 239 sc->sc_v->stop(sc); 240 sc->sc_started = 0; 241 242 timeout_add_sec(&sc->sc_to, 1); 243} 244