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