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