rk_v1crypto.c revision 1.4
1/*	$NetBSD: rk_v1crypto.c,v 1.4 2021/01/18 02:35:49 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * rk_v1crypto -- Rockchip crypto v1 driver
34 *
35 * This is just the RNG for now.
36 */
37
38#include <sys/cdefs.h>
39__KERNEL_RCSID(1, "$NetBSD: rk_v1crypto.c,v 1.4 2021/01/18 02:35:49 thorpej Exp $");
40
41#include <sys/types.h>
42
43#include <sys/bus.h>
44#include <sys/device.h>
45#include <sys/errno.h>
46#include <sys/mutex.h>
47#include <sys/rndsource.h>
48#include <sys/sysctl.h>
49
50#include <dev/fdt/fdtvar.h>
51
52#include <arm/rockchip/rk_v1crypto.h>
53
54struct rk_v1crypto_softc {
55	device_t			sc_dev;
56	bus_space_tag_t			sc_bst;
57	bus_space_handle_t		sc_bsh;
58	kmutex_t			sc_lock;
59	struct krndsource		sc_rndsource;
60	struct rk_v1crypto_sysctl {
61		struct sysctllog		*cy_log;
62		const struct sysctlnode		*cy_root_node;
63	}				sc_sysctl;
64};
65
66static int rk_v1crypto_match(device_t, cfdata_t, void *);
67static void rk_v1crypto_attach(device_t, device_t, void *);
68static int rk_v1crypto_selftest(struct rk_v1crypto_softc *);
69static void rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *);
70static void rk_v1crypto_rng_get(size_t, void *);
71static void rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *);
72static int rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS);
73static int rk_v1crypto_rng(struct rk_v1crypto_softc *,
74    uint32_t[static RK_V1CRYPTO_TRNG_NOUT]);
75
76static uint32_t
77RKC_READ(struct rk_v1crypto_softc *sc, bus_addr_t reg)
78{
79	return bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg);
80}
81
82static void
83RKC_WRITE(struct rk_v1crypto_softc *sc, bus_addr_t reg, uint32_t v)
84{
85	bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, v);
86}
87
88static inline void
89RKC_CTRL(struct rk_v1crypto_softc *sc, uint16_t m, uint16_t v)
90{
91	uint32_t c = 0;
92
93	c |= __SHIFTIN(m, RK_V1CRYPTO_CTRL_MASK);
94	c |= __SHIFTIN(v, m);
95	RKC_WRITE(sc, RK_V1CRYPTO_CTRL, c);
96}
97
98CFATTACH_DECL_NEW(rk_v1crypto, sizeof(struct rk_v1crypto_softc),
99    rk_v1crypto_match, rk_v1crypto_attach, NULL, NULL);
100
101static const struct device_compatible_entry compat_data[] = {
102	{ .compat = "rockchip,rk3288-crypto" },
103
104	{ 0 }
105};
106
107static int
108rk_v1crypto_match(device_t parent, cfdata_t cf, void *aux)
109{
110	const struct fdt_attach_args *const faa = aux;
111
112	return of_match_compat_data(faa->faa_phandle, compat_data);
113}
114
115static void
116rk_v1crypto_attach(device_t parent, device_t self, void *aux)
117{
118	static const char *const clks[] = {"aclk", "hclk", "sclk", "apb_pclk"};
119	struct rk_v1crypto_softc *const sc = device_private(self);
120	const struct fdt_attach_args *const faa = aux;
121	bus_addr_t addr;
122	bus_size_t size;
123	const int phandle = faa->faa_phandle;
124	struct fdtbus_reset *rst;
125	unsigned i;
126	uint32_t ctrl;
127
128	fdtbus_clock_assign(phandle);
129
130	sc->sc_dev = self;
131	sc->sc_bst = faa->faa_bst;
132	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
133
134	/* Get and map device registers.  */
135	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
136		aprint_error(": couldn't get registers\n");
137		return;
138	}
139	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
140		aprint_error(": couldn't map registers\n");
141		return;
142	}
143
144	/* Enable the clocks.  */
145	for (i = 0; i < __arraycount(clks); i++) {
146		if (fdtbus_clock_enable(phandle, clks[i], true) != 0) {
147			aprint_error(": couldn't enable %s clock\n", clks[i]);
148			return;
149		}
150	}
151
152	/* Get a reset handle if we need and try to deassert it.  */
153	if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) {
154		if (fdtbus_reset_deassert(rst) != 0) {
155			aprint_error(": couldn't de-assert reset\n");
156			return;
157		}
158	}
159
160	aprint_naive("\n");
161	aprint_normal(": Crypto v1\n");
162
163	/*
164	 * Enable ring oscillator to start gathering entropy, and set
165	 * up the crypto clock to sample it once every 100 cycles.
166	 *
167	 * The ring oscillator can run even when the clock is gated or
168	 * flush is asserted, and the longer we run it, the less it
169	 * will be synchronized with the main clock owing to jitter
170	 * ideally from unpredictable thermal noise.
171	 */
172	ctrl = RK_V1CRYPTO_TRNG_CTRL_OSC_ENABLE;
173	ctrl |= __SHIFTIN(100, RK_V1CRYPTO_TRNG_CTRL_CYCLES);
174	RKC_WRITE(sc, RK_V1CRYPTO_TRNG_CTRL, ctrl);
175
176	if (rk_v1crypto_selftest(sc))
177		return;
178	rk_v1crypto_rndsource_attach(sc);
179	rk_v1crypto_sysctl_attach(sc);
180}
181
182static int
183rk_v1crypto_selftest(struct rk_v1crypto_softc *sc)
184{
185	static const uint32_t key[4] = {0};
186	static const uint32_t input[4] = {0};
187	static const uint32_t expected[4] = {
188		0x66e94bd4, 0xef8a2c3b, 0x884cfa59, 0xca342b2e,
189	};
190	uint32_t output[4];
191	uint32_t ctrl;
192	unsigned i, timo;
193
194	/* Program the key and input block.  */
195	for (i = 0; i < 4; i++)
196		RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), key[i]);
197	for (i = 0; i < 4; i++)
198		RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), input[i]);
199
200	/*
201	 * Set up the AES unit to do AES-128 `ECB' (i.e., just the raw
202	 * AES permutation) in the encryption direction.
203	 */
204	ctrl = 0;
205	ctrl |= RK_V1CRYPTO_AES_CTRL_KEYCHANGE;
206	ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_MODE_ECB,
207	    RK_V1CRYPTO_AES_CTRL_MODE);
208	ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_KEYSIZE_128,
209	    RK_V1CRYPTO_AES_CTRL_KEYSIZE);
210	ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_DIR_ENC,
211	    RK_V1CRYPTO_AES_CTRL_DIR);
212	RKC_WRITE(sc, RK_V1CRYPTO_AES_CTRL, ctrl);
213
214	/* Kick it off.  */
215	RKC_CTRL(sc, RK_V1CRYPTO_CTRL_AES_START, 1);
216
217	/* Wait up to 1ms for it to complete.  */
218	timo = 1000;
219	while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_AES_START) {
220		if (--timo == 0) {
221			device_printf(sc->sc_dev, "AES self-test timed out\n");
222			return -1;
223		}
224		DELAY(1);
225	}
226
227	/* Read the output.  */
228	for (i = 0; i < 4; i++)
229		output[i] = RKC_READ(sc, RK_V1CRYPTO_AES_DOUT(i));
230
231	/* Verify the output.  */
232	for (i = 0; i < 4; i++) {
233		if (output[i] != expected[i]) {
234			device_printf(sc->sc_dev, "AES self-test failed\n");
235			return -1;
236		}
237	}
238
239	/* Success!  */
240	return 0;
241}
242
243static void
244rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *sc)
245{
246	device_t self = sc->sc_dev;
247
248	rndsource_setcb(&sc->sc_rndsource, rk_v1crypto_rng_get, sc);
249	rnd_attach_source(&sc->sc_rndsource, device_xname(self),
250	    RND_TYPE_RNG, RND_FLAG_DEFAULT|RND_FLAG_HASCB);
251}
252
253static void
254rk_v1crypto_rng_get(size_t nbytes, void *cookie)
255{
256	struct rk_v1crypto_softc *sc = cookie;
257	device_t self = sc->sc_dev;
258	uint32_t buf[RK_V1CRYPTO_TRNG_NOUT];
259	uint32_t entropybits = NBBY*sizeof(buf)/2; /* be conservative */
260	unsigned n = RK_V1CRYPTO_TRNG_NOUT;
261	int error;
262	size_t nbits = NBBY*nbytes;
263
264	while (nbits) {
265		CTASSERT((RK_V1CRYPTO_TRNG_NOUT % 2) == 0);
266
267		error = rk_v1crypto_rng(sc, buf);
268		if (error) {
269			device_printf(self, "timed out\n");
270			break;
271		}
272		if (consttime_memequal(buf, buf + n/2, n/2)) {
273			device_printf(self, "failed repeated output test\n");
274			break;
275		}
276		rnd_add_data_sync(&sc->sc_rndsource, buf, sizeof buf,
277		    entropybits);
278		nbits -= MIN(nbits, MAX(1, entropybits));
279	}
280	explicit_memset(buf, 0, sizeof buf);
281}
282
283static void
284rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *sc)
285{
286	device_t self = sc->sc_dev;
287	struct rk_v1crypto_sysctl *cy = &sc->sc_sysctl;
288	int error;
289
290	/* hw.rkv1cryptoN (node) */
291	error = sysctl_createv(&cy->cy_log, 0, NULL, &cy->cy_root_node,
292	    CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(self),
293	    SYSCTL_DESCR("rk crypto v1 engine knobs"),
294	    NULL, 0, NULL, 0,
295	    CTL_HW, CTL_CREATE, CTL_EOL);
296	if (error) {
297		aprint_error_dev(self,
298		    "failed to set up sysctl hw.%s: %d\n",
299		    device_xname(self), error);
300		return;
301	}
302
303	/* hw.rkv1cryptoN.rng (`struct', 32-byte array) */
304	sysctl_createv(&cy->cy_log, 0, &cy->cy_root_node, NULL,
305	    CTLFLAG_PERMANENT|CTLFLAG_READONLY|CTLFLAG_PRIVATE, CTLTYPE_STRUCT,
306	    "rng", SYSCTL_DESCR("Read up to 32 bytes out of the TRNG"),
307	    &rk_v1crypto_sysctl_rng, 0, sc, 0, CTL_CREATE, CTL_EOL);
308	if (error) {
309		aprint_error_dev(self,
310		    "failed to set up sysctl hw.%s.rng: %d\n",
311		    device_xname(self), error);
312		return;
313	}
314}
315
316static int
317rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS)
318{
319	uint32_t buf[RK_V1CRYPTO_TRNG_NOUT];
320	struct sysctlnode node = *rnode;
321	struct rk_v1crypto_softc *sc = node.sysctl_data;
322	size_t size;
323	int error;
324
325	/* If oldp == NULL, the caller wants to learn the size.  */
326	if (oldp == NULL) {
327		*oldlenp = sizeof buf;
328		return 0;
329	}
330
331	/* Verify the output buffer size is reasonable.  */
332	size = *oldlenp;
333	if (size > sizeof buf)	/* size_t, so never negative */
334		return E2BIG;
335	if (size == 0)
336		return 0;	/* nothing to do */
337
338	/* Generate data.  */
339	error = rk_v1crypto_rng(sc, buf);
340	if (error)
341		return error;
342
343	/* Copy out the data.  */
344	node.sysctl_data = buf;
345	node.sysctl_size = size;
346	error = sysctl_lookup(SYSCTLFN_CALL(&node));
347
348	/* Clear the buffer.  */
349	explicit_memset(buf, 0, sizeof buf);
350
351	/* Return the sysctl_lookup error, if any.  */
352	return error;
353}
354
355static int
356rk_v1crypto_rng(struct rk_v1crypto_softc *sc,
357    uint32_t buf[static RK_V1CRYPTO_TRNG_NOUT])
358{
359	unsigned i, timo;
360	int error;
361
362	/* Acquire lock to serialize access to TRNG.  */
363	mutex_enter(&sc->sc_lock);
364
365	/*
366	 * Query TRNG and wait up to 1ms for it to post.  Empirically,
367	 * this takes around 120us.
368	 */
369	RKC_CTRL(sc, RK_V1CRYPTO_CTRL_TRNG_START, 1);
370	timo = 1000;
371	while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_TRNG_START) {
372		if (--timo == 0) {
373			error = ETIMEDOUT;
374			goto out;
375		}
376		DELAY(1);
377	}
378
379	/* Read out the data.  */
380	for (i = 0; i < RK_V1CRYPTO_TRNG_NOUT; i++)
381		buf[i] = RKC_READ(sc, RK_V1CRYPTO_TRNG_DOUT(i));
382
383	/* Success!  */
384	error = 0;
385out:	mutex_exit(&sc->sc_lock);
386	return error;
387}
388