blob: 48a5251988faee74ac1451b3be961c4434573122 [file] [log] [blame]
Heinrich Schuchardt80863542023-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:
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +020058 return -ENOENT;
Heinrich Schuchardt80863542023-10-31 14:55:52 +020059 }
60 }
61
62 return 0;
63}
64
65/**
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +020066 * riscv_zkr_bind() - check if the seed register is available
Heinrich Schuchardt80863542023-10-31 14:55:52 +020067 *
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +020068 * If the SBI software has not set mseccfg.sseed=1 or the Zkr extension is not
69 * available, reading the seed register will result in an exception from which
70 * this function safely resumes.
Heinrich Schuchardt80863542023-10-31 14:55:52 +020071 *
72 * @dev: RNG device
73 * Return: 0 if successfully probed
74 */
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +020075static int riscv_zkr_bind(struct udevice *dev)
Heinrich Schuchardt80863542023-10-31 14:55:52 +020076{
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)
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +020090 return -ENOENT;
91
92 return 0;
93}
94
95/**
96 * riscv_zkr_probe() - check if entropy is available
97 *
98 * The bind method already checked that the seed register can be read without
99 * excpetiong. Here we wait for the self test to finish and entropy becoming
100 * available.
101 *
102 * @dev: RNG device
103 * Return: 0 if successfully probed
104 */
105static int riscv_zkr_probe(struct udevice *dev)
106{
107 u32 val;
Heinrich Schuchardt80863542023-10-31 14:55:52 +0200108
109 do {
110 val = read_seed();
111 val >>= 30;
112 } while (val == BIST || val == WAIT);
113
114 if (val == DEAD)
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +0200115 return -ENOENT;
Heinrich Schuchardt80863542023-10-31 14:55:52 +0200116
117 return 0;
118}
119
120static const struct dm_rng_ops riscv_zkr_ops = {
121 .read = riscv_zkr_read,
122};
123
124U_BOOT_DRIVER(riscv_zkr) = {
125 .name = DRIVER_NAME,
126 .id = UCLASS_RNG,
127 .ops = &riscv_zkr_ops,
Heinrich Schuchardt15943ca2023-11-04 08:51:07 +0200128 .bind = riscv_zkr_bind,
Heinrich Schuchardt80863542023-10-31 14:55:52 +0200129 .probe = riscv_zkr_probe,
130};
131
132U_BOOT_DRVINFO(cpu_riscv_zkr) = {
133 .name = DRIVER_NAME,
134};