]> git.proxmox.com Git - mirror_qemu.git/blob - hw/misc/nrf51_rng.c
Merge remote-tracking branch 'remotes/rth/tags/pull-rng-20190522' into staging
[mirror_qemu.git] / hw / misc / nrf51_rng.c
1 /*
2 * nRF51 Random Number Generator
3 *
4 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
5 *
6 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
7 *
8 * This code is licensed under the GPL version 2 or later. See
9 * the COPYING file in the top-level directory.
10 */
11
12 #include "qemu/osdep.h"
13 #include "qemu/log.h"
14 #include "qapi/error.h"
15 #include "hw/arm/nrf51.h"
16 #include "hw/misc/nrf51_rng.h"
17 #include "qemu/guest-random.h"
18
19 static void update_irq(NRF51RNGState *s)
20 {
21 bool irq = s->interrupt_enabled && s->event_valrdy;
22 qemu_set_irq(s->irq, irq);
23 }
24
25 static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
26 {
27 NRF51RNGState *s = NRF51_RNG(opaque);
28 uint64_t r = 0;
29
30 switch (offset) {
31 case NRF51_RNG_EVENT_VALRDY:
32 r = s->event_valrdy;
33 break;
34 case NRF51_RNG_REG_SHORTS:
35 r = s->shortcut_stop_on_valrdy;
36 break;
37 case NRF51_RNG_REG_INTEN:
38 case NRF51_RNG_REG_INTENSET:
39 case NRF51_RNG_REG_INTENCLR:
40 r = s->interrupt_enabled;
41 break;
42 case NRF51_RNG_REG_CONFIG:
43 r = s->filter_enabled;
44 break;
45 case NRF51_RNG_REG_VALUE:
46 r = s->value;
47 break;
48
49 default:
50 qemu_log_mask(LOG_GUEST_ERROR,
51 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
52 __func__, offset);
53 }
54
55 return r;
56 }
57
58 static int64_t calc_next_timeout(NRF51RNGState *s)
59 {
60 int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
61 if (s->filter_enabled) {
62 timeout += s->period_filtered_us;
63 } else {
64 timeout += s->period_unfiltered_us;
65 }
66
67 return timeout;
68 }
69
70
71 static void rng_update_timer(NRF51RNGState *s)
72 {
73 if (s->active) {
74 timer_mod(&s->timer, calc_next_timeout(s));
75 } else {
76 timer_del(&s->timer);
77 }
78 }
79
80
81 static void rng_write(void *opaque, hwaddr offset,
82 uint64_t value, unsigned int size)
83 {
84 NRF51RNGState *s = NRF51_RNG(opaque);
85
86 switch (offset) {
87 case NRF51_RNG_TASK_START:
88 if (value == NRF51_TRIGGER_TASK) {
89 s->active = 1;
90 rng_update_timer(s);
91 }
92 break;
93 case NRF51_RNG_TASK_STOP:
94 if (value == NRF51_TRIGGER_TASK) {
95 s->active = 0;
96 rng_update_timer(s);
97 }
98 break;
99 case NRF51_RNG_EVENT_VALRDY:
100 if (value == NRF51_EVENT_CLEAR) {
101 s->event_valrdy = 0;
102 }
103 break;
104 case NRF51_RNG_REG_SHORTS:
105 s->shortcut_stop_on_valrdy =
106 (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
107 break;
108 case NRF51_RNG_REG_INTEN:
109 s->interrupt_enabled =
110 (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
111 break;
112 case NRF51_RNG_REG_INTENSET:
113 if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
114 s->interrupt_enabled = 1;
115 }
116 break;
117 case NRF51_RNG_REG_INTENCLR:
118 if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
119 s->interrupt_enabled = 0;
120 }
121 break;
122 case NRF51_RNG_REG_CONFIG:
123 s->filter_enabled =
124 (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
125 break;
126
127 default:
128 qemu_log_mask(LOG_GUEST_ERROR,
129 "%s: bad write offset 0x%" HWADDR_PRIx "\n",
130 __func__, offset);
131 }
132
133 update_irq(s);
134 }
135
136 static const MemoryRegionOps rng_ops = {
137 .read = rng_read,
138 .write = rng_write,
139 .endianness = DEVICE_LITTLE_ENDIAN,
140 .impl.min_access_size = 4,
141 .impl.max_access_size = 4
142 };
143
144 static void nrf51_rng_timer_expire(void *opaque)
145 {
146 NRF51RNGState *s = NRF51_RNG(opaque);
147
148 qemu_guest_getrandom_nofail(&s->value, 1);
149
150 s->event_valrdy = 1;
151 qemu_set_irq(s->eep_valrdy, 1);
152
153 if (s->shortcut_stop_on_valrdy) {
154 s->active = 0;
155 }
156
157 rng_update_timer(s);
158 update_irq(s);
159 }
160
161 static void nrf51_rng_tep_start(void *opaque, int n, int level)
162 {
163 NRF51RNGState *s = NRF51_RNG(opaque);
164
165 if (level) {
166 s->active = 1;
167 rng_update_timer(s);
168 }
169 }
170
171 static void nrf51_rng_tep_stop(void *opaque, int n, int level)
172 {
173 NRF51RNGState *s = NRF51_RNG(opaque);
174
175 if (level) {
176 s->active = 0;
177 rng_update_timer(s);
178 }
179 }
180
181
182 static void nrf51_rng_init(Object *obj)
183 {
184 NRF51RNGState *s = NRF51_RNG(obj);
185 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
186
187 memory_region_init_io(&s->mmio, obj, &rng_ops, s,
188 TYPE_NRF51_RNG, NRF51_RNG_SIZE);
189 sysbus_init_mmio(sbd, &s->mmio);
190
191 timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
192
193 sysbus_init_irq(sbd, &s->irq);
194
195 /* Tasks */
196 qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
197 qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
198
199 /* Events */
200 qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
201 }
202
203 static void nrf51_rng_reset(DeviceState *dev)
204 {
205 NRF51RNGState *s = NRF51_RNG(dev);
206
207 s->value = 0;
208 s->active = 0;
209 s->event_valrdy = 0;
210 s->shortcut_stop_on_valrdy = 0;
211 s->interrupt_enabled = 0;
212 s->filter_enabled = 0;
213
214 rng_update_timer(s);
215 }
216
217
218 static Property nrf51_rng_properties[] = {
219 DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
220 period_unfiltered_us, 167),
221 DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
222 period_filtered_us, 660),
223 DEFINE_PROP_END_OF_LIST(),
224 };
225
226 static const VMStateDescription vmstate_rng = {
227 .name = "nrf51_soc.rng",
228 .version_id = 1,
229 .minimum_version_id = 1,
230 .fields = (VMStateField[]) {
231 VMSTATE_UINT32(active, NRF51RNGState),
232 VMSTATE_UINT32(event_valrdy, NRF51RNGState),
233 VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
234 VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
235 VMSTATE_UINT32(filter_enabled, NRF51RNGState),
236 VMSTATE_END_OF_LIST()
237 }
238 };
239
240 static void nrf51_rng_class_init(ObjectClass *klass, void *data)
241 {
242 DeviceClass *dc = DEVICE_CLASS(klass);
243
244 dc->props = nrf51_rng_properties;
245 dc->vmsd = &vmstate_rng;
246 dc->reset = nrf51_rng_reset;
247 }
248
249 static const TypeInfo nrf51_rng_info = {
250 .name = TYPE_NRF51_RNG,
251 .parent = TYPE_SYS_BUS_DEVICE,
252 .instance_size = sizeof(NRF51RNGState),
253 .instance_init = nrf51_rng_init,
254 .class_init = nrf51_rng_class_init
255 };
256
257 static void nrf51_rng_register_types(void)
258 {
259 type_register_static(&nrf51_rng_info);
260 }
261
262 type_init(nrf51_rng_register_types)