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