10434e30aSPaolo Bonzini /* 20434e30aSPaolo Bonzini * ARM11MPCore internal peripheral emulation. 30434e30aSPaolo Bonzini * 40434e30aSPaolo Bonzini * Copyright (c) 2006-2007 CodeSourcery. 50434e30aSPaolo Bonzini * Written by Paul Brook 60434e30aSPaolo Bonzini * 70434e30aSPaolo Bonzini * This code is licensed under the GPL. 80434e30aSPaolo Bonzini */ 90434e30aSPaolo Bonzini 1017b7f2dbSPeter Maydell #include "qemu/osdep.h" 11da34e65cSMarkus Armbruster #include "qapi/error.h" 120b8fa32fSMarkus Armbruster #include "qemu/module.h" 137b960dc3SAndreas Färber #include "hw/cpu/arm11mpcore.h" 14306476eaSAndreas Färber #include "hw/intc/realview_gic.h" 1564552b6bSMarkus Armbruster #include "hw/irq.h" 16a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 170434e30aSPaolo Bonzini 1825f1d9f3SSai Pavan Boddu #define ARM11MPCORE_NUM_GIC_PRIORITY_BITS 4 190434e30aSPaolo Bonzini 200434e30aSPaolo Bonzini static void mpcore_priv_set_irq(void *opaque, int irq, int level) 210434e30aSPaolo Bonzini { 220434e30aSPaolo Bonzini ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque; 2308602ac5SAndreas Färber 2408602ac5SAndreas Färber qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level); 250434e30aSPaolo Bonzini } 260434e30aSPaolo Bonzini 270434e30aSPaolo Bonzini static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) 280434e30aSPaolo Bonzini { 290434e30aSPaolo Bonzini int i; 3053cb9a1cSAndreas Färber SysBusDevice *scubusdev = SYS_BUS_DEVICE(&s->scu); 3108602ac5SAndreas Färber DeviceState *gicdev = DEVICE(&s->gic); 3208602ac5SAndreas Färber SysBusDevice *gicbusdev = SYS_BUS_DEVICE(&s->gic); 3308602ac5SAndreas Färber SysBusDevice *timerbusdev = SYS_BUS_DEVICE(&s->mptimer); 3408602ac5SAndreas Färber SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(&s->wdtimer); 3553cb9a1cSAndreas Färber 3653cb9a1cSAndreas Färber memory_region_add_subregion(&s->container, 0, 3753cb9a1cSAndreas Färber sysbus_mmio_get_region(scubusdev, 0)); 380434e30aSPaolo Bonzini /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs 390434e30aSPaolo Bonzini * at 0x200, 0x300... 400434e30aSPaolo Bonzini */ 410434e30aSPaolo Bonzini for (i = 0; i < (s->num_cpu + 1); i++) { 420434e30aSPaolo Bonzini hwaddr offset = 0x100 + (i * 0x100); 430434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, offset, 440434e30aSPaolo Bonzini sysbus_mmio_get_region(gicbusdev, i + 1)); 450434e30aSPaolo Bonzini } 460434e30aSPaolo Bonzini /* Add the regions for timer and watchdog for "current CPU" and 470434e30aSPaolo Bonzini * for each specific CPU. 480434e30aSPaolo Bonzini */ 490434e30aSPaolo Bonzini for (i = 0; i < (s->num_cpu + 1); i++) { 500434e30aSPaolo Bonzini /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */ 510434e30aSPaolo Bonzini hwaddr offset = 0x600 + i * 0x100; 520434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, offset, 530434e30aSPaolo Bonzini sysbus_mmio_get_region(timerbusdev, i)); 540434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, offset + 0x20, 550434e30aSPaolo Bonzini sysbus_mmio_get_region(wdtbusdev, i)); 560434e30aSPaolo Bonzini } 570434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x1000, 580434e30aSPaolo Bonzini sysbus_mmio_get_region(gicbusdev, 0)); 590434e30aSPaolo Bonzini /* Wire up the interrupt from each watchdog and timer. 600434e30aSPaolo Bonzini * For each core the timer is PPI 29 and the watchdog PPI 30. 610434e30aSPaolo Bonzini */ 620434e30aSPaolo Bonzini for (i = 0; i < s->num_cpu; i++) { 630434e30aSPaolo Bonzini int ppibase = (s->num_irq - 32) + i * 32; 640434e30aSPaolo Bonzini sysbus_connect_irq(timerbusdev, i, 6508602ac5SAndreas Färber qdev_get_gpio_in(gicdev, ppibase + 29)); 660434e30aSPaolo Bonzini sysbus_connect_irq(wdtbusdev, i, 6708602ac5SAndreas Färber qdev_get_gpio_in(gicdev, ppibase + 30)); 680434e30aSPaolo Bonzini } 690434e30aSPaolo Bonzini } 700434e30aSPaolo Bonzini 7108602ac5SAndreas Färber static void mpcore_priv_realize(DeviceState *dev, Error **errp) 720434e30aSPaolo Bonzini { 7308602ac5SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 7456fc0281SAndreas Färber ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(dev); 7553cb9a1cSAndreas Färber DeviceState *scudev = DEVICE(&s->scu); 7608602ac5SAndreas Färber DeviceState *gicdev = DEVICE(&s->gic); 7708602ac5SAndreas Färber DeviceState *mptimerdev = DEVICE(&s->mptimer); 7808602ac5SAndreas Färber DeviceState *wdtimerdev = DEVICE(&s->wdtimer); 7908602ac5SAndreas Färber Error *err = NULL; 8053cb9a1cSAndreas Färber 8153cb9a1cSAndreas Färber qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); 82*db873cc5SMarkus Armbruster sysbus_realize(SYS_BUS_DEVICE(&s->scu), &err); 8308602ac5SAndreas Färber if (err != NULL) { 8408602ac5SAndreas Färber error_propagate(errp, err); 8508602ac5SAndreas Färber return; 8608602ac5SAndreas Färber } 870434e30aSPaolo Bonzini 8808602ac5SAndreas Färber qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); 8908602ac5SAndreas Färber qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); 9025f1d9f3SSai Pavan Boddu qdev_prop_set_uint32(gicdev, "num-priority-bits", 9125f1d9f3SSai Pavan Boddu ARM11MPCORE_NUM_GIC_PRIORITY_BITS); 9225f1d9f3SSai Pavan Boddu 9325f1d9f3SSai Pavan Boddu 94*db873cc5SMarkus Armbruster sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err); 9508602ac5SAndreas Färber if (err != NULL) { 9608602ac5SAndreas Färber error_propagate(errp, err); 9708602ac5SAndreas Färber return; 9808602ac5SAndreas Färber } 990434e30aSPaolo Bonzini 1000434e30aSPaolo Bonzini /* Pass through outbound IRQ lines from the GIC */ 10108602ac5SAndreas Färber sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->gic)); 1020434e30aSPaolo Bonzini 1030434e30aSPaolo Bonzini /* Pass through inbound GPIO lines to the GIC */ 10456fc0281SAndreas Färber qdev_init_gpio_in(dev, mpcore_priv_set_irq, s->num_irq - 32); 1050434e30aSPaolo Bonzini 10608602ac5SAndreas Färber qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu); 107*db873cc5SMarkus Armbruster sysbus_realize(SYS_BUS_DEVICE(&s->mptimer), &err); 10808602ac5SAndreas Färber if (err != NULL) { 10908602ac5SAndreas Färber error_propagate(errp, err); 11008602ac5SAndreas Färber return; 11108602ac5SAndreas Färber } 1120434e30aSPaolo Bonzini 11308602ac5SAndreas Färber qdev_prop_set_uint32(wdtimerdev, "num-cpu", s->num_cpu); 114*db873cc5SMarkus Armbruster sysbus_realize(SYS_BUS_DEVICE(&s->wdtimer), &err); 11508602ac5SAndreas Färber if (err != NULL) { 11608602ac5SAndreas Färber error_propagate(errp, err); 11708602ac5SAndreas Färber return; 11808602ac5SAndreas Färber } 1190434e30aSPaolo Bonzini 1200434e30aSPaolo Bonzini mpcore_priv_map_setup(s); 1210434e30aSPaolo Bonzini } 1220434e30aSPaolo Bonzini 1232c42c3a0SAndreas Färber static void mpcore_priv_initfn(Object *obj) 1242c42c3a0SAndreas Färber { 1252c42c3a0SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1262c42c3a0SAndreas Färber ARM11MPCorePriveState *s = ARM11MPCORE_PRIV(obj); 1272c42c3a0SAndreas Färber 1282c42c3a0SAndreas Färber memory_region_init(&s->container, OBJECT(s), 1292c42c3a0SAndreas Färber "mpcore-priv-container", 0x2000); 1302c42c3a0SAndreas Färber sysbus_init_mmio(sbd, &s->container); 13153cb9a1cSAndreas Färber 132*db873cc5SMarkus Armbruster object_initialize_child(obj, "scu", &s->scu, TYPE_ARM11_SCU); 13308602ac5SAndreas Färber 134*db873cc5SMarkus Armbruster object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC); 13508602ac5SAndreas Färber /* Request the legacy 11MPCore GIC behaviour: */ 13608602ac5SAndreas Färber qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 0); 13708602ac5SAndreas Färber 138*db873cc5SMarkus Armbruster object_initialize_child(obj, "mptimer", &s->mptimer, TYPE_ARM_MPTIMER); 13908602ac5SAndreas Färber 140*db873cc5SMarkus Armbruster object_initialize_child(obj, "wdtimer", &s->wdtimer, TYPE_ARM_MPTIMER); 1412c42c3a0SAndreas Färber } 1422c42c3a0SAndreas Färber 1430434e30aSPaolo Bonzini static Property mpcore_priv_properties[] = { 1440434e30aSPaolo Bonzini DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, num_cpu, 1), 1450434e30aSPaolo Bonzini /* The ARM11 MPCORE TRM says the on-chip controller may have 1460434e30aSPaolo Bonzini * anything from 0 to 224 external interrupt IRQ lines (with another 1470434e30aSPaolo Bonzini * 32 internal). We default to 32+32, which is the number provided by 1480434e30aSPaolo Bonzini * the ARM11 MPCore test chip in the Realview Versatile Express 1490434e30aSPaolo Bonzini * coretile. Other boards may differ and should set this property 1500434e30aSPaolo Bonzini * appropriately. Some Linux kernels may not boot if the hardware 1510434e30aSPaolo Bonzini * has more IRQ lines than the kernel expects. 1520434e30aSPaolo Bonzini */ 1530434e30aSPaolo Bonzini DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64), 1540434e30aSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 1550434e30aSPaolo Bonzini }; 1560434e30aSPaolo Bonzini 1570434e30aSPaolo Bonzini static void mpcore_priv_class_init(ObjectClass *klass, void *data) 1580434e30aSPaolo Bonzini { 1590434e30aSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 1600434e30aSPaolo Bonzini 16108602ac5SAndreas Färber dc->realize = mpcore_priv_realize; 1624f67d30bSMarc-André Lureau device_class_set_props(dc, mpcore_priv_properties); 1630434e30aSPaolo Bonzini } 1640434e30aSPaolo Bonzini 1650434e30aSPaolo Bonzini static const TypeInfo mpcore_priv_info = { 16656fc0281SAndreas Färber .name = TYPE_ARM11MPCORE_PRIV, 1670434e30aSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 1680434e30aSPaolo Bonzini .instance_size = sizeof(ARM11MPCorePriveState), 1692c42c3a0SAndreas Färber .instance_init = mpcore_priv_initfn, 1700434e30aSPaolo Bonzini .class_init = mpcore_priv_class_init, 1710434e30aSPaolo Bonzini }; 1720434e30aSPaolo Bonzini 1730434e30aSPaolo Bonzini static void arm11mpcore_register_types(void) 1740434e30aSPaolo Bonzini { 1750434e30aSPaolo Bonzini type_register_static(&mpcore_priv_info); 1760434e30aSPaolo Bonzini } 1770434e30aSPaolo Bonzini 1780434e30aSPaolo Bonzini type_init(arm11mpcore_register_types) 179