forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathentropy_neorv32_trng.c
151 lines (121 loc) · 3.46 KB
/
entropy_neorv32_trng.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
* Copyright (c) 2021 Henrik Brix Andersen <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT neorv32_trng
#include <zephyr/device.h>
#include <zephyr/drivers/syscon.h>
#include <zephyr/drivers/entropy.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/sys_io.h>
#include <soc.h>
LOG_MODULE_REGISTER(neorv32_trng, CONFIG_ENTROPY_LOG_LEVEL);
/* TRNG CTRL register bits */
#define NEORV32_TRNG_CTRL_DATA_MASK BIT_MASK(8)
#define NEORV32_TRNG_CTRL_EN BIT(30)
#define NEORV32_TRNG_CTRL_VALID BIT(31)
struct neorv32_trng_config {
const struct device *syscon;
mm_reg_t base;
};
static inline uint32_t neorv32_trng_read_ctrl(const struct device *dev)
{
const struct neorv32_trng_config *config = dev->config;
return sys_read32(config->base);
}
static inline void neorv32_trng_write_ctrl(const struct device *dev, uint32_t ctrl)
{
const struct neorv32_trng_config *config = dev->config;
sys_write32(ctrl, config->base);
}
static int neorv32_trng_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t len)
{
uint32_t ctrl;
while (len > 0) {
ctrl = neorv32_trng_read_ctrl(dev);
if ((ctrl & NEORV32_TRNG_CTRL_VALID) != 0) {
*buffer++ = ctrl & NEORV32_TRNG_CTRL_DATA_MASK;
len--;
}
}
return 0;
}
static int neorv32_trng_get_entropy_isr(const struct device *dev, uint8_t *buffer,
uint16_t len, uint32_t flags)
{
uint32_t ctrl;
int err;
if ((flags & ENTROPY_BUSYWAIT) == 0) {
ctrl = neorv32_trng_read_ctrl(dev);
if ((ctrl & NEORV32_TRNG_CTRL_VALID) != 0) {
*buffer = ctrl & NEORV32_TRNG_CTRL_DATA_MASK;
return 1;
}
/* No entropy available */
return -ENODATA;
}
err = neorv32_trng_get_entropy(dev, buffer, len);
if (err < 0) {
return err;
}
return len;
}
static int neorv32_trng_init(const struct device *dev)
{
const struct neorv32_trng_config *config = dev->config;
uint32_t features;
int err;
if (!device_is_ready(config->syscon)) {
LOG_ERR("syscon device not ready");
return -EINVAL;
}
err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_FEATURES, &features);
if (err < 0) {
LOG_ERR("failed to determine implemented features (err %d)", err);
return err;
}
if ((features & NEORV32_SYSINFO_FEATURES_IO_TRNG) == 0) {
LOG_ERR("neorv32 trng not supported");
return -ENODEV;
}
neorv32_trng_write_ctrl(dev, NEORV32_TRNG_CTRL_EN);
return 0;
}
#ifdef CONFIG_PM_DEVICE
static int neorv32_trng_pm_action(const struct device *dev, enum pm_device_action action)
{
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
neorv32_trng_write_ctrl(dev, 0);
break;
case PM_DEVICE_ACTION_RESUME:
neorv32_trng_write_ctrl(dev, NEORV32_TRNG_CTRL_EN);
break;
default:
return -ENOTSUP;
}
return 0;
}
#endif /* CONFIG_PM_DEVICE */
static const struct entropy_driver_api neorv32_trng_driver_api = {
.get_entropy = neorv32_trng_get_entropy,
.get_entropy_isr = neorv32_trng_get_entropy_isr,
};
#define NEORV32_TRNG_INIT(n) \
static const struct neorv32_trng_config neorv32_trng_##n##_config = { \
.syscon = DEVICE_DT_GET(DT_INST_PHANDLE(n, syscon)), \
.base = DT_INST_REG_ADDR(n), \
}; \
\
PM_DEVICE_DT_INST_DEFINE(n, neorv32_trng_pm_action); \
\
DEVICE_DT_INST_DEFINE(n, &neorv32_trng_init, \
PM_DEVICE_DT_INST_GET(n), \
NULL, \
&neorv32_trng_##n##_config, \
PRE_KERNEL_1, \
CONFIG_ENTROPY_INIT_PRIORITY, \
&neorv32_trng_driver_api);
DT_INST_FOREACH_STATUS_OKAY(NEORV32_TRNG_INIT)