1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 Michael Walle <michael@walle.cc>
4  *
5  * Driver for Freescale Cryptographic Accelerator and Assurance
6  * Module (CAAM) hardware random number generator.
7  */
8 
9 #include <asm/cache.h>
10 #include <common.h>
11 #include <cpu_func.h>
12 #include <dm.h>
13 #include <rng.h>
14 #include <linux/kernel.h>
15 #include "desc_constr.h"
16 #include "jobdesc.h"
17 #include "jr.h"
18 
19 #define CAAM_RNG_MAX_FIFO_STORE_SIZE 16
20 #define CAAM_RNG_DESC_LEN (3 * CAAM_CMD_SZ + CAAM_PTR_SZ)
21 
22 struct caam_rng_priv {
23 	u32 desc[CAAM_RNG_DESC_LEN / 4];
24 	u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN);
25 };
26 
caam_rng_read_one(struct caam_rng_priv * priv)27 static int caam_rng_read_one(struct caam_rng_priv *priv)
28 {
29 	int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN);
30 	int ret;
31 
32 	ret = run_descriptor_jr(priv->desc);
33 	if (ret < 0)
34 		return -EIO;
35 
36 	invalidate_dcache_range((unsigned long)priv->data,
37 				(unsigned long)priv->data + size);
38 
39 	return 0;
40 }
41 
caam_rng_read(struct udevice * dev,void * data,size_t len)42 static int caam_rng_read(struct udevice *dev, void *data, size_t len)
43 {
44 	struct caam_rng_priv *priv = dev_get_priv(dev);
45 	u8 *buffer = data;
46 	size_t size;
47 	int ret;
48 
49 	while (len) {
50 		ret = caam_rng_read_one(priv);
51 		if (ret)
52 			return ret;
53 
54 		size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE);
55 
56 		memcpy(buffer, priv->data, size);
57 		buffer += size;
58 		len -= size;
59 	}
60 
61 	return 0;
62 }
63 
caam_rng_probe(struct udevice * dev)64 static int caam_rng_probe(struct udevice *dev)
65 {
66 	struct caam_rng_priv *priv = dev_get_priv(dev);
67 	ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN);
68 
69 	inline_cnstr_jobdesc_rng(priv->desc, priv->data,
70 				 CAAM_RNG_MAX_FIFO_STORE_SIZE);
71 	flush_dcache_range((unsigned long)priv->desc,
72 			   (unsigned long)priv->desc + size);
73 
74 	return 0;
75 }
76 
77 static const struct dm_rng_ops caam_rng_ops = {
78 	.read = caam_rng_read,
79 };
80 
81 U_BOOT_DRIVER(caam_rng) = {
82 	.name = "caam-rng",
83 	.id = UCLASS_RNG,
84 	.ops = &caam_rng_ops,
85 	.probe = caam_rng_probe,
86 	.priv_auto	= sizeof(struct caam_rng_priv),
87 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
88 };
89