xref: /openbsd/sys/dev/fdt/rkrng.c (revision 3ff95acd)
1 /*	$OpenBSD: rkrng.c,v 1.6 2024/02/17 13:29:25 kettenis 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
rkrng_match(struct device * parent,void * match,void * aux)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,rk3288-crypto") ||
128 	    OF_is_compatible(faa->fa_node, "rockchip,rk3328-crypto") ||
129 	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-crypto") ||
130 	    OF_is_compatible(faa->fa_node, "rockchip,cryptov2-rng");
131 }
132 
133 void
rkrng_attach(struct device * parent,struct device * self,void * aux)134 rkrng_attach(struct device *parent, struct device *self, void *aux)
135 {
136 	struct rkrng_softc *sc = (struct rkrng_softc *)self;
137 	struct fdt_attach_args *faa = aux;
138 
139 	if (OF_is_compatible(faa->fa_node, "rockchip,cryptov1-rng") ||
140 	    OF_is_compatible(faa->fa_node, "rockchip,rk3288-crypto") ||
141 	    OF_is_compatible(faa->fa_node, "rockchip,rk3328-crypto") ||
142 	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-crypto"))
143 		sc->sc_v = &rkrnv_v1;
144 	else if (OF_is_compatible(faa->fa_node, "rockchip,cryptov2-rng"))
145 		sc->sc_v = &rkrnv_v2;
146 	else {
147 		printf(": unhandled version\n");
148 		return;
149 	}
150 
151 	if (faa->fa_nreg < 1) {
152 		printf(": no registers\n");
153 		return;
154 	}
155 
156 	sc->sc_iot = faa->fa_iot;
157 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
158 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
159 		printf(": can't map registers\n");
160 		return;
161 	}
162 
163 	printf(": ver %u\n", sc->sc_v->version);
164 
165 	clock_set_assigned(faa->fa_node);
166 	clock_enable_all(faa->fa_node);
167 
168 	timeout_set(&sc->sc_to, rkrng_rnd, sc);
169 	rkrng_rnd(sc);
170 }
171 
172 void
rkrng_v1_start(struct rkrng_softc * sc)173 rkrng_v1_start(struct rkrng_softc *sc)
174 {
175 	HWRITE4(sc, RNG_TRNG_CTRL, RNG_TRNG_CTRL_OSC_ENABLE |
176 	    RNG_TRNG_CTRL_SAMPLE_PERIOD(100));
177 	HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | RNG_CTRL_START);
178 }
179 
180 int
rkrng_v1_starting(struct rkrng_softc * sc)181 rkrng_v1_starting(struct rkrng_softc *sc)
182 {
183 	return (HREAD4(sc, RNG_CTRL) & RNG_CTRL_START);
184 }
185 
186 void
rkrng_v1_stop(struct rkrng_softc * sc)187 rkrng_v1_stop(struct rkrng_softc *sc)
188 {
189 	HWRITE4(sc, RNG_CTRL, (RNG_CTRL_START << 16) | 0);
190 }
191 
192 void
rkrng_v2_start(struct rkrng_softc * sc)193 rkrng_v2_start(struct rkrng_softc *sc)
194 {
195 	uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE |
196 	    TRNG_CTL_RING_SEL_MASK | TRNG_CTL_RNG_LEN_MASK;
197 	uint32_t ctl_v = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE |
198 	    TRNG_CTL_RING_SEL_SLOW | TRNG_CTL_RNG_LEN_256BIT;
199 
200 	HWRITE4(sc, TRNG_SAMPLE_CNT, 100);
201 	HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | ctl_v);
202 }
203 
204 int
rkrng_v2_starting(struct rkrng_softc * sc)205 rkrng_v2_starting(struct rkrng_softc *sc)
206 {
207 	return (HREAD4(sc, TRNG_CTL) & TRNG_CTL_RNG_START);
208 }
209 
210 void
rkrng_v2_stop(struct rkrng_softc * sc)211 rkrng_v2_stop(struct rkrng_softc *sc)
212 {
213 	uint32_t ctl_m = TRNG_CTL_RNG_START | TRNG_CTL_RNG_ENABLE;
214 
215 	HWRITE4(sc, TRNG_CTL, (ctl_m << 16) | 0);
216 }
217 
218 void
rkrng_rnd(void * arg)219 rkrng_rnd(void *arg)
220 {
221 	struct rkrng_softc *sc = arg;
222 	bus_size_t off;
223 
224 	if (!sc->sc_started) {
225 		sc->sc_v->start(sc);
226 		sc->sc_started = 1;
227 		timeout_add_usec(&sc->sc_to, 100);
228 		return;
229 	}
230 
231 	if (sc->sc_v->starting(sc)) {
232 		timeout_add_usec(&sc->sc_to, 100);
233 		return;
234 	}
235 
236 	for (off = 0; off < 32; off += 4)
237 		enqueue_randomness(HREAD4(sc, sc->sc_v->dout + off));
238 
239 	sc->sc_v->stop(sc);
240 	sc->sc_started = 0;
241 
242 	timeout_add_sec(&sc->sc_to, 1);
243 }
244