1 /* $NetBSD: rk_v1crypto.c,v 1.12 2026/01/11 07:21:46 skrll 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.12 2026/01/11 07:21:46 skrll 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 54 struct 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 66 static int rk_v1crypto_match(device_t, cfdata_t, void *); 67 static void rk_v1crypto_attach(device_t, device_t, void *); 68 static int rk_v1crypto_selftest(struct rk_v1crypto_softc *); 69 static void rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *); 70 static void rk_v1crypto_rng_get(size_t, void *); 71 static void rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *); 72 static int rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS); 73 static int rk_v1crypto_rng(struct rk_v1crypto_softc *, 74 uint32_t[static RK_V1CRYPTO_TRNG_NOUT]); 75 76 static uint32_t 77 RKC_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 82 static void 83 RKC_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 88 static inline void 89 RKC_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 98 CFATTACH_DECL_NEW(rk_v1crypto, sizeof(struct rk_v1crypto_softc), 99 rk_v1crypto_match, rk_v1crypto_attach, NULL, NULL); 100 101 struct rk_v1crypto_data { 102 int num_clks; 103 const char *const clks[]; 104 }; 105 106 static const struct rk_v1crypto_data rk3288_crypto_data = { 107 .num_clks = 4, 108 .clks = {"aclk", "hclk", "sclk", "apb_pclk"}, 109 }; 110 111 static const struct rk_v1crypto_data rk3328_crypto_data = { 112 .num_clks = 3, 113 .clks = {"hclk_master", "hclk_slave", "sclk"}, 114 }; 115 116 static const struct device_compatible_entry compat_data[] = { 117 { .compat = "rockchip,rk3288-crypto", .data = &rk3288_crypto_data }, 118 { .compat = "rockchip,rk3328-crypto", .data = &rk3328_crypto_data }, 119 { .compat = "rockchip,rk3399-crypto", .data = &rk3328_crypto_data }, 120 DEVICE_COMPAT_EOL 121 }; 122 123 static int 124 rk_v1crypto_match(device_t parent, cfdata_t cf, void *aux) 125 { 126 const struct fdt_attach_args *const faa = aux; 127 128 return of_compatible_match(faa->faa_phandle, compat_data); 129 } 130 131 static void 132 rk_v1crypto_attach(device_t parent, device_t self, void *aux) 133 { 134 struct rk_v1crypto_softc *const sc = device_private(self); 135 const struct fdt_attach_args *const faa = aux; 136 bus_addr_t addr; 137 bus_size_t size; 138 const int phandle = faa->faa_phandle; 139 struct fdtbus_reset *rst; 140 unsigned i; 141 uint32_t ctrl; 142 const struct rk_v1crypto_data *config = 143 of_compatible_lookup(phandle, compat_data)->data; 144 const char *const *clks = config->clks; 145 146 fdtbus_clock_assign(phandle); 147 148 sc->sc_dev = self; 149 sc->sc_bst = faa->faa_bst; 150 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTSERIAL); 151 152 /* Get and map device registers. */ 153 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 154 aprint_error(": couldn't get registers\n"); 155 return; 156 } 157 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 158 aprint_error(": couldn't map registers\n"); 159 return; 160 } 161 162 /* Enable the clocks. */ 163 for (i = 0; i < config->num_clks; i++) { 164 if (fdtbus_clock_enable(phandle, clks[i], true) != 0) { 165 aprint_error(": couldn't enable %s clock\n", clks[i]); 166 return; 167 } 168 } 169 170 /* Get a reset handle if we need and try to deassert it. */ 171 if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) { 172 if (fdtbus_reset_deassert(rst) != 0) { 173 aprint_error(": couldn't de-assert reset\n"); 174 return; 175 } 176 } 177 178 aprint_naive("\n"); 179 aprint_normal(": Crypto v1\n"); 180 181 /* 182 * Enable ring oscillator to start gathering entropy, and set 183 * up the crypto clock to sample it once every 100 cycles. 184 * 185 * The ring oscillator can run even when the clock is gated or 186 * flush is asserted, and the longer we run it, the less it 187 * will be synchronized with the main clock owing to jitter 188 * ideally from unpredictable thermal noise. 189 */ 190 ctrl = RK_V1CRYPTO_TRNG_CTRL_OSC_ENABLE; 191 ctrl |= __SHIFTIN(100, RK_V1CRYPTO_TRNG_CTRL_CYCLES); 192 RKC_WRITE(sc, RK_V1CRYPTO_TRNG_CTRL, ctrl); 193 194 if (rk_v1crypto_selftest(sc)) 195 return; 196 rk_v1crypto_rndsource_attach(sc); 197 rk_v1crypto_sysctl_attach(sc); 198 } 199 200 static int 201 rk_v1crypto_selftest(struct rk_v1crypto_softc *sc) 202 { 203 static const uint32_t key[4] = {0}; 204 static const uint32_t input[4] = {0}; 205 static const uint32_t expected[4] = { 206 0x66e94bd4, 0xef8a2c3b, 0x884cfa59, 0xca342b2e, 207 }; 208 uint32_t output[4]; 209 uint32_t ctrl; 210 unsigned i, timo; 211 212 /* Program the key and input block. */ 213 for (i = 0; i < 4; i++) 214 RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), key[i]); 215 for (i = 0; i < 4; i++) 216 RKC_WRITE(sc, RK_V1CRYPTO_AES_DIN(i), input[i]); 217 218 /* 219 * Set up the AES unit to do AES-128 `ECB' (i.e., just the raw 220 * AES permutation) in the encryption direction. 221 */ 222 ctrl = 0; 223 ctrl |= RK_V1CRYPTO_AES_CTRL_KEYCHANGE; 224 ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_MODE_ECB, 225 RK_V1CRYPTO_AES_CTRL_MODE); 226 ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_KEYSIZE_128, 227 RK_V1CRYPTO_AES_CTRL_KEYSIZE); 228 ctrl |= __SHIFTIN(RK_V1CRYPTO_AES_CTRL_DIR_ENC, 229 RK_V1CRYPTO_AES_CTRL_DIR); 230 RKC_WRITE(sc, RK_V1CRYPTO_AES_CTRL, ctrl); 231 232 /* Kick it off. */ 233 RKC_CTRL(sc, RK_V1CRYPTO_CTRL_AES_START, 1); 234 235 /* Wait up to 1ms for it to complete. */ 236 timo = 1000; 237 while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_AES_START) { 238 if (--timo == 0) { 239 device_printf(sc->sc_dev, "AES self-test timed out\n"); 240 return -1; 241 } 242 DELAY(1); 243 } 244 245 /* Read the output. */ 246 for (i = 0; i < 4; i++) 247 output[i] = RKC_READ(sc, RK_V1CRYPTO_AES_DOUT(i)); 248 249 /* Verify the output. */ 250 for (i = 0; i < 4; i++) { 251 if (output[i] != expected[i]) { 252 device_printf(sc->sc_dev, "AES self-test failed\n"); 253 return -1; 254 } 255 } 256 257 /* Success! */ 258 return 0; 259 } 260 261 static void 262 rk_v1crypto_rndsource_attach(struct rk_v1crypto_softc *sc) 263 { 264 device_t self = sc->sc_dev; 265 266 rndsource_setcb(&sc->sc_rndsource, rk_v1crypto_rng_get, sc); 267 rnd_attach_source(&sc->sc_rndsource, device_xname(self), 268 RND_TYPE_RNG, RND_FLAG_DEFAULT|RND_FLAG_HASCB); 269 } 270 271 static void 272 rk_v1crypto_rng_get(size_t nbytes, void *cookie) 273 { 274 struct rk_v1crypto_softc *sc = cookie; 275 device_t self = sc->sc_dev; 276 uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; 277 uint32_t entropybits = NBBY*sizeof(buf)/2; /* be conservative */ 278 unsigned n = RK_V1CRYPTO_TRNG_NOUT; 279 int error; 280 size_t nbits = NBBY*nbytes; 281 282 while (nbits) { 283 CTASSERT((RK_V1CRYPTO_TRNG_NOUT % 2) == 0); 284 285 error = rk_v1crypto_rng(sc, buf); 286 if (error) { 287 device_printf(self, "timed out\n"); 288 break; 289 } 290 if (consttime_memequal(buf, buf + n/2, sizeof(buf[0]) * n/2)) { 291 device_printf(self, "failed repeated output test\n"); 292 break; 293 } 294 rnd_add_data_sync(&sc->sc_rndsource, buf, sizeof buf, 295 entropybits); 296 nbits -= MIN(nbits, MAX(1, entropybits)); 297 } 298 explicit_memset(buf, 0, sizeof buf); 299 } 300 301 static void 302 rk_v1crypto_sysctl_attach(struct rk_v1crypto_softc *sc) 303 { 304 device_t self = sc->sc_dev; 305 struct rk_v1crypto_sysctl *cy = &sc->sc_sysctl; 306 int error; 307 308 /* hw.rkv1cryptoN (node) */ 309 error = sysctl_createv(&cy->cy_log, 0, NULL, &cy->cy_root_node, 310 CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(self), 311 SYSCTL_DESCR("rk crypto v1 engine knobs"), 312 NULL, 0, NULL, 0, 313 CTL_HW, CTL_CREATE, CTL_EOL); 314 if (error) { 315 aprint_error_dev(self, 316 "failed to set up sysctl hw.%s: %d\n", 317 device_xname(self), error); 318 return; 319 } 320 321 /* hw.rkv1cryptoN.rng (`struct', 32-byte array) */ 322 error = sysctl_createv(&cy->cy_log, 0, &cy->cy_root_node, NULL, 323 CTLFLAG_PERMANENT|CTLFLAG_READONLY|CTLFLAG_PRIVATE, CTLTYPE_STRUCT, 324 "rng", SYSCTL_DESCR("Read up to 32 bytes out of the TRNG"), 325 &rk_v1crypto_sysctl_rng, 0, sc, 0, CTL_CREATE, CTL_EOL); 326 if (error) { 327 aprint_error_dev(self, 328 "failed to set up sysctl hw.%s.rng: %d\n", 329 device_xname(self), error); 330 return; 331 } 332 } 333 334 static int 335 rk_v1crypto_sysctl_rng(SYSCTLFN_ARGS) 336 { 337 uint32_t buf[RK_V1CRYPTO_TRNG_NOUT]; 338 struct sysctlnode node = *rnode; 339 struct rk_v1crypto_softc *sc = node.sysctl_data; 340 size_t size; 341 int error; 342 343 /* If oldp == NULL, the caller wants to learn the size. */ 344 if (oldp == NULL) { 345 *oldlenp = sizeof buf; 346 return 0; 347 } 348 349 /* Verify the output buffer size is reasonable. */ 350 size = *oldlenp; 351 if (size > sizeof buf) /* size_t, so never negative */ 352 return E2BIG; 353 if (size == 0) 354 return 0; /* nothing to do */ 355 356 /* Generate data. */ 357 error = rk_v1crypto_rng(sc, buf); 358 if (error) 359 return error; 360 361 /* Copy out the data. */ 362 node.sysctl_data = buf; 363 node.sysctl_size = size; 364 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 365 366 /* Clear the buffer. */ 367 explicit_memset(buf, 0, sizeof buf); 368 369 /* Return the sysctl_lookup error, if any. */ 370 return error; 371 } 372 373 static int 374 rk_v1crypto_rng(struct rk_v1crypto_softc *sc, 375 uint32_t buf[static RK_V1CRYPTO_TRNG_NOUT]) 376 { 377 unsigned i, timo; 378 int error; 379 380 /* Acquire lock to serialize access to TRNG. */ 381 mutex_enter(&sc->sc_lock); 382 383 /* 384 * Query TRNG and wait up to 1ms for it to post. Empirically, 385 * this takes around 120us. 386 */ 387 RKC_CTRL(sc, RK_V1CRYPTO_CTRL_TRNG_START, 1); 388 timo = 1000; 389 while (RKC_READ(sc, RK_V1CRYPTO_CTRL) & RK_V1CRYPTO_CTRL_TRNG_START) { 390 if (--timo == 0) { 391 error = ETIMEDOUT; 392 goto out; 393 } 394 DELAY(1); 395 } 396 397 /* Read out the data. */ 398 for (i = 0; i < RK_V1CRYPTO_TRNG_NOUT; i++) 399 buf[i] = RKC_READ(sc, RK_V1CRYPTO_TRNG_DOUT(i)); 400 401 /* Success! */ 402 error = 0; 403 out: mutex_exit(&sc->sc_lock); 404 return error; 405 } 406