qemu/hw/gpio/npcm7xx_gpio.c
<<
>>
Prefs
   1/*
   2 * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
   3 *
   4 * Copyright 2020 Google LLC
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include "qemu/osdep.h"
  17
  18#include "hw/gpio/npcm7xx_gpio.h"
  19#include "hw/irq.h"
  20#include "hw/qdev-properties.h"
  21#include "migration/vmstate.h"
  22#include "qapi/error.h"
  23#include "qemu/log.h"
  24#include "qemu/module.h"
  25#include "qemu/units.h"
  26#include "trace.h"
  27
  28/* 32-bit register indices. */
  29enum NPCM7xxGPIORegister {
  30    NPCM7XX_GPIO_TLOCK1,
  31    NPCM7XX_GPIO_DIN,
  32    NPCM7XX_GPIO_POL,
  33    NPCM7XX_GPIO_DOUT,
  34    NPCM7XX_GPIO_OE,
  35    NPCM7XX_GPIO_OTYP,
  36    NPCM7XX_GPIO_MP,
  37    NPCM7XX_GPIO_PU,
  38    NPCM7XX_GPIO_PD,
  39    NPCM7XX_GPIO_DBNC,
  40    NPCM7XX_GPIO_EVTYP,
  41    NPCM7XX_GPIO_EVBE,
  42    NPCM7XX_GPIO_OBL0,
  43    NPCM7XX_GPIO_OBL1,
  44    NPCM7XX_GPIO_OBL2,
  45    NPCM7XX_GPIO_OBL3,
  46    NPCM7XX_GPIO_EVEN,
  47    NPCM7XX_GPIO_EVENS,
  48    NPCM7XX_GPIO_EVENC,
  49    NPCM7XX_GPIO_EVST,
  50    NPCM7XX_GPIO_SPLCK,
  51    NPCM7XX_GPIO_MPLCK,
  52    NPCM7XX_GPIO_IEM,
  53    NPCM7XX_GPIO_OSRC,
  54    NPCM7XX_GPIO_ODSC,
  55    NPCM7XX_GPIO_DOS = 0x68 / sizeof(uint32_t),
  56    NPCM7XX_GPIO_DOC,
  57    NPCM7XX_GPIO_OES,
  58    NPCM7XX_GPIO_OEC,
  59    NPCM7XX_GPIO_TLOCK2 = 0x7c / sizeof(uint32_t),
  60    NPCM7XX_GPIO_REGS_END,
  61};
  62
  63#define NPCM7XX_GPIO_REGS_SIZE (4 * KiB)
  64
  65#define NPCM7XX_GPIO_LOCK_MAGIC1 (0xc0defa73)
  66#define NPCM7XX_GPIO_LOCK_MAGIC2 (0xc0de1248)
  67
  68static void npcm7xx_gpio_update_events(NPCM7xxGPIOState *s, uint32_t din_diff)
  69{
  70    uint32_t din_new = s->regs[NPCM7XX_GPIO_DIN];
  71
  72    /* Trigger on high level */
  73    s->regs[NPCM7XX_GPIO_EVST] |= din_new & ~s->regs[NPCM7XX_GPIO_EVTYP];
  74    /* Trigger on both edges */
  75    s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & s->regs[NPCM7XX_GPIO_EVTYP]
  76                                   & s->regs[NPCM7XX_GPIO_EVBE]);
  77    /* Trigger on rising edge */
  78    s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & din_new
  79                                   & s->regs[NPCM7XX_GPIO_EVTYP]);
  80
  81    trace_npcm7xx_gpio_update_events(DEVICE(s)->canonical_path,
  82                                     s->regs[NPCM7XX_GPIO_EVST],
  83                                     s->regs[NPCM7XX_GPIO_EVEN]);
  84    qemu_set_irq(s->irq, !!(s->regs[NPCM7XX_GPIO_EVST]
  85                            & s->regs[NPCM7XX_GPIO_EVEN]));
  86}
  87
  88static void npcm7xx_gpio_update_pins(NPCM7xxGPIOState *s, uint32_t diff)
  89{
  90    uint32_t drive_en;
  91    uint32_t drive_lvl;
  92    uint32_t not_driven;
  93    uint32_t undefined;
  94    uint32_t pin_diff;
  95    uint32_t din_old;
  96
  97    /* Calculate level of each pin driven by GPIO controller. */
  98    drive_lvl = s->regs[NPCM7XX_GPIO_DOUT] ^ s->regs[NPCM7XX_GPIO_POL];
  99    /* If OTYP=1, only drive low (open drain) */
 100    drive_en = s->regs[NPCM7XX_GPIO_OE] & ~(s->regs[NPCM7XX_GPIO_OTYP]
 101                                            & drive_lvl);
 102    /*
 103     * If a pin is driven to opposite levels by the GPIO controller and the
 104     * external driver, the result is undefined.
 105     */
 106    undefined = drive_en & s->ext_driven & (drive_lvl ^ s->ext_level);
 107    if (undefined) {
 108        qemu_log_mask(LOG_GUEST_ERROR,
 109                      "%s: pins have multiple drivers: 0x%" PRIx32 "\n",
 110                      DEVICE(s)->canonical_path, undefined);
 111    }
 112
 113    not_driven = ~(drive_en | s->ext_driven);
 114    pin_diff = s->pin_level;
 115
 116    /* Set pins to externally driven level. */
 117    s->pin_level = s->ext_level & s->ext_driven;
 118    /* Set internally driven pins, ignoring any conflicts. */
 119    s->pin_level |= drive_lvl & drive_en;
 120    /* Pull up undriven pins with internal pull-up enabled. */
 121    s->pin_level |= not_driven & s->regs[NPCM7XX_GPIO_PU];
 122    /* Pins not driven, pulled up or pulled down are undefined */
 123    undefined |= not_driven & ~(s->regs[NPCM7XX_GPIO_PU]
 124                                | s->regs[NPCM7XX_GPIO_PD]);
 125
 126    /* If any pins changed state, update the outgoing GPIOs. */
 127    pin_diff ^= s->pin_level;
 128    pin_diff |= undefined & diff;
 129    if (pin_diff) {
 130        int i;
 131
 132        for (i = 0; i < NPCM7XX_GPIO_NR_PINS; i++) {
 133            uint32_t mask = BIT(i);
 134            if (pin_diff & mask) {
 135                int level = (undefined & mask) ? -1 : !!(s->pin_level & mask);
 136                trace_npcm7xx_gpio_set_output(DEVICE(s)->canonical_path,
 137                                              i, level);
 138                qemu_set_irq(s->output[i], level);
 139            }
 140        }
 141    }
 142
 143    /* Calculate new value of DIN after masking and polarity setting. */
 144    din_old = s->regs[NPCM7XX_GPIO_DIN];
 145    s->regs[NPCM7XX_GPIO_DIN] = ((s->pin_level & s->regs[NPCM7XX_GPIO_IEM])
 146                                 ^ s->regs[NPCM7XX_GPIO_POL]);
 147
 148    /* See if any new events triggered because of all this. */
 149    npcm7xx_gpio_update_events(s, din_old ^ s->regs[NPCM7XX_GPIO_DIN]);
 150}
 151
 152static bool npcm7xx_gpio_is_locked(NPCM7xxGPIOState *s)
 153{
 154    return s->regs[NPCM7XX_GPIO_TLOCK1] == 1;
 155}
 156
 157static uint64_t npcm7xx_gpio_regs_read(void *opaque, hwaddr addr,
 158                                       unsigned int size)
 159{
 160    hwaddr reg = addr / sizeof(uint32_t);
 161    NPCM7xxGPIOState *s = opaque;
 162    uint64_t value = 0;
 163
 164    switch (reg) {
 165    case NPCM7XX_GPIO_TLOCK1 ... NPCM7XX_GPIO_EVEN:
 166    case NPCM7XX_GPIO_EVST ... NPCM7XX_GPIO_ODSC:
 167        value = s->regs[reg];
 168        break;
 169
 170    case NPCM7XX_GPIO_EVENS ... NPCM7XX_GPIO_EVENC:
 171    case NPCM7XX_GPIO_DOS ... NPCM7XX_GPIO_TLOCK2:
 172        qemu_log_mask(LOG_GUEST_ERROR,
 173                      "%s: read from write-only register 0x%" HWADDR_PRIx "\n",
 174                      DEVICE(s)->canonical_path, addr);
 175        break;
 176
 177    default:
 178        qemu_log_mask(LOG_GUEST_ERROR,
 179                      "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
 180                      DEVICE(s)->canonical_path, addr);
 181        break;
 182    }
 183
 184    trace_npcm7xx_gpio_read(DEVICE(s)->canonical_path, addr, value);
 185
 186    return value;
 187}
 188
 189static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
 190                                    unsigned int size)
 191{
 192    hwaddr reg = addr / sizeof(uint32_t);
 193    NPCM7xxGPIOState *s = opaque;
 194    uint32_t value = v;
 195    uint32_t diff;
 196
 197    trace_npcm7xx_gpio_write(DEVICE(s)->canonical_path, addr, v);
 198
 199    if (npcm7xx_gpio_is_locked(s)) {
 200        switch (reg) {
 201        case NPCM7XX_GPIO_TLOCK1:
 202            if (s->regs[NPCM7XX_GPIO_TLOCK2] == NPCM7XX_GPIO_LOCK_MAGIC2 &&
 203                value == NPCM7XX_GPIO_LOCK_MAGIC1) {
 204                s->regs[NPCM7XX_GPIO_TLOCK1] = 0;
 205                s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
 206            }
 207            break;
 208
 209        case NPCM7XX_GPIO_TLOCK2:
 210            s->regs[reg] = value;
 211            break;
 212
 213        default:
 214            qemu_log_mask(LOG_GUEST_ERROR,
 215                          "%s: write to locked register @ 0x%" HWADDR_PRIx "\n",
 216                          DEVICE(s)->canonical_path, addr);
 217            break;
 218        }
 219
 220        return;
 221    }
 222
 223    diff = s->regs[reg] ^ value;
 224
 225    switch (reg) {
 226    case NPCM7XX_GPIO_TLOCK1:
 227    case NPCM7XX_GPIO_TLOCK2:
 228        s->regs[NPCM7XX_GPIO_TLOCK1] = 1;
 229        s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
 230        break;
 231
 232    case NPCM7XX_GPIO_DIN:
 233        qemu_log_mask(LOG_GUEST_ERROR,
 234                      "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
 235                      DEVICE(s)->canonical_path, addr);
 236        break;
 237
 238    case NPCM7XX_GPIO_POL:
 239    case NPCM7XX_GPIO_DOUT:
 240    case NPCM7XX_GPIO_OE:
 241    case NPCM7XX_GPIO_OTYP:
 242    case NPCM7XX_GPIO_PU:
 243    case NPCM7XX_GPIO_PD:
 244    case NPCM7XX_GPIO_IEM:
 245        s->regs[reg] = value;
 246        npcm7xx_gpio_update_pins(s, diff);
 247        break;
 248
 249    case NPCM7XX_GPIO_DOS:
 250        s->regs[NPCM7XX_GPIO_DOUT] |= value;
 251        npcm7xx_gpio_update_pins(s, value);
 252        break;
 253    case NPCM7XX_GPIO_DOC:
 254        s->regs[NPCM7XX_GPIO_DOUT] &= ~value;
 255        npcm7xx_gpio_update_pins(s, value);
 256        break;
 257    case NPCM7XX_GPIO_OES:
 258        s->regs[NPCM7XX_GPIO_OE] |= value;
 259        npcm7xx_gpio_update_pins(s, value);
 260        break;
 261    case NPCM7XX_GPIO_OEC:
 262        s->regs[NPCM7XX_GPIO_OE] &= ~value;
 263        npcm7xx_gpio_update_pins(s, value);
 264        break;
 265
 266    case NPCM7XX_GPIO_EVTYP:
 267    case NPCM7XX_GPIO_EVBE:
 268    case NPCM7XX_GPIO_EVEN:
 269        s->regs[reg] = value;
 270        npcm7xx_gpio_update_events(s, 0);
 271        break;
 272
 273    case NPCM7XX_GPIO_EVENS:
 274        s->regs[NPCM7XX_GPIO_EVEN] |= value;
 275        npcm7xx_gpio_update_events(s, 0);
 276        break;
 277    case NPCM7XX_GPIO_EVENC:
 278        s->regs[NPCM7XX_GPIO_EVEN] &= ~value;
 279        npcm7xx_gpio_update_events(s, 0);
 280        break;
 281
 282    case NPCM7XX_GPIO_EVST:
 283        s->regs[reg] &= ~value;
 284        npcm7xx_gpio_update_events(s, 0);
 285        break;
 286
 287    case NPCM7XX_GPIO_MP:
 288    case NPCM7XX_GPIO_DBNC:
 289    case NPCM7XX_GPIO_OSRC:
 290    case NPCM7XX_GPIO_ODSC:
 291        /* Nothing to do; just store the value. */
 292        s->regs[reg] = value;
 293        break;
 294
 295    case NPCM7XX_GPIO_OBL0:
 296    case NPCM7XX_GPIO_OBL1:
 297    case NPCM7XX_GPIO_OBL2:
 298    case NPCM7XX_GPIO_OBL3:
 299        s->regs[reg] = value;
 300        qemu_log_mask(LOG_UNIMP, "%s: Blinking is not implemented\n",
 301                      __func__);
 302        break;
 303
 304    case NPCM7XX_GPIO_SPLCK:
 305    case NPCM7XX_GPIO_MPLCK:
 306        qemu_log_mask(LOG_UNIMP, "%s: Per-pin lock is not implemented\n",
 307                      __func__);
 308        break;
 309
 310    default:
 311        qemu_log_mask(LOG_GUEST_ERROR,
 312                      "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
 313                      DEVICE(s)->canonical_path, addr);
 314        break;
 315    }
 316}
 317
 318static const MemoryRegionOps npcm7xx_gpio_regs_ops = {
 319    .read = npcm7xx_gpio_regs_read,
 320    .write = npcm7xx_gpio_regs_write,
 321    .endianness = DEVICE_NATIVE_ENDIAN,
 322    .valid = {
 323        .min_access_size = 4,
 324        .max_access_size = 4,
 325        .unaligned = false,
 326    },
 327};
 328
 329static void npcm7xx_gpio_set_input(void *opaque, int line, int level)
 330{
 331    NPCM7xxGPIOState *s = opaque;
 332
 333    trace_npcm7xx_gpio_set_input(DEVICE(s)->canonical_path, line, level);
 334
 335    g_assert(line >= 0 && line < NPCM7XX_GPIO_NR_PINS);
 336
 337    s->ext_driven = deposit32(s->ext_driven, line, 1, level >= 0);
 338    s->ext_level = deposit32(s->ext_level, line, 1, level > 0);
 339
 340    npcm7xx_gpio_update_pins(s, BIT(line));
 341}
 342
 343static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
 344{
 345    NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
 346
 347    memset(s->regs, 0, sizeof(s->regs));
 348
 349    s->regs[NPCM7XX_GPIO_PU] = s->reset_pu;
 350    s->regs[NPCM7XX_GPIO_PD] = s->reset_pd;
 351    s->regs[NPCM7XX_GPIO_OSRC] = s->reset_osrc;
 352    s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
 353}
 354
 355static void npcm7xx_gpio_hold_reset(Object *obj)
 356{
 357    NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
 358
 359    npcm7xx_gpio_update_pins(s, -1);
 360}
 361
 362static void npcm7xx_gpio_init(Object *obj)
 363{
 364    NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
 365    DeviceState *dev = DEVICE(obj);
 366
 367    memory_region_init_io(&s->mmio, obj, &npcm7xx_gpio_regs_ops, s,
 368                          "regs", NPCM7XX_GPIO_REGS_SIZE);
 369    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
 370    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
 371
 372    qdev_init_gpio_in(dev, npcm7xx_gpio_set_input, NPCM7XX_GPIO_NR_PINS);
 373    qdev_init_gpio_out(dev, s->output, NPCM7XX_GPIO_NR_PINS);
 374}
 375
 376static const VMStateDescription vmstate_npcm7xx_gpio = {
 377    .name = "npcm7xx-gpio",
 378    .version_id = 0,
 379    .minimum_version_id = 0,
 380    .fields = (VMStateField[]) {
 381        VMSTATE_UINT32(pin_level, NPCM7xxGPIOState),
 382        VMSTATE_UINT32(ext_level, NPCM7xxGPIOState),
 383        VMSTATE_UINT32(ext_driven, NPCM7xxGPIOState),
 384        VMSTATE_UINT32_ARRAY(regs, NPCM7xxGPIOState, NPCM7XX_GPIO_NR_REGS),
 385        VMSTATE_END_OF_LIST(),
 386    },
 387};
 388
 389static Property npcm7xx_gpio_properties[] = {
 390    /* Bit n set => pin n has pullup enabled by default. */
 391    DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
 392    /* Bit n set => pin n has pulldown enabled by default. */
 393    DEFINE_PROP_UINT32("reset-pulldown", NPCM7xxGPIOState, reset_pd, 0),
 394    /* Bit n set => pin n has high slew rate by default. */
 395    DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
 396    /* Bit n set => pin n has high drive strength by default. */
 397    DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
 398    DEFINE_PROP_END_OF_LIST(),
 399};
 400
 401static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
 402{
 403    ResettableClass *reset = RESETTABLE_CLASS(klass);
 404    DeviceClass *dc = DEVICE_CLASS(klass);
 405
 406    QEMU_BUILD_BUG_ON(NPCM7XX_GPIO_REGS_END > NPCM7XX_GPIO_NR_REGS);
 407
 408    dc->desc = "NPCM7xx GPIO Controller";
 409    dc->vmsd = &vmstate_npcm7xx_gpio;
 410    reset->phases.enter = npcm7xx_gpio_enter_reset;
 411    reset->phases.hold = npcm7xx_gpio_hold_reset;
 412    device_class_set_props(dc, npcm7xx_gpio_properties);
 413}
 414
 415static const TypeInfo npcm7xx_gpio_types[] = {
 416    {
 417        .name = TYPE_NPCM7XX_GPIO,
 418        .parent = TYPE_SYS_BUS_DEVICE,
 419        .instance_size = sizeof(NPCM7xxGPIOState),
 420        .class_init = npcm7xx_gpio_class_init,
 421        .instance_init = npcm7xx_gpio_init,
 422    },
 423};
 424DEFINE_TYPES(npcm7xx_gpio_types);
 425