File Index
Files and directories
Sign in
FILE

xilinx-trng.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/xilinx/xilinx-trng.c 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/firmware/xlnx-zynqmp.h>
 12#include <linux/hw_random.h>
 13#include <linux/io.h>
 14#include <linux/iopoll.h>
 15#include <linux/kernel.h>
 16#include <linux/module.h>
 17#include <linux/mutex.h>
 18#include <linux/mod_devicetable.h>
 19#include <linux/platform_device.h>
 20#include <crypto/aes.h>
 21#include <crypto/df_sp80090a.h>
 22#include <crypto/internal/drbg.h>
 23#include <crypto/internal/cipher.h>
 24#include <crypto/internal/rng.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
 59struct xilinx_rng {
 60	void __iomem *rng_base;
 61	struct device *dev;
 62	unsigned char *scratchpadbuf;
 63	struct crypto_aes_ctx *aesctx;
 64	struct mutex lock;	/* Protect access to TRNG device */
 65	struct hwrng trng;
 66};
 67
 68struct xilinx_rng_ctx {
 69	struct xilinx_rng *rng;
 70};
 71
 72static struct xilinx_rng *xilinx_rng_dev;
 73
 74static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
 75{
 76	u32 val;
 77
 78	val = ioread32(addr);
 79	val = (val & (~mask)) | (mask & value);
 80	iowrite32(val, addr);
 81}
 82
 83static void xtrng_trng_reset(void __iomem *addr)
 84{
 85	xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, TRNG_RESET_VAL_MASK);
 86	udelay(TRNG_RESET_DELAY);
 87	xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, 0);
 88}
 89
 90static void xtrng_hold_reset(void __iomem *addr)
 91{
 92	xtrng_readwrite32(addr + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK,
 93			  TRNG_CTRL_PRNGSRST_MASK);
 94	iowrite32(TRNG_RESET_VAL_MASK, addr + TRNG_RESET_OFFSET);
 95	udelay(TRNG_RESET_DELAY);
 96}
 97
 98static void xtrng_softreset(struct xilinx_rng *rng)
 99{
100	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK,
101			  TRNG_CTRL_PRNGSRST_MASK);
102	udelay(TRNG_RESET_DELAY);
103	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 0);
104}
105
106/* Return no. of bytes read */
107static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait)
108{
109	int read = 0, ret;
110	int timeout = 1;
111	int i, idx;
112	u32 val;
113
114	if (wait)
115		timeout = TRNG_DATA_READ_DELAY;
116
117	for (i = 0; i < (blocks32 * 2); i++) {
118		/* TRNG core generate data in 16 bytes. Read twice to complete 32 bytes read */
119		ret = readl_poll_timeout(rng_base + TRNG_STATUS_OFFSET, val,
120					 (val & TRNG_STATUS_QCNT_MASK) ==
121					 TRNG_STATUS_QCNT_16_BYTES, !!wait, timeout);
122		if (ret)
123			break;
124
125		for (idx = 0; idx < TRNG_READ_4_WORD; idx++) {
126			*(buf + read) = cpu_to_be32(ioread32(rng_base + TRNG_CORE_OUTPUT_OFFSET));
127			read += 1;
128		}
129	}
130	return read * 4;
131}
132
133static int xtrng_collect_random_data(struct xilinx_rng *rng, u8 *rand_gen_buf,
134				     int no_of_random_bytes, bool wait)
135{
136	u8 randbuf[TRNG_SEC_STRENGTH_BYTES];
137	int byteleft, blocks, count = 0;
138	int ret;
139
140	byteleft = no_of_random_bytes & (TRNG_SEC_STRENGTH_BYTES - 1);
141	blocks = no_of_random_bytes >> TRNG_SEC_STRENGTH_SHIFT;
142	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK,
143			  TRNG_CTRL_PRNGSTART_MASK);
144	if (blocks) {
145		ret = xtrng_readblock32(rng->rng_base, (__be32 *)rand_gen_buf, blocks, wait);
146		if (!ret)
147			return 0;
148		count += ret;
149	}
150
151	if (byteleft) {
152		ret = xtrng_readblock32(rng->rng_base, (__be32 *)randbuf, 1, wait);
153		if (!ret)
154			return count;
155		memcpy(rand_gen_buf + (blocks * TRNG_SEC_STRENGTH_BYTES), randbuf, byteleft);
156		count += byteleft;
157	}
158
159	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET,
160			  TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGSTART_MASK, 0U);
161
162	return count;
163}
164
165static void xtrng_write_multiple_registers(void __iomem *base_addr, u32 *values, size_t n)
166{
167	void __iomem *reg_addr;
168	size_t i;
169
170	/* Write seed value into EXTERNAL_SEED Registers in big endian format */
171	for (i = 0; i < n; i++) {
172		reg_addr = (base_addr + ((n - 1 - i) * TRNG_BYTES_PER_REG));
173		iowrite32((u32 __force)(cpu_to_be32(values[i])), reg_addr);
174	}
175}
176
177static void xtrng_enable_entropy(struct xilinx_rng *rng)
178{
179	iowrite32(TRNG_OSC_EN_VAL_MASK, rng->rng_base + TRNG_OSC_EN_OFFSET);
180	xtrng_softreset(rng);
181	iowrite32(TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
182}
183
184static int xtrng_reseed_internal(struct xilinx_rng *rng)
185{
186	u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES];
187	struct drbg_string data;
188	LIST_HEAD(seedlist);
189	u32 val;
190	int ret;
191
192	drbg_string_fill(&data, entropy, TRNG_SEED_LEN_BYTES);
193	list_add_tail(&data.list, &seedlist);
194	memset(entropy, 0, sizeof(entropy));
195	xtrng_enable_entropy(rng);
196
197	/* collect random data to use it as entropy (input for DF) */
198	ret = xtrng_collect_random_data(rng, entropy, TRNG_SEED_LEN_BYTES, true);
199	if (ret != TRNG_SEED_LEN_BYTES)
200		return -EINVAL;
201	ret = crypto_drbg_ctr_df(rng->aesctx, rng->scratchpadbuf,
202				 TRNG_SEED_LEN_BYTES, &seedlist, AES_BLOCK_SIZE,
203				 TRNG_SEED_LEN_BYTES);
204	if (ret)
205		return ret;
206
207	xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET,
208				       (u32 *)rng->scratchpadbuf, TRNG_NUM_INIT_REGS);
209	/* select reseed operation */
210	iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
211
212	/* Start the reseed operation with above configuration and wait for STATUS.Done bit to be
213	 * set. Monitor STATUS.CERTF bit, if set indicates SP800-90B entropy health test has failed.
214	 */
215	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK,
216			  TRNG_CTRL_PRNGSTART_MASK);
217
218	ret = readl_poll_timeout(rng->rng_base + TRNG_STATUS_OFFSET, val,
219				 (val & TRNG_STATUS_DONE_MASK) == TRNG_STATUS_DONE_MASK,
220				  1U, 15000U);
221	if (ret)
222		return ret;
223
224	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, 0U);
225
226	return 0;
227}
228
229static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr,
230				       u32 rand_buf_size, int wait)
231{
232	int nbytes;
233	int ret;
234
235	xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET,
236			  TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK,
237			  TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK);
238	nbytes = xtrng_collect_random_data(rng, rand_buf_ptr, rand_buf_size, wait);
239
240	ret = xtrng_reseed_internal(rng);
241	if (ret) {
242		dev_err(rng->dev, "Re-seed fail\n");
243		return ret;
244	}
245
246	return nbytes;
247}
248
249static int xtrng_trng_generate(struct crypto_rng *tfm, const u8 *src, u32 slen,
250			       u8 *dst, u32 dlen)
251{
252	struct xilinx_rng_ctx *ctx = crypto_rng_ctx(tfm);
253	int ret;
254
255	mutex_lock(&ctx->rng->lock);
256	ret = xtrng_random_bytes_generate(ctx->rng, dst, dlen, true);
257	mutex_unlock(&ctx->rng->lock);
258
259	return ret < 0 ? ret : 0;
260}
261
262static int xtrng_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
263{
264	return 0;
265}
266
267static int xtrng_trng_init(struct crypto_tfm *rtfm)
268{
269	struct xilinx_rng_ctx *ctx = crypto_tfm_ctx(rtfm);
270
271	ctx->rng = xilinx_rng_dev;
272
273	return 0;
274}
275
276static struct rng_alg xtrng_trng_alg = {
277	.generate = xtrng_trng_generate,
278	.seed = xtrng_trng_seed,
279	.seedsize = 0,
280	.base = {
281		.cra_name = "stdrng",
282		.cra_driver_name = "xilinx-trng",
283		.cra_priority = 300,
284		.cra_ctxsize = sizeof(struct xilinx_rng_ctx),
285		.cra_module = THIS_MODULE,
286		.cra_init = xtrng_trng_init,
287	},
288};
289
290static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
291{
292	u8 buf[TRNG_SEC_STRENGTH_BYTES];
293	struct xilinx_rng *rng;
294	int ret = -EINVAL, i = 0;
295
296	rng = container_of(hwrng, struct xilinx_rng, trng);
297	/* Return in case wait not set and lock not available. */
298	if (!mutex_trylock(&rng->lock) && !wait)
299		return 0;
300	else if (!mutex_is_locked(&rng->lock) && wait)
301		mutex_lock(&rng->lock);
302
303	while (i < max) {
304		ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait);
305		if (ret < 0)
306			break;
307
308		memcpy(data + i, buf, min_t(int, ret, (max - i)));
309		i += min_t(int, ret, (max - i));
310	}
311	mutex_unlock(&rng->lock);
312
313	return ret;
314}
315
316static int xtrng_hwrng_register(struct hwrng *trng)
317{
318	int ret;
319
320	trng->name = "Xilinx Versal Crypto Engine TRNG";
321	trng->read = xtrng_hwrng_trng_read;
322
323	ret = hwrng_register(trng);
324	if (ret)
325		pr_err("Fail to register the TRNG\n");
326
327	return ret;
328}
329
330static void xtrng_hwrng_unregister(struct hwrng *trng)
331{
332	hwrng_unregister(trng);
333}
334
335static int xtrng_probe(struct platform_device *pdev)
336{
337	struct xilinx_rng *rng;
338	size_t sb_size;
339	int ret;
340
341	rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
342	if (!rng)
343		return -ENOMEM;
344
345	rng->dev = &pdev->dev;
346	rng->rng_base = devm_platform_ioremap_resource(pdev, 0);
347	if (IS_ERR(rng->rng_base)) {
348		dev_err(&pdev->dev, "Failed to map resource %pe\n", rng->rng_base);
349		return PTR_ERR(rng->rng_base);
350	}
351
352	rng->aesctx = devm_kzalloc(&pdev->dev, sizeof(*rng->aesctx), GFP_KERNEL);
353	if (!rng->aesctx)
354		return -ENOMEM;
355
356	sb_size = crypto_drbg_ctr_df_datalen(TRNG_SEED_LEN_BYTES, AES_BLOCK_SIZE);
357	rng->scratchpadbuf = devm_kzalloc(&pdev->dev, sb_size, GFP_KERNEL);
358	if (!rng->scratchpadbuf) {
359		ret = -ENOMEM;
360		goto end;
361	}
362
363	xtrng_trng_reset(rng->rng_base);
364	ret = xtrng_reseed_internal(rng);
365	if (ret) {
366		dev_err(&pdev->dev, "TRNG Seed fail\n");
367		goto end;
368	}
369
370	xilinx_rng_dev = rng;
371	mutex_init(&rng->lock);
372	ret = crypto_register_rng(&xtrng_trng_alg);
373	if (ret) {
374		dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret);
375		goto end;
376	}
377
378	ret = xtrng_hwrng_register(&rng->trng);
379	if (ret) {
380		dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret);
381		goto crypto_rng_free;
382	}
383	platform_set_drvdata(pdev, rng);
384
385	return 0;
386
387crypto_rng_free:
388	crypto_unregister_rng(&xtrng_trng_alg);
389
390end:
391	return ret;
392}
393
394static void xtrng_remove(struct platform_device *pdev)
395{
396	struct xilinx_rng *rng;
397	u32 zero[TRNG_NUM_INIT_REGS] = { };
398
399	rng = platform_get_drvdata(pdev);
400	xtrng_hwrng_unregister(&rng->trng);
401	crypto_unregister_rng(&xtrng_trng_alg);
402	xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, zero,
403				       TRNG_NUM_INIT_REGS);
404	xtrng_write_multiple_registers(rng->rng_base + TRNG_PER_STRNG_OFFSET, zero,
405				       TRNG_NUM_INIT_REGS);
406	xtrng_hold_reset(rng->rng_base);
407	xilinx_rng_dev = NULL;
408}
409
410static const struct of_device_id xtrng_of_match[] = {
411	{ .compatible = "xlnx,versal-trng", },
412	{},
413};
414
415MODULE_DEVICE_TABLE(of, xtrng_of_match);
416
417static struct platform_driver xtrng_driver = {
418	.driver = {
419		.name = "xlnx,versal-trng",
420		.of_match_table	= xtrng_of_match,
421	},
422	.probe = xtrng_probe,
423	.remove = xtrng_remove,
424};
425
426module_platform_driver(xtrng_driver);
427MODULE_LICENSE("GPL");
428MODULE_AUTHOR("Harsh Jain <h.jain@amd.com>");
429MODULE_AUTHOR("Mounika Botcha <mounika.botcha@amd.com>");
430MODULE_DESCRIPTION("True Random Number Generator Driver");
~/ Read-only file preview.