xref: /openbmc/qemu/hw/gpio/nrf51_gpio.c (revision c7b95171)
1 /*
2  * nRF51 System-on-Chip general purpose input/output register definition
3  *
4  * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
5  * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
6  *
7  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
8  *
9  * This code is licensed under the GPL version 2 or later.  See
10  * the COPYING file in the top-level directory.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "qemu/log.h"
15 #include "hw/gpio/nrf51_gpio.h"
16 #include "trace.h"
17 
18 /*
19  * Check if the output driver is connected to the direction switch
20  * given the current configuration and logic level.
21  * It is not differentiated between standard and "high"(-power) drive modes.
22  */
23 static bool is_connected(uint32_t config, uint32_t level)
24 {
25     bool state;
26     uint32_t drive_config = extract32(config, 8, 3);
27 
28     switch (drive_config) {
29     case 0 ... 3:
30         state = true;
31         break;
32     case 4 ... 5:
33         state = level != 0;
34         break;
35     case 6 ... 7:
36         state = level == 0;
37         break;
38     default:
39         g_assert_not_reached();
40         break;
41     }
42 
43     return state;
44 }
45 
46 static void update_output_irq(NRF51GPIOState *s, size_t i,
47                               bool connected, bool level)
48 {
49     int64_t irq_level = connected ? level : -1;
50     bool old_connected = extract32(s->old_out_connected, i, 1);
51     bool old_level = extract32(s->old_out, i, 1);
52 
53     if ((old_connected != connected) || (old_level != level)) {
54         qemu_set_irq(s->output[i], irq_level);
55         trace_nrf51_gpio_update_output_irq(i, irq_level);
56     }
57 
58     s->old_out = deposit32(s->old_out, i, 1, level);
59     s->old_out_connected = deposit32(s->old_out_connected, i, 1, connected);
60 }
61 
62 static void update_state(NRF51GPIOState *s)
63 {
64     uint32_t pull;
65     size_t i;
66     bool connected_out, dir, connected_in, out, input;
67 
68     for (i = 0; i < NRF51_GPIO_PINS; i++) {
69         pull = extract32(s->cnf[i], 2, 2);
70         dir = extract32(s->cnf[i], 0, 1);
71         connected_in = extract32(s->in_mask, i, 1);
72         out = extract32(s->out, i, 1);
73         input = !extract32(s->cnf[i], 1, 1);
74         connected_out = is_connected(s->cnf[i], out) && dir;
75 
76         update_output_irq(s, i, connected_out, out);
77 
78         /* Pin both driven externally and internally */
79         if (connected_out && connected_in) {
80             qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
81         }
82 
83         /*
84          * Input buffer disconnected from internal/external drives, so
85          * pull-up/pull-down becomes relevant
86          */
87         if (!input || (input && !connected_in && !connected_out)) {
88             if (pull == NRF51_GPIO_PULLDOWN) {
89                 s->in = deposit32(s->in, i, 1, 0);
90             } else if (pull == NRF51_GPIO_PULLUP) {
91                 s->in = deposit32(s->in, i, 1, 1);
92             }
93         }
94 
95         /* Self stimulation through internal output driver */
96         if (connected_out && !connected_in && input) {
97             s->in = deposit32(s->in, i, 1, out);
98         }
99     }
100 
101 }
102 
103 /*
104  * Direction is exposed in both the DIR register and the DIR bit
105  * of each PINs CNF configuration register. Reflect bits for pins in DIR
106  * to individual pin configuration registers.
107  */
108 static void reflect_dir_bit_in_cnf(NRF51GPIOState *s)
109 {
110     size_t i;
111 
112     uint32_t value = s->dir;
113 
114     for (i = 0; i < NRF51_GPIO_PINS; i++) {
115         s->cnf[i] = (s->cnf[i] & ~(1UL)) | ((value >> i) & 0x01);
116     }
117 }
118 
119 static uint64_t nrf51_gpio_read(void *opaque, hwaddr offset, unsigned int size)
120 {
121     NRF51GPIOState *s = NRF51_GPIO(opaque);
122     uint64_t r = 0;
123     size_t idx;
124 
125     switch (offset) {
126     case NRF51_GPIO_REG_OUT ... NRF51_GPIO_REG_OUTCLR:
127         r = s->out;
128         break;
129 
130     case NRF51_GPIO_REG_IN:
131         r = s->in;
132         break;
133 
134     case NRF51_GPIO_REG_DIR ... NRF51_GPIO_REG_DIRCLR:
135         r = s->dir;
136         break;
137 
138     case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
139         idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
140         r = s->cnf[idx];
141         break;
142 
143     default:
144         qemu_log_mask(LOG_GUEST_ERROR,
145                 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
146                       __func__, offset);
147     }
148 
149     trace_nrf51_gpio_read(offset, r);
150 
151     return r;
152 }
153 
154 static void nrf51_gpio_write(void *opaque, hwaddr offset,
155                        uint64_t value, unsigned int size)
156 {
157     NRF51GPIOState *s = NRF51_GPIO(opaque);
158     size_t idx;
159 
160     trace_nrf51_gpio_write(offset, value);
161 
162     switch (offset) {
163     case NRF51_GPIO_REG_OUT:
164         s->out = value;
165         break;
166 
167     case NRF51_GPIO_REG_OUTSET:
168         s->out |= value;
169         break;
170 
171     case NRF51_GPIO_REG_OUTCLR:
172         s->out &= ~value;
173         break;
174 
175     case NRF51_GPIO_REG_DIR:
176         s->dir = value;
177         reflect_dir_bit_in_cnf(s);
178         break;
179 
180     case NRF51_GPIO_REG_DIRSET:
181         s->dir |= value;
182         reflect_dir_bit_in_cnf(s);
183         break;
184 
185     case NRF51_GPIO_REG_DIRCLR:
186         s->dir &= ~value;
187         reflect_dir_bit_in_cnf(s);
188         break;
189 
190     case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
191         idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
192         s->cnf[idx] = value;
193         /*
194          * direction is exposed in both the DIR register and the DIR bit
195          * of each PINs CNF configuration register.
196          */
197         s->dir = (s->dir & ~(1UL << idx)) | ((value & 0x01) << idx);
198         break;
199 
200     default:
201         qemu_log_mask(LOG_GUEST_ERROR,
202                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
203                       __func__, offset);
204     }
205 
206     update_state(s);
207 }
208 
209 static const MemoryRegionOps gpio_ops = {
210     .read =  nrf51_gpio_read,
211     .write = nrf51_gpio_write,
212     .endianness = DEVICE_LITTLE_ENDIAN,
213     .impl.min_access_size = 4,
214     .impl.max_access_size = 4,
215 };
216 
217 static void nrf51_gpio_set(void *opaque, int line, int value)
218 {
219     NRF51GPIOState *s = NRF51_GPIO(opaque);
220 
221     trace_nrf51_gpio_set(line, value);
222 
223     assert(line >= 0 && line < NRF51_GPIO_PINS);
224 
225     s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
226     if (value >= 0) {
227         s->in = deposit32(s->in, line, 1, value != 0);
228     }
229 
230     update_state(s);
231 }
232 
233 static void nrf51_gpio_reset(DeviceState *dev)
234 {
235     NRF51GPIOState *s = NRF51_GPIO(dev);
236     size_t i;
237 
238     s->out = 0;
239     s->old_out = 0;
240     s->old_out_connected = 0;
241     s->in = 0;
242     s->in_mask = 0;
243     s->dir = 0;
244 
245     for (i = 0; i < NRF51_GPIO_PINS; i++) {
246         s->cnf[i] = 0x00000002;
247     }
248 }
249 
250 static const VMStateDescription vmstate_nrf51_gpio = {
251     .name = TYPE_NRF51_GPIO,
252     .version_id = 1,
253     .minimum_version_id = 1,
254     .fields = (VMStateField[]) {
255         VMSTATE_UINT32(out, NRF51GPIOState),
256         VMSTATE_UINT32(in, NRF51GPIOState),
257         VMSTATE_UINT32(in_mask, NRF51GPIOState),
258         VMSTATE_UINT32(dir, NRF51GPIOState),
259         VMSTATE_UINT32_ARRAY(cnf, NRF51GPIOState, NRF51_GPIO_PINS),
260         VMSTATE_UINT32(old_out, NRF51GPIOState),
261         VMSTATE_UINT32(old_out_connected, NRF51GPIOState),
262         VMSTATE_END_OF_LIST()
263     }
264 };
265 
266 static void nrf51_gpio_init(Object *obj)
267 {
268     NRF51GPIOState *s = NRF51_GPIO(obj);
269 
270     memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
271             TYPE_NRF51_GPIO, NRF51_GPIO_SIZE);
272     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
273 
274     qdev_init_gpio_in(DEVICE(s), nrf51_gpio_set, NRF51_GPIO_PINS);
275     qdev_init_gpio_out(DEVICE(s), s->output, NRF51_GPIO_PINS);
276 }
277 
278 static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
279 {
280     DeviceClass *dc = DEVICE_CLASS(klass);
281 
282     dc->vmsd = &vmstate_nrf51_gpio;
283     dc->reset = nrf51_gpio_reset;
284     dc->desc = "nRF51 GPIO";
285 }
286 
287 static const TypeInfo nrf51_gpio_info = {
288     .name = TYPE_NRF51_GPIO,
289     .parent = TYPE_SYS_BUS_DEVICE,
290     .instance_size = sizeof(NRF51GPIOState),
291     .instance_init = nrf51_gpio_init,
292     .class_init = nrf51_gpio_class_init
293 };
294 
295 static void nrf51_gpio_register_types(void)
296 {
297     type_register_static(&nrf51_gpio_info);
298 }
299 
300 type_init(nrf51_gpio_register_types)
301