blob: eb21afe4e7cb078d1b97498041c36875f5f45327 [file] [log] [blame]
Chanho Parkebaee702023-11-01 21:16:50 +09001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * TRNG driver for the StarFive JH7110 SoC
4 *
5 */
6
7#include <clk.h>
8#include <dm.h>
9#include <reset.h>
10#include <rng.h>
11#include <asm/io.h>
12#include <linux/iopoll.h>
13
14/* trng register offset */
15#define STARFIVE_CTRL 0x00
16#define STARFIVE_STAT 0x04
17#define STARFIVE_MODE 0x08
18#define STARFIVE_SMODE 0x0C
19#define STARFIVE_IE 0x10
20#define STARFIVE_ISTAT 0x14
21#define STARFIVE_RAND0 0x20
22#define STARFIVE_RAND1 0x24
23#define STARFIVE_RAND2 0x28
24#define STARFIVE_RAND3 0x2C
25#define STARFIVE_RAND4 0x30
26#define STARFIVE_RAND5 0x34
27#define STARFIVE_RAND6 0x38
28#define STARFIVE_RAND7 0x3C
29#define STARFIVE_AUTO_RQSTS 0x60
30#define STARFIVE_AUTO_AGE 0x64
31
32/* CTRL CMD */
33#define STARFIVE_CTRL_EXEC_NOP 0x0
34#define STARFIVE_CTRL_GENE_RANDNUM 0x1
35#define STARFIVE_CTRL_EXEC_RANDRESEED 0x2
36
37/* STAT */
38#define STARFIVE_STAT_NONCE_MODE BIT(2)
39#define STARFIVE_STAT_R256 BIT(3)
40#define STARFIVE_STAT_MISSION_MODE BIT(8)
41#define STARFIVE_STAT_SEEDED BIT(9)
42#define STARFIVE_STAT_LAST_RESEED(x) ((x) << 16)
43#define STARFIVE_STAT_SRVC_RQST BIT(27)
44#define STARFIVE_STAT_RAND_GENERATING BIT(30)
45#define STARFIVE_STAT_RAND_SEEDING BIT(31)
46#define STARFIVE_STAT_RUNNING (STARFIVE_STAT_RAND_GENERATING | \
47 STARFIVE_STAT_RAND_SEEDING)
48
49/* MODE */
50#define STARFIVE_MODE_R256 BIT(3)
51
52/* SMODE */
53#define STARFIVE_SMODE_NONCE_MODE BIT(2)
54#define STARFIVE_SMODE_MISSION_MODE BIT(8)
55#define STARFIVE_SMODE_MAX_REJECTS(x) ((x) << 16)
56
57/* IE */
58#define STARFIVE_IE_RAND_RDY_EN BIT(0)
59#define STARFIVE_IE_SEED_DONE_EN BIT(1)
60#define STARFIVE_IE_LFSR_LOCKUP_EN BIT(4)
61#define STARFIVE_IE_GLBL_EN BIT(31)
62
63#define STARFIVE_IE_ALL (STARFIVE_IE_GLBL_EN | \
64 STARFIVE_IE_RAND_RDY_EN | \
65 STARFIVE_IE_SEED_DONE_EN | \
66 STARFIVE_IE_LFSR_LOCKUP_EN)
67
68/* ISTAT */
69#define STARFIVE_ISTAT_RAND_RDY BIT(0)
70#define STARFIVE_ISTAT_SEED_DONE BIT(1)
71#define STARFIVE_ISTAT_LFSR_LOCKUP BIT(4)
72
73#define STARFIVE_RAND_LEN sizeof(u32)
74
75enum mode {
76 PRNG_128BIT,
77 PRNG_256BIT,
78};
79
80struct starfive_trng_plat {
81 void *base;
82 struct clk *hclk;
83 struct clk *ahb;
84 struct reset_ctl *rst;
85 u32 mode;
86};
87
88static inline int starfive_trng_wait_idle(struct starfive_trng_plat *trng)
89{
90 u32 stat;
91
92 return readl_relaxed_poll_timeout(trng->base + STARFIVE_STAT, stat,
93 !(stat & STARFIVE_STAT_RUNNING),
94 100000);
95}
96
97static inline void starfive_trng_irq_mask_clear(struct starfive_trng_plat *trng)
98{
99 /* clear register: ISTAT */
100 u32 data = readl(trng->base + STARFIVE_ISTAT);
101
102 writel(data, trng->base + STARFIVE_ISTAT);
103}
104
105static int starfive_trng_cmd(struct starfive_trng_plat *trng, u32 cmd)
106{
107 u32 stat, flg;
108 int ret;
109
110 switch (cmd) {
111 case STARFIVE_CTRL_GENE_RANDNUM:
112 writel(cmd, trng->base + STARFIVE_CTRL);
113 flg = STARFIVE_ISTAT_RAND_RDY;
114 break;
115 case STARFIVE_CTRL_EXEC_RANDRESEED:
116 writel(cmd, trng->base + STARFIVE_CTRL);
117 flg = STARFIVE_ISTAT_SEED_DONE;
118 break;
119 default:
120 return -EINVAL;
121 }
122
123 ret = readl_relaxed_poll_timeout(trng->base + STARFIVE_ISTAT, stat,
124 (stat & flg), 1000);
125 writel(flg, trng->base + STARFIVE_ISTAT);
126
127 return ret;
128}
129
130static int starfive_trng_read(struct udevice *dev, void *data, size_t len)
131{
132 struct starfive_trng_plat *trng = dev_get_plat(dev);
133 u8 *buffer = data;
134 int iter_mask;
135
136 if (trng->mode == PRNG_256BIT)
137 iter_mask = 7;
138 else
139 iter_mask = 3;
140
141 for (int i = 0; len; ++i, i &= iter_mask) {
142 u32 val;
143 size_t step;
144 int ret;
145
146 if (!i) {
147 ret = starfive_trng_cmd(trng,
148 STARFIVE_CTRL_GENE_RANDNUM);
149 if (ret)
150 return ret;
151 }
152
153 val = readl(trng->base + STARFIVE_RAND0 +
154 (i * STARFIVE_RAND_LEN));
155 step = min_t(size_t, len, STARFIVE_RAND_LEN);
156 memcpy(buffer, &val, step);
157 buffer += step;
158 len -= step;
159 }
160
161 return 0;
162}
163
164static int starfive_trng_init(struct starfive_trng_plat *trng)
165{
166 u32 mode, intr = 0;
167
168 /* setup Auto Request/Age register */
169 writel(0, trng->base + STARFIVE_AUTO_AGE);
170 writel(0, trng->base + STARFIVE_AUTO_RQSTS);
171
172 /* clear register: ISTAT */
173 starfive_trng_irq_mask_clear(trng);
174
175 intr |= STARFIVE_IE_ALL;
176 writel(intr, trng->base + STARFIVE_IE);
177
178 mode = readl(trng->base + STARFIVE_MODE);
179
180 switch (trng->mode) {
181 case PRNG_128BIT:
182 mode &= ~STARFIVE_MODE_R256;
183 break;
184 case PRNG_256BIT:
185 mode |= STARFIVE_MODE_R256;
186 break;
187 default:
188 mode |= STARFIVE_MODE_R256;
189 break;
190 }
191
192 writel(mode, trng->base + STARFIVE_MODE);
193
194 return starfive_trng_cmd(trng, STARFIVE_CTRL_EXEC_RANDRESEED);
195}
196
197static int starfive_trng_probe(struct udevice *dev)
198{
199 struct starfive_trng_plat *pdata = dev_get_plat(dev);
200 int err;
201
202 err = clk_enable(pdata->hclk);
203 if (err)
204 return err;
205
206 err = clk_enable(pdata->ahb);
207 if (err)
208 goto err_ahb;
209
210 err = reset_deassert(pdata->rst);
211 if (err)
212 goto err_reset;
213
214 pdata->mode = PRNG_256BIT;
215
216 err = starfive_trng_init(pdata);
217 if (err)
218 goto err_trng_init;
219
220 return 0;
221
222err_trng_init:
223 reset_assert(pdata->rst);
224err_reset:
225 clk_disable(pdata->ahb);
226err_ahb:
227 clk_disable(pdata->hclk);
228
229 return err;
230}
231
232static int starfive_trng_of_to_plat(struct udevice *dev)
233{
234 struct starfive_trng_plat *pdata = dev_get_plat(dev);
235
236 pdata->base = (void *)dev_read_addr(dev);
237 if (!pdata->base)
238 return -ENODEV;
239
240 pdata->hclk = devm_clk_get(dev, "hclk");
241 if (IS_ERR(pdata->hclk))
242 return -ENODEV;
243
244 pdata->ahb = devm_clk_get(dev, "ahb");
245 if (IS_ERR(pdata->ahb))
246 return -ENODEV;
247
248 pdata->rst = devm_reset_control_get(dev, NULL);
249 if (IS_ERR(pdata->rst))
250 return -ENODEV;
251
252 return 0;
253}
254
255static const struct dm_rng_ops starfive_trng_ops = {
256 .read = starfive_trng_read,
257};
258
259static const struct udevice_id starfive_trng_match[] = {
260 {
261 .compatible = "starfive,jh7110-trng",
262 },
263 {},
264};
265
266U_BOOT_DRIVER(starfive_trng) = {
267 .name = "jh7110-trng",
268 .id = UCLASS_RNG,
269 .of_match = starfive_trng_match,
270 .probe = starfive_trng_probe,
271 .ops = &starfive_trng_ops,
272 .plat_auto = sizeof(struct starfive_trng_plat),
273 .of_to_plat = starfive_trng_of_to_plat,
274};