1*9fdf0c62Smpi /* $OpenBSD: mvrng.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */
28f257a12Skettenis /*
38f257a12Skettenis * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
48f257a12Skettenis *
58f257a12Skettenis * Permission to use, copy, modify, and distribute this software for any
68f257a12Skettenis * purpose with or without fee is hereby granted, provided that the above
78f257a12Skettenis * copyright notice and this permission notice appear in all copies.
88f257a12Skettenis *
98f257a12Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108f257a12Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118f257a12Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128f257a12Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138f257a12Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148f257a12Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158f257a12Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168f257a12Skettenis */
178f257a12Skettenis
188f257a12Skettenis #include <sys/param.h>
198f257a12Skettenis #include <sys/systm.h>
208f257a12Skettenis #include <sys/device.h>
218f257a12Skettenis #include <sys/timeout.h>
228f257a12Skettenis
238f257a12Skettenis #include <machine/bus.h>
248f257a12Skettenis #include <machine/fdt.h>
258f257a12Skettenis
268f257a12Skettenis #include <dev/ofw/openfirm.h>
278f257a12Skettenis #include <dev/ofw/fdt.h>
288f257a12Skettenis
298f257a12Skettenis /* Registers */
308f257a12Skettenis #define RNG_OUTPUT0 0x0000
318f257a12Skettenis #define RNG_OUTPUT1 0x0004
328f257a12Skettenis #define RNG_OUTPUT2 0x0008
338f257a12Skettenis #define RNG_OUTPUT3 0x000c
348f257a12Skettenis #define RNG_STATUS 0x0010
358f257a12Skettenis #define RNG_STATUS_READY (1 << 0)
368f257a12Skettenis #define RNG_STATUS_SHUTDOWN (1 << 1)
378f257a12Skettenis #define RNG_CONTROL 0x0014
388f257a12Skettenis #define RNG_CONTROL_TRNG_EN (1 << 10)
398f257a12Skettenis #define RNG_CONFIG 0x0018
408f257a12Skettenis #define RNG_CONFIG_MIN_CYCLES_SHIFT 0
418f257a12Skettenis #define RNG_CONFIG_MAX_CYCLES_SHIFT 16
428f257a12Skettenis #define RNG_FROENABLE 0x0020
438f257a12Skettenis #define RNG_FROENABLE_MASK 0xffffff
448f257a12Skettenis #define RNG_FRODETUNE 0x0024
458f257a12Skettenis #define RNG_ALARMMASK 0x0028
468f257a12Skettenis #define RNG_ALARMSTOP 0x002c
478f257a12Skettenis
488f257a12Skettenis #define HREAD4(sc, reg) \
498f257a12Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
508f257a12Skettenis #define HWRITE4(sc, reg, val) \
518f257a12Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
528f257a12Skettenis #define HSET4(sc, reg, bits) \
538f257a12Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
548f257a12Skettenis #define HCLR4(sc, reg, bits) \
558f257a12Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
568f257a12Skettenis
578f257a12Skettenis struct mvrng_softc {
588f257a12Skettenis struct device sc_dev;
598f257a12Skettenis bus_space_tag_t sc_iot;
608f257a12Skettenis bus_space_handle_t sc_ioh;
618f257a12Skettenis
628f257a12Skettenis struct timeout sc_to;
638f257a12Skettenis };
648f257a12Skettenis
658f257a12Skettenis int mvrng_match(struct device *, void *, void *);
668f257a12Skettenis void mvrng_attach(struct device *, struct device *, void *);
678f257a12Skettenis
68*9fdf0c62Smpi const struct cfattach mvrng_ca = {
698f257a12Skettenis sizeof (struct mvrng_softc), mvrng_match, mvrng_attach
708f257a12Skettenis };
718f257a12Skettenis
728f257a12Skettenis struct cfdriver mvrng_cd = {
738f257a12Skettenis NULL, "mvrng", DV_DULL
748f257a12Skettenis };
758f257a12Skettenis
768f257a12Skettenis void mvrng_rnd(void *);
778f257a12Skettenis
788f257a12Skettenis int
mvrng_match(struct device * parent,void * match,void * aux)798f257a12Skettenis mvrng_match(struct device *parent, void *match, void *aux)
808f257a12Skettenis {
818f257a12Skettenis struct fdt_attach_args *faa = aux;
828f257a12Skettenis
838f257a12Skettenis return OF_is_compatible(faa->fa_node, "marvell,armada-8k-rng");
848f257a12Skettenis }
858f257a12Skettenis
868f257a12Skettenis void
mvrng_attach(struct device * parent,struct device * self,void * aux)878f257a12Skettenis mvrng_attach(struct device *parent, struct device *self, void *aux)
888f257a12Skettenis {
898f257a12Skettenis struct mvrng_softc *sc = (struct mvrng_softc *)self;
908f257a12Skettenis struct fdt_attach_args *faa = aux;
918f257a12Skettenis
928f257a12Skettenis if (faa->fa_nreg < 1) {
938f257a12Skettenis printf(": no registers\n");
948f257a12Skettenis return;
958f257a12Skettenis }
968f257a12Skettenis
978f257a12Skettenis sc->sc_iot = faa->fa_iot;
988f257a12Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
998f257a12Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1008f257a12Skettenis printf(": can't map registers\n");
1018f257a12Skettenis return;
1028f257a12Skettenis }
1038f257a12Skettenis
1048f257a12Skettenis printf("\n");
1058f257a12Skettenis
1068f257a12Skettenis /* Configure and enable the RNG. */
1078f257a12Skettenis HWRITE4(sc, RNG_CONFIG, 0x5 << RNG_CONFIG_MIN_CYCLES_SHIFT |
1088f257a12Skettenis 0x22 << RNG_CONFIG_MAX_CYCLES_SHIFT);
1098f257a12Skettenis HWRITE4(sc, RNG_FRODETUNE, 0);
1108f257a12Skettenis HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK);
1118f257a12Skettenis HSET4(sc, RNG_CONTROL, RNG_CONTROL_TRNG_EN);
1128f257a12Skettenis
1138f257a12Skettenis timeout_set(&sc->sc_to, mvrng_rnd, sc);
1148f257a12Skettenis mvrng_rnd(sc);
1158f257a12Skettenis }
1168f257a12Skettenis
1178f257a12Skettenis void
mvrng_rnd(void * arg)1188f257a12Skettenis mvrng_rnd(void *arg)
1198f257a12Skettenis {
1208f257a12Skettenis struct mvrng_softc *sc = arg;
1218f257a12Skettenis uint32_t status, detune;
1228f257a12Skettenis
1238f257a12Skettenis status = HREAD4(sc, RNG_STATUS);
1248f257a12Skettenis if (status & RNG_STATUS_SHUTDOWN) {
1258f257a12Skettenis /* Clear alarms. */
1268f257a12Skettenis HWRITE4(sc, RNG_ALARMMASK, 0);
1278f257a12Skettenis HWRITE4(sc, RNG_ALARMSTOP, 0);
1288f257a12Skettenis
1298f257a12Skettenis /* Detune FROs that are shutdown. */
1308f257a12Skettenis detune = ~HREAD4(sc, RNG_FROENABLE) & RNG_FROENABLE_MASK;
1318f257a12Skettenis HSET4(sc, RNG_FRODETUNE, detune);
1328f257a12Skettenis
1338f257a12Skettenis /* Re-enable them. */
1348f257a12Skettenis HWRITE4(sc, RNG_FROENABLE, RNG_FROENABLE_MASK);
1358f257a12Skettenis HWRITE4(sc, RNG_STATUS, RNG_STATUS_SHUTDOWN);
1368f257a12Skettenis }
1378f257a12Skettenis if (status & RNG_STATUS_READY) {
1389e9abf5bSjasper enqueue_randomness(HREAD4(sc, RNG_OUTPUT0));
1399e9abf5bSjasper enqueue_randomness(HREAD4(sc, RNG_OUTPUT1));
1409e9abf5bSjasper enqueue_randomness(HREAD4(sc, RNG_OUTPUT2));
1419e9abf5bSjasper enqueue_randomness(HREAD4(sc, RNG_OUTPUT3));
1428f257a12Skettenis HWRITE4(sc, RNG_STATUS, RNG_STATUS_READY);
1438f257a12Skettenis }
1448f257a12Skettenis
1458f257a12Skettenis timeout_add_sec(&sc->sc_to, 1);
1468f257a12Skettenis }
147