10434e30aSPaolo Bonzini /* 20434e30aSPaolo Bonzini * Cortex-A15MPCore internal peripheral emulation. 30434e30aSPaolo Bonzini * 40434e30aSPaolo Bonzini * Copyright (c) 2012 Linaro Limited. 50434e30aSPaolo Bonzini * Written by Peter Maydell. 60434e30aSPaolo Bonzini * 70434e30aSPaolo Bonzini * This program is free software; you can redistribute it and/or modify 80434e30aSPaolo Bonzini * it under the terms of the GNU General Public License as published by 90434e30aSPaolo Bonzini * the Free Software Foundation; either version 2 of the License, or 100434e30aSPaolo Bonzini * (at your option) any later version. 110434e30aSPaolo Bonzini * 120434e30aSPaolo Bonzini * This program is distributed in the hope that it will be useful, 130434e30aSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 140434e30aSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 150434e30aSPaolo Bonzini * GNU General Public License for more details. 160434e30aSPaolo Bonzini * 170434e30aSPaolo Bonzini * You should have received a copy of the GNU General Public License along 180434e30aSPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>. 190434e30aSPaolo Bonzini */ 200434e30aSPaolo Bonzini 210430891cSPeter Maydell #include "qemu/osdep.h" 22da34e65cSMarkus Armbruster #include "qapi/error.h" 230b8fa32fSMarkus Armbruster #include "qemu/module.h" 2443482f72SAndreas Färber #include "hw/cpu/a15mpcore.h" 25*64552b6bSMarkus Armbruster #include "hw/irq.h" 260434e30aSPaolo Bonzini #include "sysemu/kvm.h" 27e6fbcbc4SPavel Fedin #include "kvm_arm.h" 280434e30aSPaolo Bonzini 290434e30aSPaolo Bonzini static void a15mp_priv_set_irq(void *opaque, int irq, int level) 300434e30aSPaolo Bonzini { 310434e30aSPaolo Bonzini A15MPPrivState *s = (A15MPPrivState *)opaque; 32524a2d8eSAndreas Färber 33524a2d8eSAndreas Färber qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level); 340434e30aSPaolo Bonzini } 350434e30aSPaolo Bonzini 36b9ed148dSAndreas Färber static void a15mp_priv_initfn(Object *obj) 37b9ed148dSAndreas Färber { 38b9ed148dSAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 39b9ed148dSAndreas Färber A15MPPrivState *s = A15MPCORE_PRIV(obj); 400434e30aSPaolo Bonzini 41524a2d8eSAndreas Färber memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000); 42524a2d8eSAndreas Färber sysbus_init_mmio(sbd, &s->container); 43524a2d8eSAndreas Färber 44fd317012SThomas Huth sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic), 45fd317012SThomas Huth gic_class_name()); 46fd317012SThomas Huth qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); 47524a2d8eSAndreas Färber } 48524a2d8eSAndreas Färber 497c76a48dSAndreas Färber static void a15mp_priv_realize(DeviceState *dev, Error **errp) 50524a2d8eSAndreas Färber { 517c76a48dSAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 52524a2d8eSAndreas Färber A15MPPrivState *s = A15MPCORE_PRIV(dev); 53524a2d8eSAndreas Färber DeviceState *gicdev; 54524a2d8eSAndreas Färber SysBusDevice *busdev; 55524a2d8eSAndreas Färber int i; 567c76a48dSAndreas Färber Error *err = NULL; 574182bbb1SPeter Maydell bool has_el3; 58ba3287d1SPeter Maydell bool has_el2 = false; 594182bbb1SPeter Maydell Object *cpuobj; 60524a2d8eSAndreas Färber 61524a2d8eSAndreas Färber gicdev = DEVICE(&s->gic); 62524a2d8eSAndreas Färber qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); 63524a2d8eSAndreas Färber qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); 644182bbb1SPeter Maydell 654182bbb1SPeter Maydell if (!kvm_irqchip_in_kernel()) { 664182bbb1SPeter Maydell /* Make the GIC's TZ support match the CPUs. We assume that 674182bbb1SPeter Maydell * either all the CPUs have TZ, or none do. 684182bbb1SPeter Maydell */ 694182bbb1SPeter Maydell cpuobj = OBJECT(qemu_get_cpu(0)); 706533a1fcSEdgar E. Iglesias has_el3 = object_property_find(cpuobj, "has_el3", NULL) && 714182bbb1SPeter Maydell object_property_get_bool(cpuobj, "has_el3", &error_abort); 724182bbb1SPeter Maydell qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); 73ba3287d1SPeter Maydell /* Similarly for virtualization support */ 74ba3287d1SPeter Maydell has_el2 = object_property_find(cpuobj, "has_el2", NULL) && 75ba3287d1SPeter Maydell object_property_get_bool(cpuobj, "has_el2", &error_abort); 76ba3287d1SPeter Maydell qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2); 774182bbb1SPeter Maydell } 784182bbb1SPeter Maydell 797c76a48dSAndreas Färber object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); 807c76a48dSAndreas Färber if (err != NULL) { 817c76a48dSAndreas Färber error_propagate(errp, err); 827c76a48dSAndreas Färber return; 837c76a48dSAndreas Färber } 84524a2d8eSAndreas Färber busdev = SYS_BUS_DEVICE(&s->gic); 850434e30aSPaolo Bonzini 860434e30aSPaolo Bonzini /* Pass through outbound IRQ lines from the GIC */ 877c76a48dSAndreas Färber sysbus_pass_irq(sbd, busdev); 880434e30aSPaolo Bonzini 890434e30aSPaolo Bonzini /* Pass through inbound GPIO lines to the GIC */ 907c76a48dSAndreas Färber qdev_init_gpio_in(dev, a15mp_priv_set_irq, s->num_irq - 32); 910434e30aSPaolo Bonzini 926033e840SPeter Maydell /* Wire the outputs from each CPU's generic timer to the 936033e840SPeter Maydell * appropriate GIC PPI inputs 946033e840SPeter Maydell */ 9527013bf2SAndreas Färber for (i = 0; i < s->num_cpu; i++) { 9627013bf2SAndreas Färber DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); 976033e840SPeter Maydell int ppibase = s->num_irq - 32 + i * 32; 985dfaa75bSPeter Maydell int irq; 995dfaa75bSPeter Maydell /* Mapping from the output timer irq lines from the CPU to the 1005dfaa75bSPeter Maydell * GIC PPI inputs used on the A15: 1016033e840SPeter Maydell */ 1025dfaa75bSPeter Maydell const int timer_irq[] = { 1035dfaa75bSPeter Maydell [GTIMER_PHYS] = 30, 1045dfaa75bSPeter Maydell [GTIMER_VIRT] = 27, 1055dfaa75bSPeter Maydell [GTIMER_HYP] = 26, 1065dfaa75bSPeter Maydell [GTIMER_SEC] = 29, 1075dfaa75bSPeter Maydell }; 1085dfaa75bSPeter Maydell for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { 1095dfaa75bSPeter Maydell qdev_connect_gpio_out(cpudev, irq, 1105dfaa75bSPeter Maydell qdev_get_gpio_in(gicdev, 1115dfaa75bSPeter Maydell ppibase + timer_irq[irq])); 1125dfaa75bSPeter Maydell } 113ba3287d1SPeter Maydell if (has_el2) { 114ba3287d1SPeter Maydell /* Connect the GIC maintenance interrupt to PPI ID 25 */ 115ba3287d1SPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(gicdev), i + 4 * s->num_cpu, 116ba3287d1SPeter Maydell qdev_get_gpio_in(gicdev, ppibase + 25)); 117ba3287d1SPeter Maydell } 1186033e840SPeter Maydell } 1196033e840SPeter Maydell 1200434e30aSPaolo Bonzini /* Memory map (addresses are offsets from PERIPHBASE): 1210434e30aSPaolo Bonzini * 0x0000-0x0fff -- reserved 1220434e30aSPaolo Bonzini * 0x1000-0x1fff -- GIC Distributor 123a55c910eSPeter Maydell * 0x2000-0x3fff -- GIC CPU interface 124ba3287d1SPeter Maydell * 0x4000-0x4fff -- GIC virtual interface control for this CPU 125ba3287d1SPeter Maydell * 0x5000-0x51ff -- GIC virtual interface control for CPU 0 126ba3287d1SPeter Maydell * 0x5200-0x53ff -- GIC virtual interface control for CPU 1 127ba3287d1SPeter Maydell * 0x5400-0x55ff -- GIC virtual interface control for CPU 2 128ba3287d1SPeter Maydell * 0x5600-0x57ff -- GIC virtual interface control for CPU 3 129ba3287d1SPeter Maydell * 0x6000-0x7fff -- GIC virtual CPU interface 1300434e30aSPaolo Bonzini */ 1310434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x1000, 1320434e30aSPaolo Bonzini sysbus_mmio_get_region(busdev, 0)); 1330434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x2000, 1340434e30aSPaolo Bonzini sysbus_mmio_get_region(busdev, 1)); 135ba3287d1SPeter Maydell if (has_el2) { 136ba3287d1SPeter Maydell memory_region_add_subregion(&s->container, 0x4000, 137ba3287d1SPeter Maydell sysbus_mmio_get_region(busdev, 2)); 138ba3287d1SPeter Maydell memory_region_add_subregion(&s->container, 0x6000, 139ba3287d1SPeter Maydell sysbus_mmio_get_region(busdev, 3)); 140ba3287d1SPeter Maydell for (i = 0; i < s->num_cpu; i++) { 141ba3287d1SPeter Maydell hwaddr base = 0x5000 + i * 0x200; 142ba3287d1SPeter Maydell MemoryRegion *mr = sysbus_mmio_get_region(busdev, 143ba3287d1SPeter Maydell 4 + s->num_cpu + i); 144ba3287d1SPeter Maydell memory_region_add_subregion(&s->container, base, mr); 145ba3287d1SPeter Maydell } 146ba3287d1SPeter Maydell } 1470434e30aSPaolo Bonzini } 1480434e30aSPaolo Bonzini 1490434e30aSPaolo Bonzini static Property a15mp_priv_properties[] = { 1500434e30aSPaolo Bonzini DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1), 1510434e30aSPaolo Bonzini /* The Cortex-A15MP may have anything from 0 to 224 external interrupt 15252862242SPeter Maydell * IRQ lines (with another 32 internal). We default to 128+32, which 1530434e30aSPaolo Bonzini * is the number provided by the Cortex-A15MP test chip in the 1540434e30aSPaolo Bonzini * Versatile Express A15 development board. 1550434e30aSPaolo Bonzini * Other boards may differ and should set this property appropriately. 1560434e30aSPaolo Bonzini */ 15752862242SPeter Maydell DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 160), 1580434e30aSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 1590434e30aSPaolo Bonzini }; 1600434e30aSPaolo Bonzini 1610434e30aSPaolo Bonzini static void a15mp_priv_class_init(ObjectClass *klass, void *data) 1620434e30aSPaolo Bonzini { 1630434e30aSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 1647c76a48dSAndreas Färber 1657c76a48dSAndreas Färber dc->realize = a15mp_priv_realize; 1660434e30aSPaolo Bonzini dc->props = a15mp_priv_properties; 1670434e30aSPaolo Bonzini /* We currently have no savable state */ 1680434e30aSPaolo Bonzini } 1690434e30aSPaolo Bonzini 1700434e30aSPaolo Bonzini static const TypeInfo a15mp_priv_info = { 17197da11d8SAndreas Färber .name = TYPE_A15MPCORE_PRIV, 1720434e30aSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 1730434e30aSPaolo Bonzini .instance_size = sizeof(A15MPPrivState), 174b9ed148dSAndreas Färber .instance_init = a15mp_priv_initfn, 1750434e30aSPaolo Bonzini .class_init = a15mp_priv_class_init, 1760434e30aSPaolo Bonzini }; 1770434e30aSPaolo Bonzini 1780434e30aSPaolo Bonzini static void a15mp_register_types(void) 1790434e30aSPaolo Bonzini { 1800434e30aSPaolo Bonzini type_register_static(&a15mp_priv_info); 1810434e30aSPaolo Bonzini } 1820434e30aSPaolo Bonzini 1830434e30aSPaolo Bonzini type_init(a15mp_register_types) 184