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
22struct 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
27static 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
42static 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
64static 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
77static const struct dm_rng_ops caam_rng_ops = {
78	.read = caam_rng_read,
79};
80
81U_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