nrf51_gpio.c (8546B)
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 */ 26static 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 49static 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 60static 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 76static 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 */ 126static 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 137static 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 172static 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 227static 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 235static 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 251static 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 268static 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 284static 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 296static 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 305static 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 313static void nrf51_gpio_register_types(void) 314{ 315 type_register_static(&nrf51_gpio_info); 316} 317 318type_init(nrf51_gpio_register_types)