1*0ca9fa2eSStafford Horne /* 2*0ca9fa2eSStafford Horne * This file is subject to the terms and conditions of the GNU General Public 3*0ca9fa2eSStafford Horne * License. See the file "COPYING" in the main directory of this archive 4*0ca9fa2eSStafford Horne * for more details. 5*0ca9fa2eSStafford Horne * 6*0ca9fa2eSStafford Horne * Authors: Stafford Horne <shorne@gmail.com> 7*0ca9fa2eSStafford Horne */ 8*0ca9fa2eSStafford Horne 9*0ca9fa2eSStafford Horne #include "qemu/osdep.h" 10*0ca9fa2eSStafford Horne #include "qemu/log.h" 11*0ca9fa2eSStafford Horne #include "qapi/error.h" 12*0ca9fa2eSStafford Horne #include "hw/hw.h" 13*0ca9fa2eSStafford Horne #include "hw/sysbus.h" 14*0ca9fa2eSStafford Horne #include "exec/memory.h" 15*0ca9fa2eSStafford Horne 16*0ca9fa2eSStafford Horne #define TYPE_OR1K_OMPIC "or1k-ompic" 17*0ca9fa2eSStafford Horne #define OR1K_OMPIC(obj) OBJECT_CHECK(OR1KOMPICState, (obj), TYPE_OR1K_OMPIC) 18*0ca9fa2eSStafford Horne 19*0ca9fa2eSStafford Horne #define OMPIC_CTRL_IRQ_ACK (1 << 31) 20*0ca9fa2eSStafford Horne #define OMPIC_CTRL_IRQ_GEN (1 << 30) 21*0ca9fa2eSStafford Horne #define OMPIC_CTRL_DST(cpu) (((cpu) >> 16) & 0x3fff) 22*0ca9fa2eSStafford Horne 23*0ca9fa2eSStafford Horne #define OMPIC_REG(addr) (((addr) >> 2) & 0x1) 24*0ca9fa2eSStafford Horne #define OMPIC_SRC_CPU(addr) (((addr) >> 3) & 0x4f) 25*0ca9fa2eSStafford Horne #define OMPIC_DST_CPU(addr) (((addr) >> 3) & 0x4f) 26*0ca9fa2eSStafford Horne 27*0ca9fa2eSStafford Horne #define OMPIC_STATUS_IRQ_PENDING (1 << 30) 28*0ca9fa2eSStafford Horne #define OMPIC_STATUS_SRC(cpu) (((cpu) & 0x3fff) << 16) 29*0ca9fa2eSStafford Horne #define OMPIC_STATUS_DATA(data) ((data) & 0xffff) 30*0ca9fa2eSStafford Horne 31*0ca9fa2eSStafford Horne #define OMPIC_CONTROL 0 32*0ca9fa2eSStafford Horne #define OMPIC_STATUS 1 33*0ca9fa2eSStafford Horne 34*0ca9fa2eSStafford Horne #define OMPIC_MAX_CPUS 4 /* Real max is much higher, but dont waste memory */ 35*0ca9fa2eSStafford Horne #define OMPIC_ADDRSPACE_SZ (OMPIC_MAX_CPUS * 2 * 4) /* 2 32-bit regs per cpu */ 36*0ca9fa2eSStafford Horne 37*0ca9fa2eSStafford Horne typedef struct OR1KOMPICState OR1KOMPICState; 38*0ca9fa2eSStafford Horne typedef struct OR1KOMPICCPUState OR1KOMPICCPUState; 39*0ca9fa2eSStafford Horne 40*0ca9fa2eSStafford Horne struct OR1KOMPICCPUState { 41*0ca9fa2eSStafford Horne qemu_irq irq; 42*0ca9fa2eSStafford Horne uint32_t status; 43*0ca9fa2eSStafford Horne uint32_t control; 44*0ca9fa2eSStafford Horne }; 45*0ca9fa2eSStafford Horne 46*0ca9fa2eSStafford Horne struct OR1KOMPICState { 47*0ca9fa2eSStafford Horne SysBusDevice parent_obj; 48*0ca9fa2eSStafford Horne MemoryRegion mr; 49*0ca9fa2eSStafford Horne 50*0ca9fa2eSStafford Horne OR1KOMPICCPUState cpus[OMPIC_MAX_CPUS]; 51*0ca9fa2eSStafford Horne 52*0ca9fa2eSStafford Horne uint32_t num_cpus; 53*0ca9fa2eSStafford Horne }; 54*0ca9fa2eSStafford Horne 55*0ca9fa2eSStafford Horne static uint64_t ompic_read(void *opaque, hwaddr addr, unsigned size) 56*0ca9fa2eSStafford Horne { 57*0ca9fa2eSStafford Horne OR1KOMPICState *s = opaque; 58*0ca9fa2eSStafford Horne int src_cpu = OMPIC_SRC_CPU(addr); 59*0ca9fa2eSStafford Horne 60*0ca9fa2eSStafford Horne /* We can only write to control control, write control + update status */ 61*0ca9fa2eSStafford Horne if (OMPIC_REG(addr) == OMPIC_CONTROL) { 62*0ca9fa2eSStafford Horne return s->cpus[src_cpu].control; 63*0ca9fa2eSStafford Horne } else { 64*0ca9fa2eSStafford Horne return s->cpus[src_cpu].status; 65*0ca9fa2eSStafford Horne } 66*0ca9fa2eSStafford Horne 67*0ca9fa2eSStafford Horne } 68*0ca9fa2eSStafford Horne 69*0ca9fa2eSStafford Horne static void ompic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) 70*0ca9fa2eSStafford Horne { 71*0ca9fa2eSStafford Horne OR1KOMPICState *s = opaque; 72*0ca9fa2eSStafford Horne /* We can only write to control control, write control + update status */ 73*0ca9fa2eSStafford Horne if (OMPIC_REG(addr) == OMPIC_CONTROL) { 74*0ca9fa2eSStafford Horne int src_cpu = OMPIC_SRC_CPU(addr); 75*0ca9fa2eSStafford Horne 76*0ca9fa2eSStafford Horne s->cpus[src_cpu].control = data; 77*0ca9fa2eSStafford Horne 78*0ca9fa2eSStafford Horne if (data & OMPIC_CTRL_IRQ_GEN) { 79*0ca9fa2eSStafford Horne int dst_cpu = OMPIC_CTRL_DST(data); 80*0ca9fa2eSStafford Horne 81*0ca9fa2eSStafford Horne s->cpus[dst_cpu].status = OMPIC_STATUS_IRQ_PENDING | 82*0ca9fa2eSStafford Horne OMPIC_STATUS_SRC(src_cpu) | 83*0ca9fa2eSStafford Horne OMPIC_STATUS_DATA(data); 84*0ca9fa2eSStafford Horne 85*0ca9fa2eSStafford Horne qemu_irq_raise(s->cpus[dst_cpu].irq); 86*0ca9fa2eSStafford Horne } 87*0ca9fa2eSStafford Horne if (data & OMPIC_CTRL_IRQ_ACK) { 88*0ca9fa2eSStafford Horne s->cpus[src_cpu].status &= ~OMPIC_STATUS_IRQ_PENDING; 89*0ca9fa2eSStafford Horne qemu_irq_lower(s->cpus[src_cpu].irq); 90*0ca9fa2eSStafford Horne } 91*0ca9fa2eSStafford Horne } 92*0ca9fa2eSStafford Horne } 93*0ca9fa2eSStafford Horne 94*0ca9fa2eSStafford Horne static const MemoryRegionOps ompic_ops = { 95*0ca9fa2eSStafford Horne .read = ompic_read, 96*0ca9fa2eSStafford Horne .write = ompic_write, 97*0ca9fa2eSStafford Horne .endianness = DEVICE_NATIVE_ENDIAN, 98*0ca9fa2eSStafford Horne .impl = { 99*0ca9fa2eSStafford Horne .max_access_size = 8, 100*0ca9fa2eSStafford Horne }, 101*0ca9fa2eSStafford Horne }; 102*0ca9fa2eSStafford Horne 103*0ca9fa2eSStafford Horne static void or1k_ompic_init(Object *obj) 104*0ca9fa2eSStafford Horne { 105*0ca9fa2eSStafford Horne SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 106*0ca9fa2eSStafford Horne OR1KOMPICState *s = OR1K_OMPIC(obj); 107*0ca9fa2eSStafford Horne 108*0ca9fa2eSStafford Horne memory_region_init_io(&s->mr, OBJECT(s), &ompic_ops, s, 109*0ca9fa2eSStafford Horne "or1k-ompic", OMPIC_ADDRSPACE_SZ); 110*0ca9fa2eSStafford Horne sysbus_init_mmio(sbd, &s->mr); 111*0ca9fa2eSStafford Horne } 112*0ca9fa2eSStafford Horne 113*0ca9fa2eSStafford Horne static void or1k_ompic_realize(DeviceState *dev, Error **errp) 114*0ca9fa2eSStafford Horne { 115*0ca9fa2eSStafford Horne OR1KOMPICState *s = OR1K_OMPIC(dev); 116*0ca9fa2eSStafford Horne SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 117*0ca9fa2eSStafford Horne int i; 118*0ca9fa2eSStafford Horne 119*0ca9fa2eSStafford Horne if (s->num_cpus > OMPIC_MAX_CPUS) { 120*0ca9fa2eSStafford Horne error_setg(errp, "Exceeded maximum CPUs %d", s->num_cpus); 121*0ca9fa2eSStafford Horne return; 122*0ca9fa2eSStafford Horne } 123*0ca9fa2eSStafford Horne /* Init IRQ sources for all CPUs */ 124*0ca9fa2eSStafford Horne for (i = 0; i < s->num_cpus; i++) { 125*0ca9fa2eSStafford Horne sysbus_init_irq(sbd, &s->cpus[i].irq); 126*0ca9fa2eSStafford Horne } 127*0ca9fa2eSStafford Horne } 128*0ca9fa2eSStafford Horne 129*0ca9fa2eSStafford Horne static Property or1k_ompic_properties[] = { 130*0ca9fa2eSStafford Horne DEFINE_PROP_UINT32("num-cpus", OR1KOMPICState, num_cpus, 1), 131*0ca9fa2eSStafford Horne DEFINE_PROP_END_OF_LIST(), 132*0ca9fa2eSStafford Horne }; 133*0ca9fa2eSStafford Horne 134*0ca9fa2eSStafford Horne static const VMStateDescription vmstate_or1k_ompic_cpu = { 135*0ca9fa2eSStafford Horne .name = "or1k_ompic_cpu", 136*0ca9fa2eSStafford Horne .version_id = 1, 137*0ca9fa2eSStafford Horne .minimum_version_id = 1, 138*0ca9fa2eSStafford Horne .fields = (VMStateField[]) { 139*0ca9fa2eSStafford Horne VMSTATE_UINT32(status, OR1KOMPICCPUState), 140*0ca9fa2eSStafford Horne VMSTATE_UINT32(control, OR1KOMPICCPUState), 141*0ca9fa2eSStafford Horne VMSTATE_END_OF_LIST() 142*0ca9fa2eSStafford Horne } 143*0ca9fa2eSStafford Horne }; 144*0ca9fa2eSStafford Horne 145*0ca9fa2eSStafford Horne static const VMStateDescription vmstate_or1k_ompic = { 146*0ca9fa2eSStafford Horne .name = TYPE_OR1K_OMPIC, 147*0ca9fa2eSStafford Horne .version_id = 1, 148*0ca9fa2eSStafford Horne .minimum_version_id = 1, 149*0ca9fa2eSStafford Horne .fields = (VMStateField[]) { 150*0ca9fa2eSStafford Horne VMSTATE_STRUCT_ARRAY(cpus, OR1KOMPICState, OMPIC_MAX_CPUS, 1, 151*0ca9fa2eSStafford Horne vmstate_or1k_ompic_cpu, OR1KOMPICCPUState), 152*0ca9fa2eSStafford Horne VMSTATE_UINT32(num_cpus, OR1KOMPICState), 153*0ca9fa2eSStafford Horne VMSTATE_END_OF_LIST() 154*0ca9fa2eSStafford Horne } 155*0ca9fa2eSStafford Horne }; 156*0ca9fa2eSStafford Horne 157*0ca9fa2eSStafford Horne static void or1k_ompic_class_init(ObjectClass *klass, void *data) 158*0ca9fa2eSStafford Horne { 159*0ca9fa2eSStafford Horne DeviceClass *dc = DEVICE_CLASS(klass); 160*0ca9fa2eSStafford Horne 161*0ca9fa2eSStafford Horne dc->props = or1k_ompic_properties; 162*0ca9fa2eSStafford Horne dc->realize = or1k_ompic_realize; 163*0ca9fa2eSStafford Horne dc->vmsd = &vmstate_or1k_ompic; 164*0ca9fa2eSStafford Horne } 165*0ca9fa2eSStafford Horne 166*0ca9fa2eSStafford Horne static const TypeInfo or1k_ompic_info = { 167*0ca9fa2eSStafford Horne .name = TYPE_OR1K_OMPIC, 168*0ca9fa2eSStafford Horne .parent = TYPE_SYS_BUS_DEVICE, 169*0ca9fa2eSStafford Horne .instance_size = sizeof(OR1KOMPICState), 170*0ca9fa2eSStafford Horne .instance_init = or1k_ompic_init, 171*0ca9fa2eSStafford Horne .class_init = or1k_ompic_class_init, 172*0ca9fa2eSStafford Horne }; 173*0ca9fa2eSStafford Horne 174*0ca9fa2eSStafford Horne static void or1k_ompic_register_types(void) 175*0ca9fa2eSStafford Horne { 176*0ca9fa2eSStafford Horne type_register_static(&or1k_ompic_info); 177*0ca9fa2eSStafford Horne } 178*0ca9fa2eSStafford Horne 179*0ca9fa2eSStafford Horne type_init(or1k_ompic_register_types) 180