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