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.

crypto: xilinx - Add TRNG driver for Versal

Add True Random Number Generator(TRNG) driver for Versal
platform.

Co-developed-by: Mounika Botcha <mounika.botcha@amd.com>
Signed-off-by: Mounika Botcha <mounika.botcha@amd.com>
Signed-off-by: Harsh Jain <h.jain@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Harsh Jain and committed by
Herbert Xu
8979744a 9de9040f

+424
+6
MAINTAINERS
··· 27609 27609 F: drivers/misc/xilinx_sdfec.c 27610 27610 F: include/uapi/misc/xilinx_sdfec.h 27611 27611 27612 + XILINX TRNG DRIVER 27613 + M: Mounika Botcha <mounika.botcha@amd.com> 27614 + M: Harsh Jain <h.jain@amd.com> 27615 + S: Maintained 27616 + F: drivers/crypto/xilinx/xilinx-trng.c 27617 + 27612 27618 XILINX UARTLITE SERIAL DRIVER 27613 27619 M: Peter Korsgaard <jacmet@sunsite.dk> 27614 27620 L: linux-serial@vger.kernel.org
+12
drivers/crypto/Kconfig
··· 725 725 Select this to enable Tegra Security Engine which accelerates various 726 726 AES encryption/decryption and HASH algorithms. 727 727 728 + config CRYPTO_DEV_XILINX_TRNG 729 + tristate "Support for Xilinx True Random Generator" 730 + depends on ZYNQMP_FIRMWARE || COMPILE_TEST 731 + select CRYPTO_RNG 732 + select HW_RANDOM 733 + help 734 + Xilinx Versal SoC driver provides kernel-side support for True Random Number 735 + Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A. 736 + 737 + To compile this driver as a module, choose M here: the module 738 + will be called xilinx-trng. 739 + 728 740 config CRYPTO_DEV_ZYNQMP_AES 729 741 tristate "Support for Xilinx ZynqMP AES hw accelerator" 730 742 depends on ZYNQMP_FIRMWARE || COMPILE_TEST
+1
drivers/crypto/xilinx/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_CRYPTO_DEV_XILINX_TRNG) += xilinx-trng.o 2 3 obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o 3 4 obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o
+405
drivers/crypto/xilinx/xilinx-trng.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD Versal True Random Number Generator driver 4 + * Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc. 5 + */ 6 + 7 + #include <linux/bitfield.h> 8 + #include <linux/clk.h> 9 + #include <linux/crypto.h> 10 + #include <linux/delay.h> 11 + #include <linux/errno.h> 12 + #include <linux/firmware/xlnx-zynqmp.h> 13 + #include <linux/hw_random.h> 14 + #include <linux/io.h> 15 + #include <linux/iopoll.h> 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/mutex.h> 19 + #include <linux/mod_devicetable.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/string.h> 22 + #include <crypto/internal/cipher.h> 23 + #include <crypto/internal/rng.h> 24 + #include <crypto/aes.h> 25 + 26 + /* TRNG Registers Offsets */ 27 + #define TRNG_STATUS_OFFSET 0x4U 28 + #define TRNG_CTRL_OFFSET 0x8U 29 + #define TRNG_EXT_SEED_OFFSET 0x40U 30 + #define TRNG_PER_STRNG_OFFSET 0x80U 31 + #define TRNG_CORE_OUTPUT_OFFSET 0xC0U 32 + #define TRNG_RESET_OFFSET 0xD0U 33 + #define TRNG_OSC_EN_OFFSET 0xD4U 34 + 35 + /* Mask values */ 36 + #define TRNG_RESET_VAL_MASK BIT(0) 37 + #define TRNG_OSC_EN_VAL_MASK BIT(0) 38 + #define TRNG_CTRL_PRNGSRST_MASK BIT(0) 39 + #define TRNG_CTRL_EUMODE_MASK BIT(8) 40 + #define TRNG_CTRL_TRSSEN_MASK BIT(2) 41 + #define TRNG_CTRL_PRNGSTART_MASK BIT(5) 42 + #define TRNG_CTRL_PRNGXS_MASK BIT(3) 43 + #define TRNG_CTRL_PRNGMODE_MASK BIT(7) 44 + #define TRNG_STATUS_DONE_MASK BIT(0) 45 + #define TRNG_STATUS_QCNT_MASK GENMASK(11, 9) 46 + #define TRNG_STATUS_QCNT_16_BYTES 0x800 47 + 48 + /* Sizes in bytes */ 49 + #define TRNG_SEED_LEN_BYTES 48U 50 + #define TRNG_ENTROPY_SEED_LEN_BYTES 64U 51 + #define TRNG_SEC_STRENGTH_SHIFT 5U 52 + #define TRNG_SEC_STRENGTH_BYTES BIT(TRNG_SEC_STRENGTH_SHIFT) 53 + #define TRNG_BYTES_PER_REG 4U 54 + #define TRNG_RESET_DELAY 10 55 + #define TRNG_NUM_INIT_REGS 12U 56 + #define TRNG_READ_4_WORD 4 57 + #define TRNG_DATA_READ_DELAY 8000 58 + 59 + struct xilinx_rng { 60 + void __iomem *rng_base; 61 + struct device *dev; 62 + struct mutex lock; /* Protect access to TRNG device */ 63 + struct hwrng trng; 64 + }; 65 + 66 + struct xilinx_rng_ctx { 67 + struct xilinx_rng *rng; 68 + }; 69 + 70 + static struct xilinx_rng *xilinx_rng_dev; 71 + 72 + static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value) 73 + { 74 + u32 val; 75 + 76 + val = ioread32(addr); 77 + val = (val & (~mask)) | (mask & value); 78 + iowrite32(val, addr); 79 + } 80 + 81 + static void xtrng_trng_reset(void __iomem *addr) 82 + { 83 + xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, TRNG_RESET_VAL_MASK); 84 + udelay(TRNG_RESET_DELAY); 85 + xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, 0); 86 + } 87 + 88 + static void xtrng_hold_reset(void __iomem *addr) 89 + { 90 + xtrng_readwrite32(addr + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 91 + TRNG_CTRL_PRNGSRST_MASK); 92 + iowrite32(TRNG_RESET_VAL_MASK, addr + TRNG_RESET_OFFSET); 93 + udelay(TRNG_RESET_DELAY); 94 + } 95 + 96 + static void xtrng_softreset(struct xilinx_rng *rng) 97 + { 98 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 99 + TRNG_CTRL_PRNGSRST_MASK); 100 + udelay(TRNG_RESET_DELAY); 101 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 0); 102 + } 103 + 104 + /* Return no. of bytes read */ 105 + static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait) 106 + { 107 + int read = 0, ret; 108 + int timeout = 1; 109 + int i, idx; 110 + u32 val; 111 + 112 + if (wait) 113 + timeout = TRNG_DATA_READ_DELAY; 114 + 115 + for (i = 0; i < (blocks32 * 2); i++) { 116 + /* TRNG core generate data in 16 bytes. Read twice to complete 32 bytes read */ 117 + ret = readl_poll_timeout(rng_base + TRNG_STATUS_OFFSET, val, 118 + (val & TRNG_STATUS_QCNT_MASK) == 119 + TRNG_STATUS_QCNT_16_BYTES, !!wait, timeout); 120 + if (ret) 121 + break; 122 + 123 + for (idx = 0; idx < TRNG_READ_4_WORD; idx++) { 124 + *(buf + read) = cpu_to_be32(ioread32(rng_base + TRNG_CORE_OUTPUT_OFFSET)); 125 + read += 1; 126 + } 127 + } 128 + return read * 4; 129 + } 130 + 131 + static int xtrng_collect_random_data(struct xilinx_rng *rng, u8 *rand_gen_buf, 132 + int no_of_random_bytes, bool wait) 133 + { 134 + u8 randbuf[TRNG_SEC_STRENGTH_BYTES]; 135 + int byteleft, blocks, count = 0; 136 + int ret; 137 + 138 + byteleft = no_of_random_bytes & (TRNG_SEC_STRENGTH_BYTES - 1); 139 + blocks = no_of_random_bytes >> TRNG_SEC_STRENGTH_SHIFT; 140 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, 141 + TRNG_CTRL_PRNGSTART_MASK); 142 + if (blocks) { 143 + ret = xtrng_readblock32(rng->rng_base, (__be32 *)rand_gen_buf, blocks, wait); 144 + if (!ret) 145 + return 0; 146 + count += ret; 147 + } 148 + 149 + if (byteleft) { 150 + ret = xtrng_readblock32(rng->rng_base, (__be32 *)randbuf, 1, wait); 151 + if (!ret) 152 + return count; 153 + memcpy(rand_gen_buf + (blocks * TRNG_SEC_STRENGTH_BYTES), randbuf, byteleft); 154 + count += byteleft; 155 + } 156 + 157 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, 158 + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGSTART_MASK, 0U); 159 + 160 + return count; 161 + } 162 + 163 + static void xtrng_write_multiple_registers(void __iomem *base_addr, u32 *values, size_t n) 164 + { 165 + void __iomem *reg_addr; 166 + size_t i; 167 + 168 + /* Write seed value into EXTERNAL_SEED Registers in big endian format */ 169 + for (i = 0; i < n; i++) { 170 + reg_addr = (base_addr + ((n - 1 - i) * TRNG_BYTES_PER_REG)); 171 + iowrite32((u32 __force)(cpu_to_be32(values[i])), reg_addr); 172 + } 173 + } 174 + 175 + static void xtrng_enable_entropy(struct xilinx_rng *rng) 176 + { 177 + iowrite32(TRNG_OSC_EN_VAL_MASK, rng->rng_base + TRNG_OSC_EN_OFFSET); 178 + xtrng_softreset(rng); 179 + iowrite32(TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK, rng->rng_base + TRNG_CTRL_OFFSET); 180 + } 181 + 182 + static int xtrng_reseed_internal(struct xilinx_rng *rng) 183 + { 184 + u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES]; 185 + u32 val; 186 + int ret; 187 + 188 + memset(entropy, 0, sizeof(entropy)); 189 + xtrng_enable_entropy(rng); 190 + 191 + /* collect random data to use it as entropy (input for DF) */ 192 + ret = xtrng_collect_random_data(rng, entropy, TRNG_SEED_LEN_BYTES, true); 193 + if (ret != TRNG_SEED_LEN_BYTES) 194 + return -EINVAL; 195 + 196 + xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, 197 + (u32 *)entropy, TRNG_NUM_INIT_REGS); 198 + /* select reseed operation */ 199 + iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET); 200 + 201 + /* Start the reseed operation with above configuration and wait for STATUS.Done bit to be 202 + * set. Monitor STATUS.CERTF bit, if set indicates SP800-90B entropy health test has failed. 203 + */ 204 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, 205 + TRNG_CTRL_PRNGSTART_MASK); 206 + 207 + ret = readl_poll_timeout(rng->rng_base + TRNG_STATUS_OFFSET, val, 208 + (val & TRNG_STATUS_DONE_MASK) == TRNG_STATUS_DONE_MASK, 209 + 1U, 15000U); 210 + if (ret) 211 + return ret; 212 + 213 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, 0U); 214 + 215 + return 0; 216 + } 217 + 218 + static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr, 219 + u32 rand_buf_size, int wait) 220 + { 221 + int nbytes; 222 + int ret; 223 + 224 + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, 225 + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK, 226 + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK); 227 + nbytes = xtrng_collect_random_data(rng, rand_buf_ptr, rand_buf_size, wait); 228 + 229 + ret = xtrng_reseed_internal(rng); 230 + if (ret) { 231 + dev_err(rng->dev, "Re-seed fail\n"); 232 + return ret; 233 + } 234 + 235 + return nbytes; 236 + } 237 + 238 + static int xtrng_trng_generate(struct crypto_rng *tfm, const u8 *src, u32 slen, 239 + u8 *dst, u32 dlen) 240 + { 241 + struct xilinx_rng_ctx *ctx = crypto_rng_ctx(tfm); 242 + int ret; 243 + 244 + mutex_lock(&ctx->rng->lock); 245 + ret = xtrng_random_bytes_generate(ctx->rng, dst, dlen, true); 246 + mutex_unlock(&ctx->rng->lock); 247 + 248 + return ret < 0 ? ret : 0; 249 + } 250 + 251 + static int xtrng_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) 252 + { 253 + return 0; 254 + } 255 + 256 + static int xtrng_trng_init(struct crypto_tfm *rtfm) 257 + { 258 + struct xilinx_rng_ctx *ctx = crypto_tfm_ctx(rtfm); 259 + 260 + ctx->rng = xilinx_rng_dev; 261 + 262 + return 0; 263 + } 264 + 265 + static struct rng_alg xtrng_trng_alg = { 266 + .generate = xtrng_trng_generate, 267 + .seed = xtrng_trng_seed, 268 + .seedsize = 0, 269 + .base = { 270 + .cra_name = "stdrng", 271 + .cra_driver_name = "xilinx-trng", 272 + .cra_priority = 300, 273 + .cra_ctxsize = sizeof(struct xilinx_rng_ctx), 274 + .cra_module = THIS_MODULE, 275 + .cra_init = xtrng_trng_init, 276 + }, 277 + }; 278 + 279 + static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) 280 + { 281 + u8 buf[TRNG_SEC_STRENGTH_BYTES]; 282 + struct xilinx_rng *rng; 283 + int ret = -EINVAL, i = 0; 284 + 285 + rng = container_of(hwrng, struct xilinx_rng, trng); 286 + /* Return in case wait not set and lock not available. */ 287 + if (!mutex_trylock(&rng->lock) && !wait) 288 + return 0; 289 + else if (!mutex_is_locked(&rng->lock) && wait) 290 + mutex_lock(&rng->lock); 291 + 292 + while (i < max) { 293 + ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait); 294 + if (ret < 0) 295 + break; 296 + 297 + memcpy(data + i, buf, min_t(int, ret, (max - i))); 298 + i += min_t(int, ret, (max - i)); 299 + } 300 + mutex_unlock(&rng->lock); 301 + 302 + return ret; 303 + } 304 + 305 + static int xtrng_hwrng_register(struct hwrng *trng) 306 + { 307 + int ret; 308 + 309 + trng->name = "Xilinx Versal Crypto Engine TRNG"; 310 + trng->read = xtrng_hwrng_trng_read; 311 + 312 + ret = hwrng_register(trng); 313 + if (ret) 314 + pr_err("Fail to register the TRNG\n"); 315 + 316 + return ret; 317 + } 318 + 319 + static void xtrng_hwrng_unregister(struct hwrng *trng) 320 + { 321 + hwrng_unregister(trng); 322 + } 323 + 324 + static int xtrng_probe(struct platform_device *pdev) 325 + { 326 + struct xilinx_rng *rng; 327 + int ret; 328 + 329 + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); 330 + if (!rng) 331 + return -ENOMEM; 332 + 333 + rng->dev = &pdev->dev; 334 + rng->rng_base = devm_platform_ioremap_resource(pdev, 0); 335 + if (IS_ERR(rng->rng_base)) { 336 + dev_err(&pdev->dev, "Failed to map resource %ld\n", PTR_ERR(rng->rng_base)); 337 + return PTR_ERR(rng->rng_base); 338 + } 339 + 340 + xtrng_trng_reset(rng->rng_base); 341 + ret = xtrng_reseed_internal(rng); 342 + if (ret) { 343 + dev_err(&pdev->dev, "TRNG Seed fail\n"); 344 + return ret; 345 + } 346 + 347 + xilinx_rng_dev = rng; 348 + mutex_init(&rng->lock); 349 + ret = crypto_register_rng(&xtrng_trng_alg); 350 + if (ret) { 351 + dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret); 352 + return ret; 353 + } 354 + ret = xtrng_hwrng_register(&rng->trng); 355 + if (ret) { 356 + dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret); 357 + goto crypto_rng_free; 358 + } 359 + platform_set_drvdata(pdev, rng); 360 + 361 + return 0; 362 + 363 + crypto_rng_free: 364 + crypto_unregister_rng(&xtrng_trng_alg); 365 + 366 + return ret; 367 + } 368 + 369 + static void xtrng_remove(struct platform_device *pdev) 370 + { 371 + struct xilinx_rng *rng; 372 + u32 zero[TRNG_NUM_INIT_REGS] = { }; 373 + 374 + rng = platform_get_drvdata(pdev); 375 + xtrng_hwrng_unregister(&rng->trng); 376 + crypto_unregister_rng(&xtrng_trng_alg); 377 + xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, zero, 378 + TRNG_NUM_INIT_REGS); 379 + xtrng_write_multiple_registers(rng->rng_base + TRNG_PER_STRNG_OFFSET, zero, 380 + TRNG_NUM_INIT_REGS); 381 + xtrng_hold_reset(rng->rng_base); 382 + xilinx_rng_dev = NULL; 383 + } 384 + 385 + static const struct of_device_id xtrng_of_match[] = { 386 + { .compatible = "xlnx,versal-trng", }, 387 + {}, 388 + }; 389 + 390 + MODULE_DEVICE_TABLE(of, xtrng_of_match); 391 + 392 + static struct platform_driver xtrng_driver = { 393 + .driver = { 394 + .name = "xlnx,versal-trng", 395 + .of_match_table = xtrng_of_match, 396 + }, 397 + .probe = xtrng_probe, 398 + .remove = xtrng_remove, 399 + }; 400 + 401 + module_platform_driver(xtrng_driver); 402 + MODULE_LICENSE("GPL"); 403 + MODULE_AUTHOR("Harsh Jain <h.jain@amd.com>"); 404 + MODULE_AUTHOR("Mounika Botcha <mounika.botcha@amd.com>"); 405 + MODULE_DESCRIPTION("True Random Number Generator Driver");