xref: /openbsd/sys/dev/fdt/rkrng.c (revision 4bdff4be)
1 /*	$OpenBSD: rkrng.c,v 1.5 2023/04/14 01:11:32 dlg 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 
64 struct rkrng_v;
65 
66 struct 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 
76 struct 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 
84 int	rkrng_match(struct device *, void *, void *);
85 void	rkrng_attach(struct device *, struct device *, void *);
86 
87 const struct cfattach rkrng_ca = {
88 	sizeof (struct rkrng_softc), rkrng_match, rkrng_attach
89 };
90 
91 struct cfdriver rkrng_cd = {
92 	NULL, "rkrng", DV_DULL
93 };
94 
95 void	rkrng_rnd(void *);
96 
97 void	rkrng_v1_start(struct rkrng_softc *);
98 int	rkrng_v1_starting(struct rkrng_softc *);
99 void	rkrng_v1_stop(struct rkrng_softc *);
100 
101 static 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 
109 void	rkrng_v2_start(struct rkrng_softc *);
110 int	rkrng_v2_starting(struct rkrng_softc *);
111 void	rkrng_v2_stop(struct rkrng_softc *);
112 
113 static 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 
121 int
122 rkrng_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,cryptov2-rng");
128 }
129 
130 void
131 rkrng_attach(struct device *parent, struct device *self, void *aux)
132 {
133 	struct rkrng_softc *sc = (struct rkrng_softc *)self;
134 	struct fdt_attach_args *faa = aux;
135 
136 	if (OF_is_compatible(faa->fa_node, "rockchip,cryptov1-rng"))
137 		sc->sc_v = &rkrnv_v1;
138 	else if (OF_is_compatible(faa->fa_node, "rockchip,cryptov2-rng"))
139 		sc->sc_v = &rkrnv_v2;
140 	else {
141 		printf(": unhandled version\n");
142 		return;
143 	}
144 
145 	if (faa->fa_nreg < 1) {
146 		printf(": no registers\n");
147 		return;
148 	}
149 
150 	sc->sc_iot = faa->fa_iot;
151 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
152 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
153 		printf(": can't map registers\n");
154 		return;
155 	}
156 
157 	printf(": ver %u\n", sc->sc_v->version);
158 
159 	clock_set_assigned(faa->fa_node);
160 	clock_enable_all(faa->fa_node);
161 
162 	timeout_set(&sc->sc_to, rkrng_rnd, sc);
163 	rkrng_rnd(sc);
164 }
165 
166 void
167 rkrng_v1_start(struct rkrng_softc *sc)
168 {
169 	HWRITE4(sc, RNG_TRNG_CTRL, RNG_TRNG_CTRL_OSC_ENABLE |
170 	    RNG_TRNG_CTRL_SAMPLE_PERIOD(100));
171 	HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | RNG_CTRL_START);
172 }
173 
174 int
175 rkrng_v1_starting(struct rkrng_softc *sc)
176 {
177 	return (HREAD4(sc, RNG_CTRL) & RNG_CTRL_START);
178 }
179 
180 void
181 rkrng_v1_stop(struct rkrng_softc *sc)
182 {
183 	HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | 0);
184 }
185 
186 void
187 rkrng_v2_start(struct rkrng_softc *sc)
188 {
189 	uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE |
190 	    TRNG_CTL_RING_SEL_MASK | TRNG_CTL_RNG_LEN_MASK;
191 	uint32_t ctl_v = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE |
192 	    TRNG_CTL_RING_SEL_SLOW | TRNG_CTL_RNG_LEN_256BIT;
193 
194 	HWRITE4(sc, TRNG_SAMPLE_CNT, 100);
195 	HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | ctl_v);
196 }
197 
198 int
199 rkrng_v2_starting(struct rkrng_softc *sc)
200 {
201 	return (HREAD4(sc, TRNG_CTL) & TRNG_CTL_RNG_START);
202 }
203 
204 void
205 rkrng_v2_stop(struct rkrng_softc *sc)
206 {
207 	uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE;
208 
209 	HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | 0);
210 }
211 
212 void
213 rkrng_rnd(void *arg)
214 {
215 	struct rkrng_softc *sc = arg;
216 	bus_size_t off;
217 
218 	if (!sc->sc_started) {
219 		sc->sc_v->start(sc);
220 		sc->sc_started = 1;
221 		timeout_add_usec(&sc->sc_to, 100);
222 		return;
223 	}
224 
225 	if (sc->sc_v->starting(sc)) {
226 		timeout_add_usec(&sc->sc_to, 100);
227 		return;
228 	}
229 
230 	for (off = 0; off < 32; off += 4)
231 		enqueue_randomness(HREAD4(sc, sc->sc_v->dout + off));
232 
233 	sc->sc_v->stop(sc);
234 	sc->sc_started = 0;
235 
236 	timeout_add_sec(&sc->sc_to, 1);
237 }
238