blob: de6672e955fa044afcbc770f2526224ff6a3be3b [file] [log] [blame]
Matthias Brugger537f0012020-12-15 10:49:23 +01001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2020, Matthias Brugger <mbrugger@suse.com>
4 *
5 * Driver for Raspberry Pi hardware random number generator
6 */
7
8#include <common.h>
9#include <dm.h>
10#include <linux/delay.h>
11#include <rng.h>
12#include <asm/io.h>
13
14#define usleep_range(a, b) udelay((b))
15
16#define RNG_CTRL_OFFSET 0x00
17#define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
18#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
19#define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
20
21#define RNG_SOFT_RESET_OFFSET 0x04
22#define RNG_SOFT_RESET 0x00000001
23
24#define RBG_SOFT_RESET_OFFSET 0x08
25#define RBG_SOFT_RESET 0x00000001
26
27#define RNG_INT_STATUS_OFFSET 0x18
28#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
29#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
30
31#define RNG_FIFO_DATA_OFFSET 0x20
32
33#define RNG_FIFO_COUNT_OFFSET 0x24
34#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
35
36struct iproc_rng200_platdata {
37 fdt_addr_t base;
38};
39
40static void iproc_rng200_enable(struct iproc_rng200_platdata *pdata, bool enable)
41{
42 fdt_addr_t rng_base = pdata->base;
43 u32 val;
44
45 val = readl(rng_base + RNG_CTRL_OFFSET);
46 val &= ~RNG_CTRL_RNG_RBGEN_MASK;
47 if (enable)
48 val |= RNG_CTRL_RNG_RBGEN_ENABLE;
49 else
50 val &= ~RNG_CTRL_RNG_RBGEN_ENABLE;
51
52 writel(val, rng_base + RNG_CTRL_OFFSET);
53
54}
55
56static void iproc_rng200_restart(struct iproc_rng200_platdata *pdata)
57{
58 fdt_addr_t rng_base = pdata->base;
59 u32 val;
60
61 iproc_rng200_enable(pdata, false);
62
63 /* Clear all interrupt status */
64 writel(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
65
66 /* Reset RNG and RBG */
67 val = readl(rng_base + RBG_SOFT_RESET_OFFSET);
68 val |= RBG_SOFT_RESET;
69 writel(val, rng_base + RBG_SOFT_RESET_OFFSET);
70
71 val = readl(rng_base + RNG_SOFT_RESET_OFFSET);
72 val |= RNG_SOFT_RESET;
73 writel(val, rng_base + RNG_SOFT_RESET_OFFSET);
74
75 val = readl(rng_base + RNG_SOFT_RESET_OFFSET);
76 val &= ~RNG_SOFT_RESET;
77 writel(val, rng_base + RNG_SOFT_RESET_OFFSET);
78
79 val = readl(rng_base + RBG_SOFT_RESET_OFFSET);
80 val &= ~RBG_SOFT_RESET;
81 writel(val, rng_base + RBG_SOFT_RESET_OFFSET);
82
83 iproc_rng200_enable(pdata, true);
84}
85
86static int iproc_rng200_read(struct udevice *dev, void *data, size_t len)
87{
88 struct iproc_rng200_platdata *priv = dev_get_plat(dev);
89 char *buf = (char *)data;
90 u32 num_remaining = len;
91 u32 status;
92
93 #define MAX_RESETS_PER_READ 1
94 u32 num_resets = 0;
95
96 while (num_remaining > 0) {
97
98 /* Is RNG sane? If not, reset it. */
99 status = readl(priv->base + RNG_INT_STATUS_OFFSET);
100 if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
101 RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
102
103 if (num_resets >= MAX_RESETS_PER_READ)
104 return len - num_remaining;
105
106 iproc_rng200_restart(priv);
107 num_resets++;
108 }
109
110 /* Are there any random numbers available? */
111 if ((readl(priv->base + RNG_FIFO_COUNT_OFFSET) &
112 RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
113
114 if (num_remaining >= sizeof(u32)) {
115 /* Buffer has room to store entire word */
116 *(u32 *)buf = readl(priv->base +
117 RNG_FIFO_DATA_OFFSET);
118 buf += sizeof(u32);
119 num_remaining -= sizeof(u32);
120 } else {
121 /* Buffer can only store partial word */
122 u32 rnd_number = readl(priv->base +
123 RNG_FIFO_DATA_OFFSET);
124 memcpy(buf, &rnd_number, num_remaining);
125 buf += num_remaining;
126 num_remaining = 0;
127 }
128
129 } else {
130 /* Can wait, give others chance to run */
131 usleep_range(min(num_remaining * 10, 500U), 500);
132 }
133 }
134
135 return 0;
136}
137
138static int iproc_rng200_probe(struct udevice *dev)
139{
140 struct iproc_rng200_platdata *priv = dev_get_plat(dev);
141
142 iproc_rng200_enable(priv, true);
143
144 return 0;
145}
146
147static int iproc_rng200_remove(struct udevice *dev)
148{
149 struct iproc_rng200_platdata *priv = dev_get_plat(dev);
150
151 iproc_rng200_enable(priv, false);
152
153 return 0;
154}
155
156static int iproc_rng200_ofdata_to_platdata(struct udevice *dev)
157{
158 struct iproc_rng200_platdata *pdata = dev_get_plat(dev);
159
160 pdata->base = dev_read_addr(dev);
161 if (!pdata->base)
162 return -ENODEV;
163
164 return 0;
165}
166
167static const struct dm_rng_ops iproc_rng200_ops = {
168 .read = iproc_rng200_read,
169};
170
171static const struct udevice_id iproc_rng200_rng_match[] = {
172 { .compatible = "brcm,bcm2711-rng200", },
173 { .compatible = "brcm,iproc-rng200", },
174 {},
175};
176
177U_BOOT_DRIVER(iproc_rng200_rng) = {
178 .name = "iproc_rng200-rng",
179 .id = UCLASS_RNG,
180 .of_match = iproc_rng200_rng_match,
181 .ops = &iproc_rng200_ops,
182 .probe = iproc_rng200_probe,
183 .remove = iproc_rng200_remove,
184 .plat_auto = sizeof(struct iproc_rng200_platdata),
185 .of_to_plat = iproc_rng200_ofdata_to_platdata,
186};