xref: /openbmc/qemu/hw/misc/nrf51_rng.c (revision da054c64)
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 "crypto/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     qcrypto_random_bytes(&s->value, 1, &error_abort);
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)
263