xref: /openbsd/sys/dev/fdt/mvrng.c (revision 9fdf0c62)
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