qemu/hw/intc/xilinx_zynqmp_ipi.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the IPI Inter Processor Interrupt block
   3 *
   4 * Copyright (c) 2014 Xilinx Inc.
   5 *
   6 * Autogenerated by xregqemu.py 2014-09-02.
   7 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/sysbus.h"
  30#include "hw/register.h"
  31#include "qemu/bitops.h"
  32#include "qemu/log.h"
  33
  34#include "hw/fdt_generic_util.h"
  35
  36#define TYPE_XILINX_IPI "xlnx.zynqmp_ipi"
  37
  38#define XILINX_IPI(obj) \
  39     OBJECT_CHECK(IPI, (obj), TYPE_XILINX_IPI)
  40
  41#ifndef XILINX_IPI_ERR_DEBUG
  42#define XILINX_IPI_ERR_DEBUG 0
  43#endif
  44
  45#define DB_PRINT_L(lvl, fmt, args...) do {\
  46    if (XILINX_IPI_ERR_DEBUG >= lvl) {\
  47        qemu_log(TYPE_XILINX_IPI ": %s:" fmt, __func__, ## args);\
  48    } \
  49} while (0);
  50
  51#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
  52
  53REG32(IPI_TRIG, 0x0)
  54    FIELD(IPI_TRIG, PL_3, 1, 27)
  55    FIELD(IPI_TRIG, PL_2, 1, 26)
  56    FIELD(IPI_TRIG, PL_1, 1, 25)
  57    FIELD(IPI_TRIG, PL_0, 1, 24)
  58    FIELD(IPI_TRIG, PMU_3, 1, 19)
  59    FIELD(IPI_TRIG, PMU_2, 1, 18)
  60    FIELD(IPI_TRIG, PMU_1, 1, 17)
  61    FIELD(IPI_TRIG, PMU_0, 1, 16)
  62    FIELD(IPI_TRIG, RPU_1, 1, 9)
  63    FIELD(IPI_TRIG, RPU_0, 1, 8)
  64    FIELD(IPI_TRIG, APU, 1, 0)
  65REG32(IPI_OBS, 0x4)
  66    FIELD(IPI_OBS, PL_3, 1, 27)
  67    FIELD(IPI_OBS, PL_2, 1, 26)
  68    FIELD(IPI_OBS, PL_1, 1, 25)
  69    FIELD(IPI_OBS, PL_0, 1, 24)
  70    FIELD(IPI_OBS, PMU_3, 1, 19)
  71    FIELD(IPI_OBS, PMU_2, 1, 18)
  72    FIELD(IPI_OBS, PMU_1, 1, 17)
  73    FIELD(IPI_OBS, PMU_0, 1, 16)
  74    FIELD(IPI_OBS, RPU_1, 1, 9)
  75    FIELD(IPI_OBS, RPU_0, 1, 8)
  76    FIELD(IPI_OBS, APU, 1, 0)
  77REG32(IPI_ISR, 0x10)
  78    FIELD(IPI_ISR, PL_3, 1, 27)
  79    FIELD(IPI_ISR, PL_2, 1, 26)
  80    FIELD(IPI_ISR, PL_1, 1, 25)
  81    FIELD(IPI_ISR, PL_0, 1, 24)
  82    FIELD(IPI_ISR, PMU_3, 1, 19)
  83    FIELD(IPI_ISR, PMU_2, 1, 18)
  84    FIELD(IPI_ISR, PMU_1, 1, 17)
  85    FIELD(IPI_ISR, PMU_0, 1, 16)
  86    FIELD(IPI_ISR, RPU_1, 1, 9)
  87    FIELD(IPI_ISR, RPU_0, 1, 8)
  88    FIELD(IPI_ISR, APU, 1, 0)
  89REG32(IPI_IMR, 0x14)
  90    FIELD(IPI_IMR, PL_3, 1, 27)
  91    FIELD(IPI_IMR, PL_2, 1, 26)
  92    FIELD(IPI_IMR, PL_1, 1, 25)
  93    FIELD(IPI_IMR, PL_0, 1, 24)
  94    FIELD(IPI_IMR, PMU_3, 1, 19)
  95    FIELD(IPI_IMR, PMU_2, 1, 18)
  96    FIELD(IPI_IMR, PMU_1, 1, 17)
  97    FIELD(IPI_IMR, PMU_0, 1, 16)
  98    FIELD(IPI_IMR, RPU_1, 1, 9)
  99    FIELD(IPI_IMR, RPU_0, 1, 8)
 100    FIELD(IPI_IMR, APU, 1, 0)
 101REG32(IPI_IER, 0x18)
 102    FIELD(IPI_IER, PL_3, 1, 27)
 103    FIELD(IPI_IER, PL_2, 1, 26)
 104    FIELD(IPI_IER, PL_1, 1, 25)
 105    FIELD(IPI_IER, PL_0, 1, 24)
 106    FIELD(IPI_IER, PMU_3, 1, 19)
 107    FIELD(IPI_IER, PMU_2, 1, 18)
 108    FIELD(IPI_IER, PMU_1, 1, 17)
 109    FIELD(IPI_IER, PMU_0, 1, 16)
 110    FIELD(IPI_IER, RPU_1, 1, 9)
 111    FIELD(IPI_IER, RPU_0, 1, 8)
 112    FIELD(IPI_IER, APU, 1, 0)
 113REG32(IPI_IDR, 0x1c)
 114    FIELD(IPI_IDR, PL_3, 1, 27)
 115    FIELD(IPI_IDR, PL_2, 1, 26)
 116    FIELD(IPI_IDR, PL_1, 1, 25)
 117    FIELD(IPI_IDR, PL_0, 1, 24)
 118    FIELD(IPI_IDR, PMU_3, 1, 19)
 119    FIELD(IPI_IDR, PMU_2, 1, 18)
 120    FIELD(IPI_IDR, PMU_1, 1, 17)
 121    FIELD(IPI_IDR, PMU_0, 1, 16)
 122    FIELD(IPI_IDR, RPU_1, 1, 9)
 123    FIELD(IPI_IDR, RPU_0, 1, 8)
 124    FIELD(IPI_IDR, APU, 1, 0)
 125
 126#define R_MAX (R_IPI_IDR + 1)
 127
 128typedef struct IPI {
 129    SysBusDevice parent_obj;
 130    MemoryRegion iomem;
 131    qemu_irq irq;
 132
 133    uint32_t regs[R_MAX];
 134    RegisterInfo regs_info[R_MAX];
 135} IPI;
 136
 137static void ipi_update_irq(IPI *s)
 138{
 139    bool pending = s->regs[R_IPI_ISR] & ~s->regs[R_IPI_IMR];
 140    DB_PRINT("%s: irq=%d isr=%x mask=%x\n",
 141             object_get_canonical_path(OBJECT(s)),
 142             pending, s->regs[R_IPI_ISR], s->regs[R_IPI_IMR]);
 143    qemu_set_irq(s->irq, pending);
 144}
 145
 146static void ipi_isr_postw(RegisterInfo *reg, uint64_t val64)
 147{
 148    IPI *s = XILINX_IPI(reg->opaque);
 149    ipi_update_irq(s);
 150}
 151
 152static uint64_t ipi_ier_prew(RegisterInfo *reg, uint64_t val64)
 153{
 154    IPI *s = XILINX_IPI(reg->opaque);
 155    uint32_t val = val64;
 156
 157    s->regs[R_IPI_IMR] &= ~val;
 158    ipi_update_irq(s);
 159    return 0;
 160}
 161
 162static uint64_t ipi_idr_prew(RegisterInfo *reg, uint64_t val64)
 163{
 164    IPI *s = XILINX_IPI(reg->opaque);
 165    uint32_t val = val64;
 166
 167    s->regs[R_IPI_IMR] |= val;
 168    ipi_update_irq(s);
 169    return 0;
 170}
 171
 172static void ipi_trig_postw(RegisterInfo *reg, uint64_t val64) {
 173    IPI *s = XILINX_IPI(reg->opaque);
 174    uint64_t old_value = s->regs[R_IPI_TRIG];
 175
 176    /* TRIG generates a pulse on the outbound signals. We use the
 177     * post-write callback to bring the signal back-down.  */
 178    s->regs[R_IPI_TRIG] = 0;
 179    register_refresh_gpios(reg, old_value);
 180}
 181
 182#define GPIO_TRIG_OUT(x) \
 183    { .name = stringify(x), .bit_pos = R_IPI_TRIG_ ## x ## _SHIFT, .width = 1 }
 184
 185#define GPIO_OBS_OUT(x) \
 186    { .name = "OBS_" stringify(x), .bit_pos = R_IPI_ISR_ ## x ## _SHIFT, .width = 1 }
 187
 188static RegisterAccessInfo ipi_regs_info[] = {
 189    {   .name = "IPI_TRIG",  .decode.addr = A_IPI_TRIG,
 190        .rsvd = 0xf0f0fcfe,
 191        .ro = 0xf0f0fcfe,
 192        .post_write = ipi_trig_postw,
 193        .gpios = (RegisterGPIOMapping[]) {
 194            GPIO_TRIG_OUT(APU),
 195            GPIO_TRIG_OUT(RPU_0),
 196            GPIO_TRIG_OUT(RPU_1),
 197            GPIO_TRIG_OUT(PMU_0),
 198            GPIO_TRIG_OUT(PMU_1),
 199            GPIO_TRIG_OUT(PMU_2),
 200            GPIO_TRIG_OUT(PMU_3),
 201            GPIO_TRIG_OUT(PL_0),
 202            GPIO_TRIG_OUT(PL_1),
 203            GPIO_TRIG_OUT(PL_2),
 204            GPIO_TRIG_OUT(PL_3),
 205            { },
 206        }
 207    },{ .name = "IPI_OBS",  .decode.addr = A_IPI_OBS,
 208        .rsvd = 0xf0f0fcfe,
 209        .ro = 0xffffffff,
 210    },{ .name = "IPI_ISR",  .decode.addr = A_IPI_ISR,
 211        .rsvd = 0xf0f0fcfe,
 212        .ro = 0xf0f0fcfe,
 213        .w1c = 0xf0f0301,
 214        .post_write = ipi_isr_postw,
 215        .gpios = (RegisterGPIOMapping[]) {
 216            GPIO_OBS_OUT(APU),
 217            GPIO_OBS_OUT(RPU_0),
 218            GPIO_OBS_OUT(RPU_1),
 219            GPIO_OBS_OUT(PMU_0),
 220            GPIO_OBS_OUT(PMU_1),
 221            GPIO_OBS_OUT(PMU_2),
 222            GPIO_OBS_OUT(PMU_3),
 223            GPIO_OBS_OUT(PL_0),
 224            GPIO_OBS_OUT(PL_1),
 225            GPIO_OBS_OUT(PL_2),
 226            GPIO_OBS_OUT(PL_3),
 227            { },
 228        }
 229    },{ .name = "IPI_IMR",  .decode.addr = A_IPI_IMR,
 230        .reset = 0xf0f0301,
 231        .rsvd = 0xf0f0fcfe,
 232        .ro = 0xffffffff,
 233    },{ .name = "IPI_IER",  .decode.addr = A_IPI_IER,
 234        .rsvd = 0xf0f0fcfe,
 235        .ro = 0xf0f0fcfe,
 236        .pre_write = ipi_ier_prew,
 237    },{ .name = "IPI_IDR",  .decode.addr = A_IPI_IDR,
 238        .rsvd = 0xf0f0fcfe,
 239        .ro = 0xf0f0fcfe,
 240        .pre_write = ipi_idr_prew,
 241    }
 242};
 243
 244static void ipi_reset(DeviceState *dev)
 245{
 246    IPI *s = XILINX_IPI(dev);
 247    unsigned int i;
 248
 249    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 250        register_reset(&s->regs_info[i]);
 251    }
 252
 253    ipi_update_irq(s);
 254}
 255
 256static void ipi_handler(void *opaque, int n, int level)
 257{
 258    IPI *s = XILINX_IPI(opaque);
 259    RegisterInfo *r_isr = &s->regs_info[A_IPI_ISR / 4];
 260    uint32_t val = (!!level) << n;
 261    uint64_t old_value = s->regs[R_IPI_ISR];
 262
 263    DB_PRINT("%s: %s: irq[%d]=%d\n", __func__,
 264             object_get_canonical_path(OBJECT(s)), n, level);
 265
 266    s->regs[R_IPI_ISR] |= val;
 267    ipi_update_irq(s);
 268    register_refresh_gpios(r_isr, old_value);
 269}
 270
 271static void obs_handler(void *opaque, int n, int level)
 272{
 273    IPI *s = XILINX_IPI(opaque);
 274
 275    s->regs[R_IPI_OBS] &= ~(1ULL << n);
 276    s->regs[R_IPI_OBS] |= (level << n);
 277}
 278
 279static uint64_t ipi_read(void *opaque, hwaddr addr, unsigned size)
 280{
 281    IPI *s = XILINX_IPI(opaque);
 282    RegisterInfo *r = &s->regs_info[addr / 4];
 283
 284    if (!r->data) {
 285        qemu_log_mask(LOG_GUEST_ERROR,
 286                      "%s: Decode error: read from %" HWADDR_PRIx "\n",
 287                      object_get_canonical_path(OBJECT(s)), addr);
 288        return 0;
 289    }
 290    return register_read(r);
 291}
 292
 293static void ipi_write(void *opaque, hwaddr addr, uint64_t value,
 294                      unsigned size)
 295{
 296    IPI *s = XILINX_IPI(opaque);
 297    RegisterInfo *r = &s->regs_info[addr / 4];
 298
 299    if (!r->data) {
 300        qemu_log_mask(LOG_GUEST_ERROR, "%s: Decode error: write to"
 301                      " %" HWADDR_PRIx "=%" PRIx64 "\n",
 302                      object_get_canonical_path(OBJECT(s)), addr, value);
 303        return;
 304    }
 305    register_write(r, value, ~0);
 306}
 307
 308static const MemoryRegionOps ipi_ops = {
 309    .read = ipi_read,
 310    .write = ipi_write,
 311    .endianness = DEVICE_LITTLE_ENDIAN,
 312    .valid = {
 313        .min_access_size = 4,
 314        .max_access_size = 4,
 315    },
 316};
 317
 318static void ipi_realize(DeviceState *dev, Error **errp)
 319{
 320    IPI *s = XILINX_IPI(dev);
 321    const char *prefix = object_get_canonical_path(OBJECT(dev));
 322    unsigned int i;
 323
 324    for (i = 0; i < ARRAY_SIZE(ipi_regs_info); ++i) {
 325        RegisterInfo *r = &s->regs_info[ipi_regs_info[i].decode.addr/4];
 326
 327        *r = (RegisterInfo) {
 328            .data = (uint8_t *)&s->regs[
 329                    ipi_regs_info[i].decode.addr/4],
 330            .data_size = sizeof(uint32_t),
 331            .access = &ipi_regs_info[i],
 332            .debug = XILINX_IPI_ERR_DEBUG,
 333            .prefix = prefix,
 334            .opaque = s,
 335        };
 336        register_init(r);
 337        qdev_pass_all_gpios(DEVICE(r), dev);
 338    }
 339
 340    qdev_init_gpio_in_named(dev, ipi_handler, "IPI_INPUTS", 32);
 341    qdev_init_gpio_in_named(dev, obs_handler, "OBS_INPUTS", 32);
 342}
 343
 344static void ipi_init(Object *obj)
 345{
 346    IPI *s = XILINX_IPI(obj);
 347    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 348
 349    memory_region_init_io(&s->iomem, obj, &ipi_ops, s,
 350                          TYPE_XILINX_IPI, R_MAX * 4);
 351    sysbus_init_mmio(sbd, &s->iomem);
 352    sysbus_init_irq(sbd, &s->irq);
 353}
 354
 355static const VMStateDescription vmstate_ipi = {
 356    .name = TYPE_XILINX_IPI,
 357    .version_id = 1,
 358    .minimum_version_id = 1,
 359    .minimum_version_id_old = 1,
 360    .fields = (VMStateField[]) {
 361        VMSTATE_UINT32_ARRAY(regs, IPI, R_MAX),
 362        VMSTATE_END_OF_LIST(),
 363    }
 364};
 365
 366#define GPIO_FDT_TRIG_OUT(x, n)                                           \
 367    {                                                                     \
 368        .name = stringify(x),                                             \
 369        .fdt_index = n,                                                   \
 370    }
 371
 372#define GPIO_FDT_OBS_OUT(x, n)                                            \
 373    {                                                                     \
 374        .name = "OBS_" stringify(x),                                      \
 375        .fdt_index = n,                                                   \
 376    }
 377
 378static const FDTGenericGPIONameSet interrupt_gpios_names = {
 379    .propname = "interrupt-gpios",
 380    .cells_propname = "#gpio-cells",
 381    .names_propname = "gpio-names",
 382};
 383
 384static const FDTGenericGPIOSet ipi_ctrl_gpios[] = {
 385    {
 386      .names = &fdt_generic_gpio_name_set_gpio,
 387      .gpios = (FDTGenericGPIOConnection[]) {
 388        { .name = "IPI_INPUTS", .fdt_index = 0, .range = 32 },
 389        { .name = "OBS_INPUTS", .fdt_index = 32, .range = 32 },
 390        { },
 391      },
 392    },
 393    { },
 394};
 395
 396static const FDTGenericGPIOSet ipi_client_gpios[] = {
 397    {
 398        .names = &interrupt_gpios_names,
 399        .gpios = (FDTGenericGPIOConnection[]) {
 400            GPIO_FDT_TRIG_OUT(APU, 0),
 401            GPIO_FDT_TRIG_OUT(RPU_0, 1),
 402            GPIO_FDT_TRIG_OUT(RPU_1, 2),
 403            GPIO_FDT_TRIG_OUT(PMU_0, 3),
 404            GPIO_FDT_TRIG_OUT(PMU_1, 4),
 405            GPIO_FDT_TRIG_OUT(PMU_2, 5),
 406            GPIO_FDT_TRIG_OUT(PMU_3, 6),
 407            GPIO_FDT_TRIG_OUT(PL_0, 7),
 408            GPIO_FDT_TRIG_OUT(PL_1, 8),
 409            GPIO_FDT_TRIG_OUT(PL_2, 9),
 410            GPIO_FDT_TRIG_OUT(PL_3, 10),
 411        }
 412    },
 413    {
 414        .names = &fdt_generic_gpio_name_set_gpio,
 415        .gpios = (FDTGenericGPIOConnection[]) {
 416            GPIO_FDT_OBS_OUT(APU, 0),
 417            GPIO_FDT_OBS_OUT(RPU_0, 1),
 418            GPIO_FDT_OBS_OUT(RPU_1, 2),
 419            GPIO_FDT_OBS_OUT(PMU_0, 3),
 420            GPIO_FDT_OBS_OUT(PMU_1, 4),
 421            GPIO_FDT_OBS_OUT(PMU_2, 5),
 422            GPIO_FDT_OBS_OUT(PMU_3, 6),
 423            GPIO_FDT_OBS_OUT(PL_0, 7),
 424            GPIO_FDT_OBS_OUT(PL_1, 8),
 425            GPIO_FDT_OBS_OUT(PL_2, 9),
 426            GPIO_FDT_OBS_OUT(PL_3, 10),
 427        }
 428    },
 429    { },
 430};
 431
 432static void ipi_class_init(ObjectClass *klass, void *data)
 433{
 434    DeviceClass *dc = DEVICE_CLASS(klass);
 435    FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
 436
 437    dc->reset = ipi_reset;
 438    dc->realize = ipi_realize;
 439    dc->vmsd = &vmstate_ipi;
 440    fggc->controller_gpios = ipi_ctrl_gpios;
 441    fggc->client_gpios = ipi_client_gpios;
 442}
 443
 444static const TypeInfo ipi_info = {
 445    .name          = TYPE_XILINX_IPI,
 446    .parent        = TYPE_SYS_BUS_DEVICE,
 447    .instance_size = sizeof(IPI),
 448    .class_init    = ipi_class_init,
 449    .instance_init = ipi_init,
 450    .interfaces    = (InterfaceInfo[]) {
 451        { TYPE_FDT_GENERIC_GPIO },
 452        { }
 453    },
 454};
 455
 456static void ipi_register_types(void)
 457{
 458    type_register_static(&ipi_info);
 459}
 460
 461type_init(ipi_register_types)
 462