qemu/hw/gpio/imx_gpio.c
<<
>>
Prefs
   1/*
   2 * i.MX processors GPIO emulation.
   3 *
   4 * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
   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 as
   8 * published by the Free Software Foundation; either version 2 or
   9 * (at your option) version 3 of the License.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along
  17 * with this program; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "hw/gpio/imx_gpio.h"
  22
  23#ifndef DEBUG_IMX_GPIO
  24#define DEBUG_IMX_GPIO 0
  25#endif
  26
  27typedef enum IMXGPIOLevel {
  28    IMX_GPIO_LEVEL_LOW = 0,
  29    IMX_GPIO_LEVEL_HIGH = 1,
  30} IMXGPIOLevel;
  31
  32#define DPRINTF(fmt, args...) \
  33    do { \
  34        if (DEBUG_IMX_GPIO) { \
  35            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \
  36                                             __func__, ##args); \
  37        } \
  38    } while (0)
  39
  40static const char *imx_gpio_reg_name(uint32_t reg)
  41{
  42    switch (reg) {
  43    case DR_ADDR:
  44        return "DR";
  45    case GDIR_ADDR:
  46        return "GDIR";
  47    case PSR_ADDR:
  48        return "PSR";
  49    case ICR1_ADDR:
  50        return "ICR1";
  51    case ICR2_ADDR:
  52        return "ICR2";
  53    case IMR_ADDR:
  54        return "IMR";
  55    case ISR_ADDR:
  56        return "ISR";
  57    case EDGE_SEL_ADDR:
  58        return "EDGE_SEL";
  59    default:
  60        return "[?]";
  61    }
  62}
  63
  64static void imx_gpio_update_int(IMXGPIOState *s)
  65{
  66    if (s->has_upper_pin_irq) {
  67        qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
  68        qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
  69    } else {
  70        qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
  71    }
  72}
  73
  74static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
  75{
  76    /* if this signal isn't configured as an input signal, nothing to do */
  77    if (!extract32(s->gdir, line, 1)) {
  78        return;
  79    }
  80
  81    /* When set, EDGE_SEL overrides the ICR config */
  82    if (extract32(s->edge_sel, line, 1)) {
  83        /* we detect interrupt on rising and falling edge */
  84        if (extract32(s->psr, line, 1) != level) {
  85            /* level changed */
  86            s->isr = deposit32(s->isr, line, 1, 1);
  87        }
  88    } else if (extract64(s->icr, 2*line + 1, 1)) {
  89        /* interrupt is edge sensitive */
  90        if (extract32(s->psr, line, 1) != level) {
  91            /* level changed */
  92            if (extract64(s->icr, 2*line, 1) != level) {
  93                s->isr = deposit32(s->isr, line, 1, 1);
  94            }
  95        }
  96    } else {
  97        /* interrupt is level sensitive */
  98        if (extract64(s->icr, 2*line, 1) == level) {
  99            s->isr = deposit32(s->isr, line, 1, 1);
 100        }
 101    }
 102}
 103
 104static void imx_gpio_set(void *opaque, int line, int level)
 105{
 106    IMXGPIOState *s = IMX_GPIO(opaque);
 107    IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
 108
 109    imx_gpio_set_int_line(s, line, imx_level);
 110
 111    /* this is an input signal, so set PSR */
 112    s->psr = deposit32(s->psr, line, 1, imx_level);
 113
 114    imx_gpio_update_int(s);
 115}
 116
 117static void imx_gpio_set_all_int_lines(IMXGPIOState *s)
 118{
 119    int i;
 120
 121    for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
 122        IMXGPIOLevel imx_level = extract32(s->psr, i, 1);
 123        imx_gpio_set_int_line(s, i, imx_level);
 124    }
 125
 126    imx_gpio_update_int(s);
 127}
 128
 129static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s)
 130{
 131    int i;
 132
 133    for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
 134        /*
 135         * if the line is set as output, then forward the line
 136         * level to its user.
 137         */
 138        if (extract32(s->gdir, i, 1) && s->output[i]) {
 139            qemu_set_irq(s->output[i], extract32(s->dr, i, 1));
 140        }
 141    }
 142}
 143
 144static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
 145{
 146    IMXGPIOState *s = IMX_GPIO(opaque);
 147    uint32_t reg_value = 0;
 148
 149    switch (offset) {
 150    case DR_ADDR:
 151        /*
 152         * depending on the "line" configuration, the bit values
 153         * are coming either from DR or PSR
 154         */
 155        reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir);
 156        break;
 157
 158    case GDIR_ADDR:
 159        reg_value = s->gdir;
 160        break;
 161
 162    case PSR_ADDR:
 163        reg_value = s->psr & ~s->gdir;
 164        break;
 165
 166    case ICR1_ADDR:
 167        reg_value = extract64(s->icr, 0, 32);
 168        break;
 169
 170    case ICR2_ADDR:
 171        reg_value = extract64(s->icr, 32, 32);
 172        break;
 173
 174    case IMR_ADDR:
 175        reg_value = s->imr;
 176        break;
 177
 178    case ISR_ADDR:
 179        reg_value = s->isr;
 180        break;
 181
 182    case EDGE_SEL_ADDR:
 183        if (s->has_edge_sel) {
 184            reg_value = s->edge_sel;
 185        } else {
 186            qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
 187                          "present on this version of GPIO device\n",
 188                          TYPE_IMX_GPIO, __func__);
 189        }
 190        break;
 191
 192    default:
 193        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 194                      HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
 195        break;
 196    }
 197
 198    DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value);
 199
 200    return reg_value;
 201}
 202
 203static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
 204                           unsigned size)
 205{
 206    IMXGPIOState *s = IMX_GPIO(opaque);
 207
 208    DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset),
 209            (uint32_t)value);
 210
 211    switch (offset) {
 212    case DR_ADDR:
 213        s->dr = value;
 214        imx_gpio_set_all_output_lines(s);
 215        break;
 216
 217    case GDIR_ADDR:
 218        s->gdir = value;
 219        imx_gpio_set_all_output_lines(s);
 220        imx_gpio_set_all_int_lines(s);
 221        break;
 222
 223    case ICR1_ADDR:
 224        s->icr = deposit64(s->icr, 0, 32, value);
 225        imx_gpio_set_all_int_lines(s);
 226        break;
 227
 228    case ICR2_ADDR:
 229        s->icr = deposit64(s->icr, 32, 32, value);
 230        imx_gpio_set_all_int_lines(s);
 231        break;
 232
 233    case IMR_ADDR:
 234        s->imr = value;
 235        imx_gpio_update_int(s);
 236        break;
 237
 238    case ISR_ADDR:
 239        s->isr |= ~value;
 240        imx_gpio_set_all_int_lines(s);
 241        break;
 242
 243    case EDGE_SEL_ADDR:
 244        if (s->has_edge_sel) {
 245            s->edge_sel = value;
 246            imx_gpio_set_all_int_lines(s);
 247        } else {
 248            qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
 249                          "present on this version of GPIO device\n",
 250                          TYPE_IMX_GPIO, __func__);
 251        }
 252        break;
 253
 254    default:
 255        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 256                      HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
 257        break;
 258    }
 259
 260    return;
 261}
 262
 263static const MemoryRegionOps imx_gpio_ops = {
 264    .read = imx_gpio_read,
 265    .write = imx_gpio_write,
 266    .valid.min_access_size = 4,
 267    .valid.max_access_size = 4,
 268    .endianness = DEVICE_NATIVE_ENDIAN,
 269};
 270
 271static const VMStateDescription vmstate_imx_gpio = {
 272    .name = TYPE_IMX_GPIO,
 273    .version_id = 1,
 274    .minimum_version_id = 1,
 275    .minimum_version_id_old = 1,
 276    .fields = (VMStateField[]) {
 277        VMSTATE_UINT32(dr, IMXGPIOState),
 278        VMSTATE_UINT32(gdir, IMXGPIOState),
 279        VMSTATE_UINT32(psr, IMXGPIOState),
 280        VMSTATE_UINT64(icr, IMXGPIOState),
 281        VMSTATE_UINT32(imr, IMXGPIOState),
 282        VMSTATE_UINT32(isr, IMXGPIOState),
 283        VMSTATE_BOOL(has_edge_sel, IMXGPIOState),
 284        VMSTATE_UINT32(edge_sel, IMXGPIOState),
 285        VMSTATE_END_OF_LIST()
 286    }
 287};
 288
 289static Property imx_gpio_properties[] = {
 290    DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
 291    DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
 292                     false),
 293    DEFINE_PROP_END_OF_LIST(),
 294};
 295
 296static void imx_gpio_reset(DeviceState *dev)
 297{
 298    IMXGPIOState *s = IMX_GPIO(dev);
 299
 300    s->dr       = 0;
 301    s->gdir     = 0;
 302    s->psr      = 0;
 303    s->icr      = 0;
 304    s->imr      = 0;
 305    s->isr      = 0;
 306    s->edge_sel = 0;
 307
 308    imx_gpio_set_all_output_lines(s);
 309    imx_gpio_update_int(s);
 310}
 311
 312static void imx_gpio_realize(DeviceState *dev, Error **errp)
 313{
 314    IMXGPIOState *s = IMX_GPIO(dev);
 315
 316    memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s,
 317                          TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE);
 318
 319    qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
 320    qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
 321
 322    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
 323    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
 324    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
 325}
 326
 327static void imx_gpio_class_init(ObjectClass *klass, void *data)
 328{
 329    DeviceClass *dc = DEVICE_CLASS(klass);
 330
 331    dc->realize = imx_gpio_realize;
 332    dc->reset = imx_gpio_reset;
 333    dc->props = imx_gpio_properties;
 334    dc->vmsd = &vmstate_imx_gpio;
 335    dc->desc = "i.MX GPIO controller";
 336}
 337
 338static const TypeInfo imx_gpio_info = {
 339    .name = TYPE_IMX_GPIO,
 340    .parent = TYPE_SYS_BUS_DEVICE,
 341    .instance_size = sizeof(IMXGPIOState),
 342    .class_init = imx_gpio_class_init,
 343};
 344
 345static void imx_gpio_register_types(void)
 346{
 347    type_register_static(&imx_gpio_info);
 348}
 349
 350type_init(imx_gpio_register_types)
 351