1*b350735eSAlistair Francis /* 2*b350735eSAlistair Francis * QEMU model of the IPI Inter Processor Interrupt block 3*b350735eSAlistair Francis * 4*b350735eSAlistair Francis * Copyright (c) 2014 Xilinx Inc. 5*b350735eSAlistair Francis * 6*b350735eSAlistair Francis * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> 7*b350735eSAlistair Francis * Written by Alistair Francis <alistair.francis@xilinx.com> 8*b350735eSAlistair Francis * 9*b350735eSAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy 10*b350735eSAlistair Francis * of this software and associated documentation files (the "Software"), to deal 11*b350735eSAlistair Francis * in the Software without restriction, including without limitation the rights 12*b350735eSAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13*b350735eSAlistair Francis * copies of the Software, and to permit persons to whom the Software is 14*b350735eSAlistair Francis * furnished to do so, subject to the following conditions: 15*b350735eSAlistair Francis * 16*b350735eSAlistair Francis * The above copyright notice and this permission notice shall be included in 17*b350735eSAlistair Francis * all copies or substantial portions of the Software. 18*b350735eSAlistair Francis * 19*b350735eSAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20*b350735eSAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21*b350735eSAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22*b350735eSAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23*b350735eSAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24*b350735eSAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25*b350735eSAlistair Francis * THE SOFTWARE. 26*b350735eSAlistair Francis */ 27*b350735eSAlistair Francis 28*b350735eSAlistair Francis #include "qemu/osdep.h" 29*b350735eSAlistair Francis #include "hw/sysbus.h" 30*b350735eSAlistair Francis #include "hw/register.h" 31*b350735eSAlistair Francis #include "qemu/bitops.h" 32*b350735eSAlistair Francis #include "qemu/log.h" 33*b350735eSAlistair Francis #include "hw/intc/xlnx-zynqmp-ipi.h" 34*b350735eSAlistair Francis 35*b350735eSAlistair Francis #ifndef XLNX_ZYNQMP_IPI_ERR_DEBUG 36*b350735eSAlistair Francis #define XLNX_ZYNQMP_IPI_ERR_DEBUG 0 37*b350735eSAlistair Francis #endif 38*b350735eSAlistair Francis 39*b350735eSAlistair Francis #define DB_PRINT_L(lvl, fmt, args...) do {\ 40*b350735eSAlistair Francis if (XLNX_ZYNQMP_IPI_ERR_DEBUG >= lvl) {\ 41*b350735eSAlistair Francis qemu_log(TYPE_XLNX_ZYNQMP_IPI ": %s:" fmt, __func__, ## args);\ 42*b350735eSAlistair Francis } \ 43*b350735eSAlistair Francis } while (0) 44*b350735eSAlistair Francis 45*b350735eSAlistair Francis #define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) 46*b350735eSAlistair Francis 47*b350735eSAlistair Francis REG32(IPI_TRIG, 0x0) 48*b350735eSAlistair Francis FIELD(IPI_TRIG, PL_3, 27, 1) 49*b350735eSAlistair Francis FIELD(IPI_TRIG, PL_2, 26, 1) 50*b350735eSAlistair Francis FIELD(IPI_TRIG, PL_1, 25, 1) 51*b350735eSAlistair Francis FIELD(IPI_TRIG, PL_0, 24, 1) 52*b350735eSAlistair Francis FIELD(IPI_TRIG, PMU_3, 19, 1) 53*b350735eSAlistair Francis FIELD(IPI_TRIG, PMU_2, 18, 1) 54*b350735eSAlistair Francis FIELD(IPI_TRIG, PMU_1, 17, 1) 55*b350735eSAlistair Francis FIELD(IPI_TRIG, PMU_0, 16, 1) 56*b350735eSAlistair Francis FIELD(IPI_TRIG, RPU_1, 9, 1) 57*b350735eSAlistair Francis FIELD(IPI_TRIG, RPU_0, 8, 1) 58*b350735eSAlistair Francis FIELD(IPI_TRIG, APU, 0, 1) 59*b350735eSAlistair Francis REG32(IPI_OBS, 0x4) 60*b350735eSAlistair Francis FIELD(IPI_OBS, PL_3, 27, 1) 61*b350735eSAlistair Francis FIELD(IPI_OBS, PL_2, 26, 1) 62*b350735eSAlistair Francis FIELD(IPI_OBS, PL_1, 25, 1) 63*b350735eSAlistair Francis FIELD(IPI_OBS, PL_0, 24, 1) 64*b350735eSAlistair Francis FIELD(IPI_OBS, PMU_3, 19, 1) 65*b350735eSAlistair Francis FIELD(IPI_OBS, PMU_2, 18, 1) 66*b350735eSAlistair Francis FIELD(IPI_OBS, PMU_1, 17, 1) 67*b350735eSAlistair Francis FIELD(IPI_OBS, PMU_0, 16, 1) 68*b350735eSAlistair Francis FIELD(IPI_OBS, RPU_1, 9, 1) 69*b350735eSAlistair Francis FIELD(IPI_OBS, RPU_0, 8, 1) 70*b350735eSAlistair Francis FIELD(IPI_OBS, APU, 0, 1) 71*b350735eSAlistair Francis REG32(IPI_ISR, 0x10) 72*b350735eSAlistair Francis FIELD(IPI_ISR, PL_3, 27, 1) 73*b350735eSAlistair Francis FIELD(IPI_ISR, PL_2, 26, 1) 74*b350735eSAlistair Francis FIELD(IPI_ISR, PL_1, 25, 1) 75*b350735eSAlistair Francis FIELD(IPI_ISR, PL_0, 24, 1) 76*b350735eSAlistair Francis FIELD(IPI_ISR, PMU_3, 19, 1) 77*b350735eSAlistair Francis FIELD(IPI_ISR, PMU_2, 18, 1) 78*b350735eSAlistair Francis FIELD(IPI_ISR, PMU_1, 17, 1) 79*b350735eSAlistair Francis FIELD(IPI_ISR, PMU_0, 16, 1) 80*b350735eSAlistair Francis FIELD(IPI_ISR, RPU_1, 9, 1) 81*b350735eSAlistair Francis FIELD(IPI_ISR, RPU_0, 8, 1) 82*b350735eSAlistair Francis FIELD(IPI_ISR, APU, 0, 1) 83*b350735eSAlistair Francis REG32(IPI_IMR, 0x14) 84*b350735eSAlistair Francis FIELD(IPI_IMR, PL_3, 27, 1) 85*b350735eSAlistair Francis FIELD(IPI_IMR, PL_2, 26, 1) 86*b350735eSAlistair Francis FIELD(IPI_IMR, PL_1, 25, 1) 87*b350735eSAlistair Francis FIELD(IPI_IMR, PL_0, 24, 1) 88*b350735eSAlistair Francis FIELD(IPI_IMR, PMU_3, 19, 1) 89*b350735eSAlistair Francis FIELD(IPI_IMR, PMU_2, 18, 1) 90*b350735eSAlistair Francis FIELD(IPI_IMR, PMU_1, 17, 1) 91*b350735eSAlistair Francis FIELD(IPI_IMR, PMU_0, 16, 1) 92*b350735eSAlistair Francis FIELD(IPI_IMR, RPU_1, 9, 1) 93*b350735eSAlistair Francis FIELD(IPI_IMR, RPU_0, 8, 1) 94*b350735eSAlistair Francis FIELD(IPI_IMR, APU, 0, 1) 95*b350735eSAlistair Francis REG32(IPI_IER, 0x18) 96*b350735eSAlistair Francis FIELD(IPI_IER, PL_3, 27, 1) 97*b350735eSAlistair Francis FIELD(IPI_IER, PL_2, 26, 1) 98*b350735eSAlistair Francis FIELD(IPI_IER, PL_1, 25, 1) 99*b350735eSAlistair Francis FIELD(IPI_IER, PL_0, 24, 1) 100*b350735eSAlistair Francis FIELD(IPI_IER, PMU_3, 19, 1) 101*b350735eSAlistair Francis FIELD(IPI_IER, PMU_2, 18, 1) 102*b350735eSAlistair Francis FIELD(IPI_IER, PMU_1, 17, 1) 103*b350735eSAlistair Francis FIELD(IPI_IER, PMU_0, 16, 1) 104*b350735eSAlistair Francis FIELD(IPI_IER, RPU_1, 9, 1) 105*b350735eSAlistair Francis FIELD(IPI_IER, RPU_0, 8, 1) 106*b350735eSAlistair Francis FIELD(IPI_IER, APU, 0, 1) 107*b350735eSAlistair Francis REG32(IPI_IDR, 0x1c) 108*b350735eSAlistair Francis FIELD(IPI_IDR, PL_3, 27, 1) 109*b350735eSAlistair Francis FIELD(IPI_IDR, PL_2, 26, 1) 110*b350735eSAlistair Francis FIELD(IPI_IDR, PL_1, 25, 1) 111*b350735eSAlistair Francis FIELD(IPI_IDR, PL_0, 24, 1) 112*b350735eSAlistair Francis FIELD(IPI_IDR, PMU_3, 19, 1) 113*b350735eSAlistair Francis FIELD(IPI_IDR, PMU_2, 18, 1) 114*b350735eSAlistair Francis FIELD(IPI_IDR, PMU_1, 17, 1) 115*b350735eSAlistair Francis FIELD(IPI_IDR, PMU_0, 16, 1) 116*b350735eSAlistair Francis FIELD(IPI_IDR, RPU_1, 9, 1) 117*b350735eSAlistair Francis FIELD(IPI_IDR, RPU_0, 8, 1) 118*b350735eSAlistair Francis FIELD(IPI_IDR, APU, 0, 1) 119*b350735eSAlistair Francis 120*b350735eSAlistair Francis /* APU 121*b350735eSAlistair Francis * RPU_0 122*b350735eSAlistair Francis * RPU_1 123*b350735eSAlistair Francis * PMU_0 124*b350735eSAlistair Francis * PMU_1 125*b350735eSAlistair Francis * PMU_2 126*b350735eSAlistair Francis * PMU_3 127*b350735eSAlistair Francis * PL_0 128*b350735eSAlistair Francis * PL_1 129*b350735eSAlistair Francis * PL_2 130*b350735eSAlistair Francis * PL_3 131*b350735eSAlistair Francis */ 132*b350735eSAlistair Francis int index_array[NUM_IPIS] = {0, 8, 9, 16, 17, 18, 19, 24, 25, 26, 27}; 133*b350735eSAlistair Francis static const char *index_array_names[NUM_IPIS] = {"APU", "RPU_0", "RPU_1", 134*b350735eSAlistair Francis "PMU_0", "PMU_1", "PMU_2", 135*b350735eSAlistair Francis "PMU_3", "PL_0", "PL_1", 136*b350735eSAlistair Francis "PL_2", "PL_3"}; 137*b350735eSAlistair Francis 138*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_set_trig(XlnxZynqMPIPI *s, uint32_t val) 139*b350735eSAlistair Francis { 140*b350735eSAlistair Francis int i, ipi_index, ipi_mask; 141*b350735eSAlistair Francis 142*b350735eSAlistair Francis for (i = 0; i < NUM_IPIS; i++) { 143*b350735eSAlistair Francis ipi_index = index_array[i]; 144*b350735eSAlistair Francis ipi_mask = (1 << ipi_index); 145*b350735eSAlistair Francis DB_PRINT("Setting %s=%d\n", index_array_names[i], 146*b350735eSAlistair Francis !!(val & ipi_mask)); 147*b350735eSAlistair Francis qemu_set_irq(s->irq_trig_out[i], !!(val & ipi_mask)); 148*b350735eSAlistair Francis } 149*b350735eSAlistair Francis } 150*b350735eSAlistair Francis 151*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_set_obs(XlnxZynqMPIPI *s, uint32_t val) 152*b350735eSAlistair Francis { 153*b350735eSAlistair Francis int i, ipi_index, ipi_mask; 154*b350735eSAlistair Francis 155*b350735eSAlistair Francis for (i = 0; i < NUM_IPIS; i++) { 156*b350735eSAlistair Francis ipi_index = index_array[i]; 157*b350735eSAlistair Francis ipi_mask = (1 << ipi_index); 158*b350735eSAlistair Francis DB_PRINT("Setting %s=%d\n", index_array_names[i], 159*b350735eSAlistair Francis !!(val & ipi_mask)); 160*b350735eSAlistair Francis qemu_set_irq(s->irq_obs_out[i], !!(val & ipi_mask)); 161*b350735eSAlistair Francis } 162*b350735eSAlistair Francis } 163*b350735eSAlistair Francis 164*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_update_irq(XlnxZynqMPIPI *s) 165*b350735eSAlistair Francis { 166*b350735eSAlistair Francis bool pending = s->regs[R_IPI_ISR] & ~s->regs[R_IPI_IMR]; 167*b350735eSAlistair Francis 168*b350735eSAlistair Francis DB_PRINT("irq=%d isr=%x mask=%x\n", 169*b350735eSAlistair Francis pending, s->regs[R_IPI_ISR], s->regs[R_IPI_IMR]); 170*b350735eSAlistair Francis qemu_set_irq(s->irq, pending); 171*b350735eSAlistair Francis } 172*b350735eSAlistair Francis 173*b350735eSAlistair Francis static uint64_t xlnx_zynqmp_ipi_trig_prew(RegisterInfo *reg, uint64_t val64) 174*b350735eSAlistair Francis { 175*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 176*b350735eSAlistair Francis 177*b350735eSAlistair Francis xlnx_zynqmp_ipi_set_trig(s, val64); 178*b350735eSAlistair Francis 179*b350735eSAlistair Francis return val64; 180*b350735eSAlistair Francis } 181*b350735eSAlistair Francis 182*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_trig_postw(RegisterInfo *reg, uint64_t val64) 183*b350735eSAlistair Francis { 184*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 185*b350735eSAlistair Francis 186*b350735eSAlistair Francis /* TRIG generates a pulse on the outbound signals. We use the 187*b350735eSAlistair Francis * post-write callback to bring the signal back-down. 188*b350735eSAlistair Francis */ 189*b350735eSAlistair Francis s->regs[R_IPI_TRIG] = 0; 190*b350735eSAlistair Francis 191*b350735eSAlistair Francis xlnx_zynqmp_ipi_set_trig(s, 0); 192*b350735eSAlistair Francis } 193*b350735eSAlistair Francis 194*b350735eSAlistair Francis static uint64_t xlnx_zynqmp_ipi_isr_prew(RegisterInfo *reg, uint64_t val64) 195*b350735eSAlistair Francis { 196*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 197*b350735eSAlistair Francis 198*b350735eSAlistair Francis xlnx_zynqmp_ipi_set_obs(s, val64); 199*b350735eSAlistair Francis 200*b350735eSAlistair Francis return val64; 201*b350735eSAlistair Francis } 202*b350735eSAlistair Francis 203*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_isr_postw(RegisterInfo *reg, uint64_t val64) 204*b350735eSAlistair Francis { 205*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 206*b350735eSAlistair Francis 207*b350735eSAlistair Francis xlnx_zynqmp_ipi_update_irq(s); 208*b350735eSAlistair Francis } 209*b350735eSAlistair Francis 210*b350735eSAlistair Francis static uint64_t xlnx_zynqmp_ipi_ier_prew(RegisterInfo *reg, uint64_t val64) 211*b350735eSAlistair Francis { 212*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 213*b350735eSAlistair Francis uint32_t val = val64; 214*b350735eSAlistair Francis 215*b350735eSAlistair Francis s->regs[R_IPI_IMR] &= ~val; 216*b350735eSAlistair Francis xlnx_zynqmp_ipi_update_irq(s); 217*b350735eSAlistair Francis return 0; 218*b350735eSAlistair Francis } 219*b350735eSAlistair Francis 220*b350735eSAlistair Francis static uint64_t xlnx_zynqmp_ipi_idr_prew(RegisterInfo *reg, uint64_t val64) 221*b350735eSAlistair Francis { 222*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(reg->opaque); 223*b350735eSAlistair Francis uint32_t val = val64; 224*b350735eSAlistair Francis 225*b350735eSAlistair Francis s->regs[R_IPI_IMR] |= val; 226*b350735eSAlistair Francis xlnx_zynqmp_ipi_update_irq(s); 227*b350735eSAlistair Francis return 0; 228*b350735eSAlistair Francis } 229*b350735eSAlistair Francis 230*b350735eSAlistair Francis static const RegisterAccessInfo xlnx_zynqmp_ipi_regs_info[] = { 231*b350735eSAlistair Francis { .name = "IPI_TRIG", .addr = A_IPI_TRIG, 232*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 233*b350735eSAlistair Francis .ro = 0xf0f0fcfe, 234*b350735eSAlistair Francis .pre_write = xlnx_zynqmp_ipi_trig_prew, 235*b350735eSAlistair Francis .post_write = xlnx_zynqmp_ipi_trig_postw, 236*b350735eSAlistair Francis },{ .name = "IPI_OBS", .addr = A_IPI_OBS, 237*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 238*b350735eSAlistair Francis .ro = 0xffffffff, 239*b350735eSAlistair Francis },{ .name = "IPI_ISR", .addr = A_IPI_ISR, 240*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 241*b350735eSAlistair Francis .ro = 0xf0f0fcfe, 242*b350735eSAlistair Francis .w1c = 0xf0f0301, 243*b350735eSAlistair Francis .pre_write = xlnx_zynqmp_ipi_isr_prew, 244*b350735eSAlistair Francis .post_write = xlnx_zynqmp_ipi_isr_postw, 245*b350735eSAlistair Francis },{ .name = "IPI_IMR", .addr = A_IPI_IMR, 246*b350735eSAlistair Francis .reset = 0xf0f0301, 247*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 248*b350735eSAlistair Francis .ro = 0xffffffff, 249*b350735eSAlistair Francis },{ .name = "IPI_IER", .addr = A_IPI_IER, 250*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 251*b350735eSAlistair Francis .ro = 0xf0f0fcfe, 252*b350735eSAlistair Francis .pre_write = xlnx_zynqmp_ipi_ier_prew, 253*b350735eSAlistair Francis },{ .name = "IPI_IDR", .addr = A_IPI_IDR, 254*b350735eSAlistair Francis .rsvd = 0xf0f0fcfe, 255*b350735eSAlistair Francis .ro = 0xf0f0fcfe, 256*b350735eSAlistair Francis .pre_write = xlnx_zynqmp_ipi_idr_prew, 257*b350735eSAlistair Francis } 258*b350735eSAlistair Francis }; 259*b350735eSAlistair Francis 260*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_reset(DeviceState *dev) 261*b350735eSAlistair Francis { 262*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(dev); 263*b350735eSAlistair Francis int i; 264*b350735eSAlistair Francis 265*b350735eSAlistair Francis for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { 266*b350735eSAlistair Francis register_reset(&s->regs_info[i]); 267*b350735eSAlistair Francis } 268*b350735eSAlistair Francis 269*b350735eSAlistair Francis xlnx_zynqmp_ipi_update_irq(s); 270*b350735eSAlistair Francis } 271*b350735eSAlistair Francis 272*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_handler(void *opaque, int n, int level) 273*b350735eSAlistair Francis { 274*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(opaque); 275*b350735eSAlistair Francis uint32_t val = (!!level) << n; 276*b350735eSAlistair Francis 277*b350735eSAlistair Francis DB_PRINT("IPI input irq[%d]=%d\n", n, level); 278*b350735eSAlistair Francis 279*b350735eSAlistair Francis s->regs[R_IPI_ISR] |= val; 280*b350735eSAlistair Francis xlnx_zynqmp_ipi_set_obs(s, s->regs[R_IPI_ISR]); 281*b350735eSAlistair Francis xlnx_zynqmp_ipi_update_irq(s); 282*b350735eSAlistair Francis } 283*b350735eSAlistair Francis 284*b350735eSAlistair Francis static void xlnx_zynqmp_obs_handler(void *opaque, int n, int level) 285*b350735eSAlistair Francis { 286*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(opaque); 287*b350735eSAlistair Francis 288*b350735eSAlistair Francis DB_PRINT("OBS input irq[%d]=%d\n", n, level); 289*b350735eSAlistair Francis 290*b350735eSAlistair Francis s->regs[R_IPI_OBS] &= ~(1ULL << n); 291*b350735eSAlistair Francis s->regs[R_IPI_OBS] |= (level << n); 292*b350735eSAlistair Francis } 293*b350735eSAlistair Francis 294*b350735eSAlistair Francis static const MemoryRegionOps xlnx_zynqmp_ipi_ops = { 295*b350735eSAlistair Francis .read = register_read_memory, 296*b350735eSAlistair Francis .write = register_write_memory, 297*b350735eSAlistair Francis .endianness = DEVICE_LITTLE_ENDIAN, 298*b350735eSAlistair Francis .valid = { 299*b350735eSAlistair Francis .min_access_size = 4, 300*b350735eSAlistair Francis .max_access_size = 4, 301*b350735eSAlistair Francis }, 302*b350735eSAlistair Francis }; 303*b350735eSAlistair Francis 304*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_realize(DeviceState *dev, Error **errp) 305*b350735eSAlistair Francis { 306*b350735eSAlistair Francis qdev_init_gpio_in_named(dev, xlnx_zynqmp_ipi_handler, "IPI_INPUTS", 32); 307*b350735eSAlistair Francis qdev_init_gpio_in_named(dev, xlnx_zynqmp_obs_handler, "OBS_INPUTS", 32); 308*b350735eSAlistair Francis } 309*b350735eSAlistair Francis 310*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_init(Object *obj) 311*b350735eSAlistair Francis { 312*b350735eSAlistair Francis XlnxZynqMPIPI *s = XLNX_ZYNQMP_IPI(obj); 313*b350735eSAlistair Francis DeviceState *dev = DEVICE(obj); 314*b350735eSAlistair Francis SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 315*b350735eSAlistair Francis RegisterInfoArray *reg_array; 316*b350735eSAlistair Francis char *irq_name; 317*b350735eSAlistair Francis int i; 318*b350735eSAlistair Francis 319*b350735eSAlistair Francis memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_IPI, 320*b350735eSAlistair Francis R_XLNX_ZYNQMP_IPI_MAX * 4); 321*b350735eSAlistair Francis reg_array = 322*b350735eSAlistair Francis register_init_block32(DEVICE(obj), xlnx_zynqmp_ipi_regs_info, 323*b350735eSAlistair Francis ARRAY_SIZE(xlnx_zynqmp_ipi_regs_info), 324*b350735eSAlistair Francis s->regs_info, s->regs, 325*b350735eSAlistair Francis &xlnx_zynqmp_ipi_ops, 326*b350735eSAlistair Francis XLNX_ZYNQMP_IPI_ERR_DEBUG, 327*b350735eSAlistair Francis R_XLNX_ZYNQMP_IPI_MAX * 4); 328*b350735eSAlistair Francis memory_region_add_subregion(&s->iomem, 329*b350735eSAlistair Francis 0x0, 330*b350735eSAlistair Francis ®_array->mem); 331*b350735eSAlistair Francis sysbus_init_mmio(sbd, &s->iomem); 332*b350735eSAlistair Francis sysbus_init_irq(sbd, &s->irq); 333*b350735eSAlistair Francis 334*b350735eSAlistair Francis for (i = 0; i < NUM_IPIS; i++) { 335*b350735eSAlistair Francis qdev_init_gpio_out_named(dev, &s->irq_trig_out[i], 336*b350735eSAlistair Francis index_array_names[i], 1); 337*b350735eSAlistair Francis 338*b350735eSAlistair Francis irq_name = g_strdup_printf("OBS_%s", index_array_names[i]); 339*b350735eSAlistair Francis qdev_init_gpio_out_named(dev, &s->irq_obs_out[i], 340*b350735eSAlistair Francis irq_name, 1); 341*b350735eSAlistair Francis g_free(irq_name); 342*b350735eSAlistair Francis } 343*b350735eSAlistair Francis } 344*b350735eSAlistair Francis 345*b350735eSAlistair Francis static const VMStateDescription vmstate_zynqmp_pmu_ipi = { 346*b350735eSAlistair Francis .name = TYPE_XLNX_ZYNQMP_IPI, 347*b350735eSAlistair Francis .version_id = 1, 348*b350735eSAlistair Francis .minimum_version_id = 1, 349*b350735eSAlistair Francis .fields = (VMStateField[]) { 350*b350735eSAlistair Francis VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPIPI, R_XLNX_ZYNQMP_IPI_MAX), 351*b350735eSAlistair Francis VMSTATE_END_OF_LIST(), 352*b350735eSAlistair Francis } 353*b350735eSAlistair Francis }; 354*b350735eSAlistair Francis 355*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, void *data) 356*b350735eSAlistair Francis { 357*b350735eSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 358*b350735eSAlistair Francis 359*b350735eSAlistair Francis dc->reset = xlnx_zynqmp_ipi_reset; 360*b350735eSAlistair Francis dc->realize = xlnx_zynqmp_ipi_realize; 361*b350735eSAlistair Francis dc->vmsd = &vmstate_zynqmp_pmu_ipi; 362*b350735eSAlistair Francis } 363*b350735eSAlistair Francis 364*b350735eSAlistair Francis static const TypeInfo xlnx_zynqmp_ipi_info = { 365*b350735eSAlistair Francis .name = TYPE_XLNX_ZYNQMP_IPI, 366*b350735eSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 367*b350735eSAlistair Francis .instance_size = sizeof(XlnxZynqMPIPI), 368*b350735eSAlistair Francis .class_init = xlnx_zynqmp_ipi_class_init, 369*b350735eSAlistair Francis .instance_init = xlnx_zynqmp_ipi_init, 370*b350735eSAlistair Francis }; 371*b350735eSAlistair Francis 372*b350735eSAlistair Francis static void xlnx_zynqmp_ipi_register_types(void) 373*b350735eSAlistair Francis { 374*b350735eSAlistair Francis type_register_static(&xlnx_zynqmp_ipi_info); 375*b350735eSAlistair Francis } 376*b350735eSAlistair Francis 377*b350735eSAlistair Francis type_init(xlnx_zynqmp_ipi_register_types) 378