xref: /openbsd/sys/dev/fdt/mvrng.c (revision 9fdf0c62)
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
mvrng_match(struct device * parent,void * match,void * aux)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
mvrng_attach(struct device * parent,struct device * self,void * aux)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
mvrng_rnd(void * arg)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