blob: ca808c457978c3e6b74aafd49e299955eba791bb [file] [log] [blame]
Max Resch18ef74a2024-02-15 17:57:57 +01001// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
2/*
3 * Copyright (c) 2024, Max Resch
4 */
5
6#include <dm.h>
7#include <malloc.h>
8#include <rng.h>
9#include <asm/dma-mapping.h>
10#include <asm/types.h>
11#include <mach/mbox.h>
12
13/* size of entropy buffer */
14#define RNG_BUFFER_SIZE 128U
15
16struct turris_rwtm_rng_priv {
17 phys_addr_t buffer;
18};
19
20static int turris_rwtm_rng_fill_entropy(phys_addr_t entropy, size_t size)
21{
22 u32 args[3] = { 1, (u32)entropy, size };
23 int ret;
24
25 /* flush data cache */
26 flush_dcache_range(entropy, entropy + size);
27
28 /*
29 * get entropy
30 * args[0] = 1 copies BYTES array in args[1] of length args[2]
31 */
32 ret = mbox_do_cmd(MBOX_CMD_GET_RANDOM, args, 3, NULL, 0);
33 if (ret < 0)
34 return ret;
35
36 /* invalidate data cache */
37 invalidate_dcache_range(entropy, entropy + size);
38
39 return 0;
40}
41
42static int turris_rwtm_rng_random_read(struct udevice *dev, void *data, size_t count)
43{
44 struct turris_rwtm_rng_priv *priv = dev_get_priv(dev);
45 phys_addr_t phys;
46 size_t size;
47 int ret;
48
49 phys = priv->buffer;
50
51 while (count) {
52 size = min_t(size_t, RNG_BUFFER_SIZE, count);
53
54 ret = turris_rwtm_rng_fill_entropy(phys, size);
55 if (ret < 0)
56 return ret;
57
58 memcpy(data, (void *)phys, size);
59 count -= size;
60 data = (u8 *)data + size;
61 }
62
63 return 0;
64}
65
66static int turris_rwtm_rng_probe(struct udevice *dev)
67{
68 struct turris_rwtm_rng_priv *priv = dev_get_priv(dev);
69 u32 args[] = { 0 };
70 int ret;
71
72 /*
73 * check if the random command is supported
74 * args[0] = 0 would copy 16 DWORDS entropy to out but we ignore them
75 */
76 ret = mbox_do_cmd(MBOX_CMD_GET_RANDOM, args, ARRAY_SIZE(args), NULL, 0);
77 if (ret < 0)
78 return ret;
79
80 /* entropy buffer */
81 priv->buffer = 0;
82
83 /* buffer address need to be aligned */
84 dma_alloc_coherent(RNG_BUFFER_SIZE, (unsigned long *)&priv->buffer);
85 if (!priv->buffer)
86 return -ENOMEM;
87
88 return 0;
89}
90
91static int turris_rwtm_rng_remove(struct udevice *dev)
92{
93 struct turris_rwtm_rng_priv *priv = dev_get_priv(dev);
94 phys_addr_t phys = priv->buffer;
95
96 dma_free_coherent((void *)phys);
97
98 return 0;
99}
100
101static const struct dm_rng_ops turris_rwtm_rng_ops = {
102 .read = turris_rwtm_rng_random_read,
103};
104
105/*
106 * only Turris MOX firmware has the RNG but allow all probable devices to be
107 * probed the default firmware will just reject the probe
108 */
109static const struct udevice_id turris_rwtm_rng_match[] = {
110 { .compatible = "cznic,turris-mox-rwtm" },
111 { .compatible = "marvell,armada-3700-rwtm-firmware" },
112 {},
113};
114
115U_BOOT_DRIVER(turris_rwtm_rng) = {
116 .name = "turris-rwtm-rng",
117 .id = UCLASS_RNG,
118 .of_match = turris_rwtm_rng_match,
119 .ops = &turris_rwtm_rng_ops,
120 .probe = turris_rwtm_rng_probe,
121 .remove = turris_rwtm_rng_remove,
122 .priv_auto = sizeof(struct turris_rwtm_rng_priv),
123};