Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hwrng: rockchip - add support for RK3576's RNG

The Rockchip RK3576 SoC uses a new hardware random number generator IP.
It's also used on the Rockchip RK3562 and the Rockchip RK3528.

It has several modes of operation and self-checking features that are
not implemented here. For starters, it has a DRNG output, which is an
AES-CTR pseudo-random number generator that can be reseeded from the
true entropy regularly.

However, it also allows for access of the true entropy generator
directly. This entropy is generated from an oscillator.

There are several configuration registers which we don't touch here. The
oscillator can be switched between a "CRO" and "STR" oscillator, and the
length of the oscillator can be configured.

The hardware also supports some automatic continuous entropy quality
checking, which is also not implemented in this driver for the time
being.

The output as-is has been deemed sufficient to be useful:

rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 997
rngtest: FIPS 140-2 failures: 3
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 1
rngtest: FIPS 140-2(2001-10-10) Runs: 1
rngtest: FIPS 140-2(2001-10-10) Long run: 1
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=17.050; avg=1897.272;
max=19531250.000)Kibits/s
rngtest: FIPS tests speed: (min=44.773; avg=71.179; max=96.820)Mibits/s
rngtest: Program run time: 11760715 microseconds
rngtest: bits received from input: 40000032
rngtest: FIPS 140-2 successes: 1997
rngtest: FIPS 140-2 failures: 3
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 1
rngtest: FIPS 140-2(2001-10-10) Runs: 1
rngtest: FIPS 140-2(2001-10-10) Long run: 1
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=17.050; avg=1798.618;
max=19531250.000)Kibits/s
rngtest: FIPS tests speed: (min=44.773; avg=64.561; max=96.820)Mibits/s
rngtest: Program run time: 23507723 microseconds

Stretching the entropy can then be left up to Linux's actual entropy
pool.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Nicolas Frattaroli and committed by
Herbert Xu
8f66ccbd 165ef524

+73
+73
drivers/char/hw_random/rockchip-rng.c
··· 93 93 #define TRNG_v1_VERSION_CODE 0x46bc 94 94 /* end of TRNG_V1 register definitions */ 95 95 96 + /* 97 + * RKRNG register definitions 98 + * The RKRNG IP is a stand-alone TRNG implementation (not part of a crypto IP) 99 + * and can be found in the Rockchip RK3576, Rockchip RK3562 and Rockchip RK3528 100 + * SoCs. It can either output true randomness (TRNG) or "deterministic" 101 + * randomness derived from hashing the true entropy (DRNG). This driver 102 + * implementation uses just the true entropy, and leaves stretching the entropy 103 + * up to Linux. 104 + */ 105 + #define RKRNG_CFG 0x0000 106 + #define RKRNG_CTRL 0x0010 107 + #define RKRNG_CTRL_REQ_TRNG BIT(4) 108 + #define RKRNG_STATE 0x0014 109 + #define RKRNG_STATE_TRNG_RDY BIT(4) 110 + #define RKRNG_TRNG_DATA0 0x0050 111 + #define RKRNG_TRNG_DATA1 0x0054 112 + #define RKRNG_TRNG_DATA2 0x0058 113 + #define RKRNG_TRNG_DATA3 0x005C 114 + #define RKRNG_TRNG_DATA4 0x0060 115 + #define RKRNG_TRNG_DATA5 0x0064 116 + #define RKRNG_TRNG_DATA6 0x0068 117 + #define RKRNG_TRNG_DATA7 0x006C 118 + #define RKRNG_READ_LEN 32 119 + 96 120 /* Before removing this assert, give rk3588_rng_read an upper bound of 32 */ 97 121 static_assert(RK_RNG_MAX_BYTE <= (TRNG_V1_RAND7 + 4 - TRNG_V1_RAND0), 98 122 "You raised RK_RNG_MAX_BYTE and broke rk3588-rng, congrats."); ··· 229 205 return (ret < 0) ? ret : to_read; 230 206 } 231 207 208 + static int rk3576_rng_init(struct hwrng *rng) 209 + { 210 + struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); 211 + 212 + return rk_rng_enable_clks(rk_rng); 213 + } 214 + 215 + static int rk3576_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) 216 + { 217 + struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); 218 + size_t to_read = min_t(size_t, max, RKRNG_READ_LEN); 219 + int ret = 0; 220 + u32 val; 221 + 222 + ret = pm_runtime_resume_and_get(rk_rng->dev); 223 + if (ret < 0) 224 + return ret; 225 + 226 + rk_rng_writel(rk_rng, RKRNG_CTRL_REQ_TRNG | (RKRNG_CTRL_REQ_TRNG << 16), 227 + RKRNG_CTRL); 228 + 229 + if (readl_poll_timeout(rk_rng->base + RKRNG_STATE, val, 230 + (val & RKRNG_STATE_TRNG_RDY), RK_RNG_POLL_PERIOD_US, 231 + RK_RNG_POLL_TIMEOUT_US)) { 232 + dev_err(rk_rng->dev, "timed out waiting for data\n"); 233 + ret = -ETIMEDOUT; 234 + goto out; 235 + } 236 + 237 + rk_rng_writel(rk_rng, RKRNG_STATE_TRNG_RDY, RKRNG_STATE); 238 + 239 + memcpy_fromio(buf, rk_rng->base + RKRNG_TRNG_DATA0, to_read); 240 + 241 + out: 242 + pm_runtime_mark_last_busy(rk_rng->dev); 243 + pm_runtime_put_sync_autosuspend(rk_rng->dev); 244 + 245 + return (ret < 0) ? ret : to_read; 246 + } 247 + 232 248 static int rk3588_rng_init(struct hwrng *rng) 233 249 { 234 250 struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng); ··· 369 305 .reset_optional = false, 370 306 }; 371 307 308 + static const struct rk_rng_soc_data rk3576_soc_data = { 309 + .rk_rng_init = rk3576_rng_init, 310 + .rk_rng_read = rk3576_rng_read, 311 + .rk_rng_cleanup = rk3588_rng_cleanup, 312 + .quality = 999, /* as determined by actual testing */ 313 + .reset_optional = true, 314 + }; 315 + 372 316 static const struct rk_rng_soc_data rk3588_soc_data = { 373 317 .rk_rng_init = rk3588_rng_init, 374 318 .rk_rng_read = rk3588_rng_read, ··· 469 397 470 398 static const struct of_device_id rk_rng_dt_match[] = { 471 399 { .compatible = "rockchip,rk3568-rng", .data = (void *)&rk3568_soc_data }, 400 + { .compatible = "rockchip,rk3576-rng", .data = (void *)&rk3576_soc_data }, 472 401 { .compatible = "rockchip,rk3588-rng", .data = (void *)&rk3588_soc_data }, 473 402 { /* sentinel */ }, 474 403 };