qemu/hw/intc/imx_avic.c
<<
>>
Prefs
   1/*
   2 * i.MX31 Vectored Interrupt Controller
   3 *
   4 * Note this is NOT the PL192 provided by ARM, but
   5 * a custom implementation by Freescale.
   6 *
   7 * Copyright (c) 2008 OKL
   8 * Copyright (c) 2011 NICTA Pty Ltd
   9 * Originally written by Hans Jiang
  10 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
  11 *
  12 * This code is licensed under the GPL version 2 or later.  See
  13 * the COPYING file in the top-level directory.
  14 *
  15 * TODO: implement vectors.
  16 */
  17
  18#include "qemu/osdep.h"
  19#include "hw/intc/imx_avic.h"
  20
  21#ifndef DEBUG_IMX_AVIC
  22#define DEBUG_IMX_AVIC 0
  23#endif
  24
  25#define DPRINTF(fmt, args...) \
  26    do { \
  27        if (DEBUG_IMX_AVIC) { \
  28            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \
  29                                             __func__, ##args); \
  30        } \
  31    } while (0)
  32
  33static const VMStateDescription vmstate_imx_avic = {
  34    .name = TYPE_IMX_AVIC,
  35    .version_id = 1,
  36    .minimum_version_id = 1,
  37    .fields = (VMStateField[]) {
  38        VMSTATE_UINT64(pending, IMXAVICState),
  39        VMSTATE_UINT64(enabled, IMXAVICState),
  40        VMSTATE_UINT64(is_fiq, IMXAVICState),
  41        VMSTATE_UINT32(intcntl, IMXAVICState),
  42        VMSTATE_UINT32(intmask, IMXAVICState),
  43        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
  44        VMSTATE_END_OF_LIST()
  45    },
  46};
  47
  48static inline int imx_avic_prio(IMXAVICState *s, int irq)
  49{
  50    uint32_t word = irq / PRIO_PER_WORD;
  51    uint32_t part = 4 * (irq % PRIO_PER_WORD);
  52    return 0xf & (s->prio[word] >> part);
  53}
  54
  55/* Update interrupts.  */
  56static void imx_avic_update(IMXAVICState *s)
  57{
  58    int i;
  59    uint64_t new = s->pending & s->enabled;
  60    uint64_t flags;
  61
  62    flags = new & s->is_fiq;
  63    qemu_set_irq(s->fiq, !!flags);
  64
  65    flags = new & ~s->is_fiq;
  66    if (!flags || (s->intmask == 0x1f)) {
  67        qemu_set_irq(s->irq, !!flags);
  68        return;
  69    }
  70
  71    /*
  72     * Take interrupt if there's a pending interrupt with
  73     * priority higher than the value of intmask
  74     */
  75    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
  76        if (flags & (1UL << i)) {
  77            if (imx_avic_prio(s, i) > s->intmask) {
  78                qemu_set_irq(s->irq, 1);
  79                return;
  80            }
  81        }
  82    }
  83    qemu_set_irq(s->irq, 0);
  84}
  85
  86static void imx_avic_set_irq(void *opaque, int irq, int level)
  87{
  88    IMXAVICState *s = (IMXAVICState *)opaque;
  89
  90    if (level) {
  91        DPRINTF("Raising IRQ %d, prio %d\n",
  92                irq, imx_avic_prio(s, irq));
  93        s->pending |= (1ULL << irq);
  94    } else {
  95        DPRINTF("Clearing IRQ %d, prio %d\n",
  96                irq, imx_avic_prio(s, irq));
  97        s->pending &= ~(1ULL << irq);
  98    }
  99
 100    imx_avic_update(s);
 101}
 102
 103
 104static uint64_t imx_avic_read(void *opaque,
 105                             hwaddr offset, unsigned size)
 106{
 107    IMXAVICState *s = (IMXAVICState *)opaque;
 108
 109    DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset);
 110
 111    switch (offset >> 2) {
 112    case 0: /* INTCNTL */
 113        return s->intcntl;
 114
 115    case 1: /* Normal Interrupt Mask Register, NIMASK */
 116        return s->intmask;
 117
 118    case 2: /* Interrupt Enable Number Register, INTENNUM */
 119    case 3: /* Interrupt Disable Number Register, INTDISNUM */
 120        return 0;
 121
 122    case 4: /* Interrupt Enabled Number Register High */
 123        return s->enabled >> 32;
 124
 125    case 5: /* Interrupt Enabled Number Register Low */
 126        return s->enabled & 0xffffffffULL;
 127
 128    case 6: /* Interrupt Type Register High */
 129        return s->is_fiq >> 32;
 130
 131    case 7: /* Interrupt Type Register Low */
 132        return s->is_fiq & 0xffffffffULL;
 133
 134    case 8: /* Normal Interrupt Priority Register 7 */
 135    case 9: /* Normal Interrupt Priority Register 6 */
 136    case 10:/* Normal Interrupt Priority Register 5 */
 137    case 11:/* Normal Interrupt Priority Register 4 */
 138    case 12:/* Normal Interrupt Priority Register 3 */
 139    case 13:/* Normal Interrupt Priority Register 2 */
 140    case 14:/* Normal Interrupt Priority Register 1 */
 141    case 15:/* Normal Interrupt Priority Register 0 */
 142        return s->prio[15-(offset>>2)];
 143
 144    case 16: /* Normal interrupt vector and status register */
 145    {
 146        /*
 147         * This returns the highest priority
 148         * outstanding interrupt.  Where there is more than
 149         * one pending IRQ with the same priority,
 150         * take the highest numbered one.
 151         */
 152        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
 153        int i;
 154        int prio = -1;
 155        int irq = -1;
 156        for (i = 63; i >= 0; --i) {
 157            if (flags & (1ULL<<i)) {
 158                int irq_prio = imx_avic_prio(s, i);
 159                if (irq_prio > prio) {
 160                    irq = i;
 161                    prio = irq_prio;
 162                }
 163            }
 164        }
 165        if (irq >= 0) {
 166            imx_avic_set_irq(s, irq, 0);
 167            return irq << 16 | prio;
 168        }
 169        return 0xffffffffULL;
 170    }
 171    case 17:/* Fast Interrupt vector and status register */
 172    {
 173        uint64_t flags = s->pending & s->enabled & s->is_fiq;
 174        int i = ctz64(flags);
 175        if (i < 64) {
 176            imx_avic_set_irq(opaque, i, 0);
 177            return i;
 178        }
 179        return 0xffffffffULL;
 180    }
 181    case 18:/* Interrupt source register high */
 182        return s->pending >> 32;
 183
 184    case 19:/* Interrupt source register low */
 185        return s->pending & 0xffffffffULL;
 186
 187    case 20:/* Interrupt Force Register high */
 188    case 21:/* Interrupt Force Register low */
 189        return 0;
 190
 191    case 22:/* Normal Interrupt Pending Register High */
 192        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
 193
 194    case 23:/* Normal Interrupt Pending Register Low */
 195        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
 196
 197    case 24: /* Fast Interrupt Pending Register High  */
 198        return (s->pending & s->enabled & s->is_fiq) >> 32;
 199
 200    case 25: /* Fast Interrupt Pending Register Low  */
 201        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
 202
 203    case 0x40:            /* AVIC vector 0, use for WFI WAR */
 204        return 0x4;
 205
 206    default:
 207        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 208                      HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
 209        return 0;
 210    }
 211}
 212
 213static void imx_avic_write(void *opaque, hwaddr offset,
 214                          uint64_t val, unsigned size)
 215{
 216    IMXAVICState *s = (IMXAVICState *)opaque;
 217
 218    /* Vector Registers not yet supported */
 219    if (offset >= 0x100 && offset <= 0x2fc) {
 220        qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n",
 221                      TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2));
 222        return;
 223    }
 224
 225    DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val);
 226
 227    switch (offset >> 2) {
 228    case 0: /* Interrupt Control Register, INTCNTL */
 229        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
 230        if (s->intcntl & ABFEN) {
 231            s->intcntl &= ~(val & ABFLAG);
 232        }
 233        break;
 234
 235    case 1: /* Normal Interrupt Mask Register, NIMASK */
 236        s->intmask = val & 0x1f;
 237        break;
 238
 239    case 2: /* Interrupt Enable Number Register, INTENNUM */
 240        DPRINTF("enable(%d)\n", (int)val);
 241        val &= 0x3f;
 242        s->enabled |= (1ULL << val);
 243        break;
 244
 245    case 3: /* Interrupt Disable Number Register, INTDISNUM */
 246        DPRINTF("disable(%d)\n", (int)val);
 247        val &= 0x3f;
 248        s->enabled &= ~(1ULL << val);
 249        break;
 250
 251    case 4: /* Interrupt Enable Number Register High */
 252        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
 253        break;
 254
 255    case 5: /* Interrupt Enable Number Register Low */
 256        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
 257        break;
 258
 259    case 6: /* Interrupt Type Register High */
 260        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
 261        break;
 262
 263    case 7: /* Interrupt Type Register Low */
 264        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
 265        break;
 266
 267    case 8: /* Normal Interrupt Priority Register 7 */
 268    case 9: /* Normal Interrupt Priority Register 6 */
 269    case 10:/* Normal Interrupt Priority Register 5 */
 270    case 11:/* Normal Interrupt Priority Register 4 */
 271    case 12:/* Normal Interrupt Priority Register 3 */
 272    case 13:/* Normal Interrupt Priority Register 2 */
 273    case 14:/* Normal Interrupt Priority Register 1 */
 274    case 15:/* Normal Interrupt Priority Register 0 */
 275        s->prio[15-(offset>>2)] = val;
 276        break;
 277
 278        /* Read-only registers, writes ignored */
 279    case 16:/* Normal Interrupt Vector and Status register */
 280    case 17:/* Fast Interrupt vector and status register */
 281    case 18:/* Interrupt source register high */
 282    case 19:/* Interrupt source register low */
 283        return;
 284
 285    case 20:/* Interrupt Force Register high */
 286        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
 287        break;
 288
 289    case 21:/* Interrupt Force Register low */
 290        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
 291        break;
 292
 293    case 22:/* Normal Interrupt Pending Register High */
 294    case 23:/* Normal Interrupt Pending Register Low */
 295    case 24: /* Fast Interrupt Pending Register High  */
 296    case 25: /* Fast Interrupt Pending Register Low  */
 297        return;
 298
 299    default:
 300        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 301                      HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
 302    }
 303    imx_avic_update(s);
 304}
 305
 306static const MemoryRegionOps imx_avic_ops = {
 307    .read = imx_avic_read,
 308    .write = imx_avic_write,
 309    .endianness = DEVICE_NATIVE_ENDIAN,
 310};
 311
 312static void imx_avic_reset(DeviceState *dev)
 313{
 314    IMXAVICState *s = IMX_AVIC(dev);
 315
 316    s->pending = 0;
 317    s->enabled = 0;
 318    s->is_fiq = 0;
 319    s->intmask = 0x1f;
 320    s->intcntl = 0;
 321    memset(s->prio, 0, sizeof s->prio);
 322}
 323
 324static int imx_avic_init(SysBusDevice *sbd)
 325{
 326    DeviceState *dev = DEVICE(sbd);
 327    IMXAVICState *s = IMX_AVIC(dev);
 328
 329    memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s,
 330                          TYPE_IMX_AVIC, 0x1000);
 331    sysbus_init_mmio(sbd, &s->iomem);
 332
 333    qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
 334    sysbus_init_irq(sbd, &s->irq);
 335    sysbus_init_irq(sbd, &s->fiq);
 336
 337    return 0;
 338}
 339
 340
 341static void imx_avic_class_init(ObjectClass *klass, void *data)
 342{
 343    DeviceClass *dc = DEVICE_CLASS(klass);
 344    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 345    k->init = imx_avic_init;
 346    dc->vmsd = &vmstate_imx_avic;
 347    dc->reset = imx_avic_reset;
 348    dc->desc = "i.MX Advanced Vector Interrupt Controller";
 349}
 350
 351static const TypeInfo imx_avic_info = {
 352    .name = TYPE_IMX_AVIC,
 353    .parent = TYPE_SYS_BUS_DEVICE,
 354    .instance_size = sizeof(IMXAVICState),
 355    .class_init = imx_avic_class_init,
 356};
 357
 358static void imx_avic_register_types(void)
 359{
 360    type_register_static(&imx_avic_info);
 361}
 362
 363type_init(imx_avic_register_types)
 364