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