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