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