qemu/hw/gpio/sifive_gpio.c
<<
>>
Prefs
   1/*
   2 * SiFive System-on-Chip general purpose input/output register definition
   3 *
   4 * Copyright 2019 AdaCore
   5 *
   6 * Base on nrf51_gpio.c:
   7 *
   8 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
   9 *
  10 * This code is licensed under the GPL version 2 or later.  See
  11 * the COPYING file in the top-level directory.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qemu/log.h"
  16#include "hw/irq.h"
  17#include "hw/qdev-properties.h"
  18#include "hw/gpio/sifive_gpio.h"
  19#include "migration/vmstate.h"
  20#include "trace.h"
  21
  22static void update_output_irq(SIFIVEGPIOState *s)
  23{
  24    uint32_t pending;
  25    uint32_t pin;
  26
  27    pending = s->high_ip & s->high_ie;
  28    pending |= s->low_ip & s->low_ie;
  29    pending |= s->rise_ip & s->rise_ie;
  30    pending |= s->fall_ip & s->fall_ie;
  31
  32    for (int i = 0; i < s->ngpio; i++) {
  33        pin = 1 << i;
  34        qemu_set_irq(s->irq[i], (pending & pin) != 0);
  35        trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
  36    }
  37}
  38
  39static void update_state(SIFIVEGPIOState *s)
  40{
  41    size_t i;
  42    bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
  43        rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
  44
  45    for (i = 0; i < s->ngpio; i++) {
  46
  47        prev_ival = extract32(s->value, i, 1);
  48        in        = extract32(s->in, i, 1);
  49        in_mask   = extract32(s->in_mask, i, 1);
  50        port      = extract32(s->port, i, 1);
  51        out_xor   = extract32(s->out_xor, i, 1);
  52        pull      = extract32(s->pue, i, 1);
  53        output_en = extract32(s->output_en, i, 1);
  54        input_en  = extract32(s->input_en, i, 1);
  55        rise_ip   = extract32(s->rise_ip, i, 1);
  56        fall_ip   = extract32(s->fall_ip, i, 1);
  57        low_ip    = extract32(s->low_ip, i, 1);
  58        high_ip   = extract32(s->high_ip, i, 1);
  59
  60        /* Output value (IOF not supported) */
  61        oval = output_en && (port ^ out_xor);
  62
  63        /* Pin both driven externally and internally */
  64        if (output_en && in_mask) {
  65            qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
  66        }
  67
  68        if (in_mask) {
  69            /* The pin is driven by external device */
  70            actual_value = in;
  71        } else if (output_en) {
  72            /* The pin is driven by internal circuit */
  73            actual_value = oval;
  74        } else {
  75            /* Floating? Apply pull-up resistor */
  76            actual_value = pull;
  77        }
  78
  79        if (output_en) {
  80            qemu_set_irq(s->output[i], actual_value);
  81        }
  82
  83        /* Input value */
  84        ival = input_en && actual_value;
  85
  86        /* Interrupts */
  87        high_ip = high_ip || ival;
  88        s->high_ip = deposit32(s->high_ip, i, 1, high_ip);
  89
  90        low_ip = low_ip || !ival;
  91        s->low_ip = deposit32(s->low_ip,  i, 1, low_ip);
  92
  93        rise_ip = rise_ip || (ival && !prev_ival);
  94        s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip);
  95
  96        fall_ip = fall_ip || (!ival && prev_ival);
  97        s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip);
  98
  99        /* Update value */
 100        s->value = deposit32(s->value, i, 1, ival);
 101    }
 102    update_output_irq(s);
 103}
 104
 105static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
 106{
 107    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
 108    uint64_t r = 0;
 109
 110    switch (offset) {
 111    case SIFIVE_GPIO_REG_VALUE:
 112        r = s->value;
 113        break;
 114
 115    case SIFIVE_GPIO_REG_INPUT_EN:
 116        r = s->input_en;
 117        break;
 118
 119    case SIFIVE_GPIO_REG_OUTPUT_EN:
 120        r = s->output_en;
 121        break;
 122
 123    case SIFIVE_GPIO_REG_PORT:
 124        r = s->port;
 125        break;
 126
 127    case SIFIVE_GPIO_REG_PUE:
 128        r = s->pue;
 129        break;
 130
 131    case SIFIVE_GPIO_REG_DS:
 132        r = s->ds;
 133        break;
 134
 135    case SIFIVE_GPIO_REG_RISE_IE:
 136        r = s->rise_ie;
 137        break;
 138
 139    case SIFIVE_GPIO_REG_RISE_IP:
 140        r = s->rise_ip;
 141        break;
 142
 143    case SIFIVE_GPIO_REG_FALL_IE:
 144        r = s->fall_ie;
 145        break;
 146
 147    case SIFIVE_GPIO_REG_FALL_IP:
 148        r = s->fall_ip;
 149        break;
 150
 151    case SIFIVE_GPIO_REG_HIGH_IE:
 152        r = s->high_ie;
 153        break;
 154
 155    case SIFIVE_GPIO_REG_HIGH_IP:
 156        r = s->high_ip;
 157        break;
 158
 159    case SIFIVE_GPIO_REG_LOW_IE:
 160        r = s->low_ie;
 161        break;
 162
 163    case SIFIVE_GPIO_REG_LOW_IP:
 164        r = s->low_ip;
 165        break;
 166
 167    case SIFIVE_GPIO_REG_IOF_EN:
 168        r = s->iof_en;
 169        break;
 170
 171    case SIFIVE_GPIO_REG_IOF_SEL:
 172        r = s->iof_sel;
 173        break;
 174
 175    case SIFIVE_GPIO_REG_OUT_XOR:
 176        r = s->out_xor;
 177        break;
 178
 179    default:
 180        qemu_log_mask(LOG_GUEST_ERROR,
 181                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
 182                      __func__, offset);
 183    }
 184
 185    trace_sifive_gpio_read(offset, r);
 186
 187    return r;
 188}
 189
 190static void sifive_gpio_write(void *opaque, hwaddr offset,
 191                              uint64_t value, unsigned int size)
 192{
 193    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
 194
 195    trace_sifive_gpio_write(offset, value);
 196
 197    switch (offset) {
 198
 199    case SIFIVE_GPIO_REG_INPUT_EN:
 200        s->input_en = value;
 201        break;
 202
 203    case SIFIVE_GPIO_REG_OUTPUT_EN:
 204        s->output_en = value;
 205        break;
 206
 207    case SIFIVE_GPIO_REG_PORT:
 208        s->port = value;
 209        break;
 210
 211    case SIFIVE_GPIO_REG_PUE:
 212        s->pue = value;
 213        break;
 214
 215    case SIFIVE_GPIO_REG_DS:
 216        s->ds = value;
 217        break;
 218
 219    case SIFIVE_GPIO_REG_RISE_IE:
 220        s->rise_ie = value;
 221        break;
 222
 223    case SIFIVE_GPIO_REG_RISE_IP:
 224         /* Write 1 to clear */
 225        s->rise_ip &= ~value;
 226        break;
 227
 228    case SIFIVE_GPIO_REG_FALL_IE:
 229        s->fall_ie = value;
 230        break;
 231
 232    case SIFIVE_GPIO_REG_FALL_IP:
 233         /* Write 1 to clear */
 234        s->fall_ip &= ~value;
 235        break;
 236
 237    case SIFIVE_GPIO_REG_HIGH_IE:
 238        s->high_ie = value;
 239        break;
 240
 241    case SIFIVE_GPIO_REG_HIGH_IP:
 242         /* Write 1 to clear */
 243        s->high_ip &= ~value;
 244        break;
 245
 246    case SIFIVE_GPIO_REG_LOW_IE:
 247        s->low_ie = value;
 248        break;
 249
 250    case SIFIVE_GPIO_REG_LOW_IP:
 251         /* Write 1 to clear */
 252        s->low_ip &= ~value;
 253        break;
 254
 255    case SIFIVE_GPIO_REG_IOF_EN:
 256        s->iof_en = value;
 257        break;
 258
 259    case SIFIVE_GPIO_REG_IOF_SEL:
 260        s->iof_sel = value;
 261        break;
 262
 263    case SIFIVE_GPIO_REG_OUT_XOR:
 264        s->out_xor = value;
 265        break;
 266
 267    default:
 268        qemu_log_mask(LOG_GUEST_ERROR,
 269                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
 270                      __func__, offset);
 271    }
 272
 273    update_state(s);
 274}
 275
 276static const MemoryRegionOps gpio_ops = {
 277    .read =  sifive_gpio_read,
 278    .write = sifive_gpio_write,
 279    .endianness = DEVICE_LITTLE_ENDIAN,
 280    .impl.min_access_size = 4,
 281    .impl.max_access_size = 4,
 282};
 283
 284static void sifive_gpio_set(void *opaque, int line, int value)
 285{
 286    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
 287
 288    trace_sifive_gpio_set(line, value);
 289
 290    assert(line >= 0 && line < SIFIVE_GPIO_PINS);
 291
 292    s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
 293    if (value >= 0) {
 294        s->in = deposit32(s->in, line, 1, value != 0);
 295    }
 296
 297    update_state(s);
 298}
 299
 300static void sifive_gpio_reset(DeviceState *dev)
 301{
 302    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
 303
 304    s->value = 0;
 305    s->input_en = 0;
 306    s->output_en = 0;
 307    s->port = 0;
 308    s->pue = 0;
 309    s->ds = 0;
 310    s->rise_ie = 0;
 311    s->rise_ip = 0;
 312    s->fall_ie = 0;
 313    s->fall_ip = 0;
 314    s->high_ie = 0;
 315    s->high_ip = 0;
 316    s->low_ie = 0;
 317    s->low_ip = 0;
 318    s->iof_en = 0;
 319    s->iof_sel = 0;
 320    s->out_xor = 0;
 321    s->in = 0;
 322    s->in_mask = 0;
 323}
 324
 325static const VMStateDescription vmstate_sifive_gpio = {
 326    .name = TYPE_SIFIVE_GPIO,
 327    .version_id = 1,
 328    .minimum_version_id = 1,
 329    .fields = (VMStateField[]) {
 330        VMSTATE_UINT32(value,     SIFIVEGPIOState),
 331        VMSTATE_UINT32(input_en,  SIFIVEGPIOState),
 332        VMSTATE_UINT32(output_en, SIFIVEGPIOState),
 333        VMSTATE_UINT32(port,      SIFIVEGPIOState),
 334        VMSTATE_UINT32(pue,       SIFIVEGPIOState),
 335        VMSTATE_UINT32(rise_ie,   SIFIVEGPIOState),
 336        VMSTATE_UINT32(rise_ip,   SIFIVEGPIOState),
 337        VMSTATE_UINT32(fall_ie,   SIFIVEGPIOState),
 338        VMSTATE_UINT32(fall_ip,   SIFIVEGPIOState),
 339        VMSTATE_UINT32(high_ie,   SIFIVEGPIOState),
 340        VMSTATE_UINT32(high_ip,   SIFIVEGPIOState),
 341        VMSTATE_UINT32(low_ie,    SIFIVEGPIOState),
 342        VMSTATE_UINT32(low_ip,    SIFIVEGPIOState),
 343        VMSTATE_UINT32(iof_en,    SIFIVEGPIOState),
 344        VMSTATE_UINT32(iof_sel,   SIFIVEGPIOState),
 345        VMSTATE_UINT32(out_xor,   SIFIVEGPIOState),
 346        VMSTATE_UINT32(in,        SIFIVEGPIOState),
 347        VMSTATE_UINT32(in_mask,   SIFIVEGPIOState),
 348        VMSTATE_END_OF_LIST()
 349    }
 350};
 351
 352static Property sifive_gpio_properties[] = {
 353    DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
 354    DEFINE_PROP_END_OF_LIST(),
 355};
 356
 357static void sifive_gpio_realize(DeviceState *dev, Error **errp)
 358{
 359    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
 360
 361    memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
 362            TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
 363
 364    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
 365
 366    for (int i = 0; i < s->ngpio; i++) {
 367        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
 368    }
 369
 370    qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
 371    qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
 372}
 373
 374static void sifive_gpio_class_init(ObjectClass *klass, void *data)
 375{
 376    DeviceClass *dc = DEVICE_CLASS(klass);
 377
 378    device_class_set_props(dc, sifive_gpio_properties);
 379    dc->vmsd = &vmstate_sifive_gpio;
 380    dc->realize = sifive_gpio_realize;
 381    dc->reset = sifive_gpio_reset;
 382    dc->desc = "SiFive GPIO";
 383}
 384
 385static const TypeInfo sifive_gpio_info = {
 386    .name = TYPE_SIFIVE_GPIO,
 387    .parent = TYPE_SYS_BUS_DEVICE,
 388    .instance_size = sizeof(SIFIVEGPIOState),
 389    .class_init = sifive_gpio_class_init
 390};
 391
 392static void sifive_gpio_register_types(void)
 393{
 394    type_register_static(&sifive_gpio_info);
 395}
 396
 397type_init(sifive_gpio_register_types)
 398