blob: 8c9e111e2e03ed747cd6892f2dc36d49464dbcd6 [file] [log] [blame]
Heinrich Schuchardtceec9772023-10-31 14:55:52 +02001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * The RISC-V Zkr extension provides CSR seed which provides access to a
4 * random number generator.
5 */
6
7#define LOG_CATEGORY UCLASS_RNG
8
9#include <dm.h>
10#include <interrupt.h>
11#include <log.h>
12#include <rng.h>
13
14#define DRIVER_NAME "riscv_zkr"
15
16enum opst {
17 /** @BIST: built in self test running */
18 BIST = 0b00,
19 /** @WAIT: sufficient amount of entropy is not yet available */
20 WAIT = 0b01,
21 /** @ES16: 16bits of entropy available */
22 ES16 = 0b10,
23 /** @DEAD: unrecoverable self-test error */
24 DEAD = 0b11,
25};
26
27static unsigned long read_seed(void)
28{
29 unsigned long ret;
30
31 __asm__ __volatile__("csrrw %0, seed, x0" : "=r" (ret) : : "memory");
32
33 return ret;
34}
35
36static int riscv_zkr_read(struct udevice *dev, void *data, size_t len)
37{
38 u8 *ptr = data;
39
40 while (len) {
41 u32 val;
42
43 val = read_seed();
44
45 switch (val >> 30) {
46 case BIST:
47 continue;
48 case WAIT:
49 continue;
50 case ES16:
51 *ptr++ = val & 0xff;
52 if (--len) {
53 *ptr++ = val >> 8;
54 --len;
55 }
56 break;
57 case DEAD:
58 return -ENODEV;
59 }
60 }
61
62 return 0;
63}
64
65/**
66 * riscv_zkr_probe() - check if the seed register is available
67 *
68 * If the SBI software has not set mseccfg.sseed=1 or the Zkr
69 * extension is not available this probe function will result
70 * in an exception. Currently we cannot recover from this.
71 *
72 * @dev: RNG device
73 * Return: 0 if successfully probed
74 */
75static int riscv_zkr_probe(struct udevice *dev)
76{
77 struct resume_data resume;
78 int ret;
79 u32 val;
80
81 /* Check if reading seed leads to interrupt */
82 set_resume(&resume);
83 ret = setjmp(resume.jump);
84 if (ret)
85 log_debug("Exception %ld reading seed CSR\n", resume.code);
86 else
87 val = read_seed();
88 set_resume(NULL);
89 if (ret)
90 return -ENODEV;
91
92 do {
93 val = read_seed();
94 val >>= 30;
95 } while (val == BIST || val == WAIT);
96
97 if (val == DEAD)
98 return -ENODEV;
99
100 return 0;
101}
102
103static const struct dm_rng_ops riscv_zkr_ops = {
104 .read = riscv_zkr_read,
105};
106
107U_BOOT_DRIVER(riscv_zkr) = {
108 .name = DRIVER_NAME,
109 .id = UCLASS_RNG,
110 .ops = &riscv_zkr_ops,
111 .probe = riscv_zkr_probe,
112};
113
114U_BOOT_DRVINFO(cpu_riscv_zkr) = {
115 .name = DRIVER_NAME,
116};