1*0434e30aSPaolo Bonzini /* 2*0434e30aSPaolo Bonzini * Cortex-A9MPCore internal peripheral emulation. 3*0434e30aSPaolo Bonzini * 4*0434e30aSPaolo Bonzini * Copyright (c) 2009 CodeSourcery. 5*0434e30aSPaolo Bonzini * Copyright (c) 2011 Linaro Limited. 6*0434e30aSPaolo Bonzini * Written by Paul Brook, Peter Maydell. 7*0434e30aSPaolo Bonzini * 8*0434e30aSPaolo Bonzini * This code is licensed under the GPL. 9*0434e30aSPaolo Bonzini */ 10*0434e30aSPaolo Bonzini 11*0434e30aSPaolo Bonzini #include "hw/sysbus.h" 12*0434e30aSPaolo Bonzini 13*0434e30aSPaolo Bonzini typedef struct A9MPPrivState { 14*0434e30aSPaolo Bonzini SysBusDevice busdev; 15*0434e30aSPaolo Bonzini uint32_t num_cpu; 16*0434e30aSPaolo Bonzini MemoryRegion container; 17*0434e30aSPaolo Bonzini DeviceState *mptimer; 18*0434e30aSPaolo Bonzini DeviceState *wdt; 19*0434e30aSPaolo Bonzini DeviceState *gic; 20*0434e30aSPaolo Bonzini DeviceState *scu; 21*0434e30aSPaolo Bonzini uint32_t num_irq; 22*0434e30aSPaolo Bonzini } A9MPPrivState; 23*0434e30aSPaolo Bonzini 24*0434e30aSPaolo Bonzini static void a9mp_priv_set_irq(void *opaque, int irq, int level) 25*0434e30aSPaolo Bonzini { 26*0434e30aSPaolo Bonzini A9MPPrivState *s = (A9MPPrivState *)opaque; 27*0434e30aSPaolo Bonzini qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); 28*0434e30aSPaolo Bonzini } 29*0434e30aSPaolo Bonzini 30*0434e30aSPaolo Bonzini static int a9mp_priv_init(SysBusDevice *dev) 31*0434e30aSPaolo Bonzini { 32*0434e30aSPaolo Bonzini A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); 33*0434e30aSPaolo Bonzini SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev; 34*0434e30aSPaolo Bonzini int i; 35*0434e30aSPaolo Bonzini 36*0434e30aSPaolo Bonzini s->gic = qdev_create(NULL, "arm_gic"); 37*0434e30aSPaolo Bonzini qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); 38*0434e30aSPaolo Bonzini qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); 39*0434e30aSPaolo Bonzini qdev_init_nofail(s->gic); 40*0434e30aSPaolo Bonzini gicbusdev = SYS_BUS_DEVICE(s->gic); 41*0434e30aSPaolo Bonzini 42*0434e30aSPaolo Bonzini /* Pass through outbound IRQ lines from the GIC */ 43*0434e30aSPaolo Bonzini sysbus_pass_irq(dev, gicbusdev); 44*0434e30aSPaolo Bonzini 45*0434e30aSPaolo Bonzini /* Pass through inbound GPIO lines to the GIC */ 46*0434e30aSPaolo Bonzini qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32); 47*0434e30aSPaolo Bonzini 48*0434e30aSPaolo Bonzini s->scu = qdev_create(NULL, "a9-scu"); 49*0434e30aSPaolo Bonzini qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu); 50*0434e30aSPaolo Bonzini qdev_init_nofail(s->scu); 51*0434e30aSPaolo Bonzini scubusdev = SYS_BUS_DEVICE(s->scu); 52*0434e30aSPaolo Bonzini 53*0434e30aSPaolo Bonzini s->mptimer = qdev_create(NULL, "arm_mptimer"); 54*0434e30aSPaolo Bonzini qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); 55*0434e30aSPaolo Bonzini qdev_init_nofail(s->mptimer); 56*0434e30aSPaolo Bonzini timerbusdev = SYS_BUS_DEVICE(s->mptimer); 57*0434e30aSPaolo Bonzini 58*0434e30aSPaolo Bonzini s->wdt = qdev_create(NULL, "arm_mptimer"); 59*0434e30aSPaolo Bonzini qdev_prop_set_uint32(s->wdt, "num-cpu", s->num_cpu); 60*0434e30aSPaolo Bonzini qdev_init_nofail(s->wdt); 61*0434e30aSPaolo Bonzini wdtbusdev = SYS_BUS_DEVICE(s->wdt); 62*0434e30aSPaolo Bonzini 63*0434e30aSPaolo Bonzini /* Memory map (addresses are offsets from PERIPHBASE): 64*0434e30aSPaolo Bonzini * 0x0000-0x00ff -- Snoop Control Unit 65*0434e30aSPaolo Bonzini * 0x0100-0x01ff -- GIC CPU interface 66*0434e30aSPaolo Bonzini * 0x0200-0x02ff -- Global Timer 67*0434e30aSPaolo Bonzini * 0x0300-0x05ff -- nothing 68*0434e30aSPaolo Bonzini * 0x0600-0x06ff -- private timers and watchdogs 69*0434e30aSPaolo Bonzini * 0x0700-0x0fff -- nothing 70*0434e30aSPaolo Bonzini * 0x1000-0x1fff -- GIC Distributor 71*0434e30aSPaolo Bonzini * 72*0434e30aSPaolo Bonzini * We should implement the global timer but don't currently do so. 73*0434e30aSPaolo Bonzini */ 74*0434e30aSPaolo Bonzini memory_region_init(&s->container, "a9mp-priv-container", 0x2000); 75*0434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0, 76*0434e30aSPaolo Bonzini sysbus_mmio_get_region(scubusdev, 0)); 77*0434e30aSPaolo Bonzini /* GIC CPU interface */ 78*0434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x100, 79*0434e30aSPaolo Bonzini sysbus_mmio_get_region(gicbusdev, 1)); 80*0434e30aSPaolo Bonzini /* Note that the A9 exposes only the "timer/watchdog for this core" 81*0434e30aSPaolo Bonzini * memory region, not the "timer/watchdog for core X" ones 11MPcore has. 82*0434e30aSPaolo Bonzini */ 83*0434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x600, 84*0434e30aSPaolo Bonzini sysbus_mmio_get_region(timerbusdev, 0)); 85*0434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x620, 86*0434e30aSPaolo Bonzini sysbus_mmio_get_region(wdtbusdev, 0)); 87*0434e30aSPaolo Bonzini memory_region_add_subregion(&s->container, 0x1000, 88*0434e30aSPaolo Bonzini sysbus_mmio_get_region(gicbusdev, 0)); 89*0434e30aSPaolo Bonzini 90*0434e30aSPaolo Bonzini sysbus_init_mmio(dev, &s->container); 91*0434e30aSPaolo Bonzini 92*0434e30aSPaolo Bonzini /* Wire up the interrupt from each watchdog and timer. 93*0434e30aSPaolo Bonzini * For each core the timer is PPI 29 and the watchdog PPI 30. 94*0434e30aSPaolo Bonzini */ 95*0434e30aSPaolo Bonzini for (i = 0; i < s->num_cpu; i++) { 96*0434e30aSPaolo Bonzini int ppibase = (s->num_irq - 32) + i * 32; 97*0434e30aSPaolo Bonzini sysbus_connect_irq(timerbusdev, i, 98*0434e30aSPaolo Bonzini qdev_get_gpio_in(s->gic, ppibase + 29)); 99*0434e30aSPaolo Bonzini sysbus_connect_irq(wdtbusdev, i, 100*0434e30aSPaolo Bonzini qdev_get_gpio_in(s->gic, ppibase + 30)); 101*0434e30aSPaolo Bonzini } 102*0434e30aSPaolo Bonzini return 0; 103*0434e30aSPaolo Bonzini } 104*0434e30aSPaolo Bonzini 105*0434e30aSPaolo Bonzini static Property a9mp_priv_properties[] = { 106*0434e30aSPaolo Bonzini DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1), 107*0434e30aSPaolo Bonzini /* The Cortex-A9MP may have anything from 0 to 224 external interrupt 108*0434e30aSPaolo Bonzini * IRQ lines (with another 32 internal). We default to 64+32, which 109*0434e30aSPaolo Bonzini * is the number provided by the Cortex-A9MP test chip in the 110*0434e30aSPaolo Bonzini * Realview PBX-A9 and Versatile Express A9 development boards. 111*0434e30aSPaolo Bonzini * Other boards may differ and should set this property appropriately. 112*0434e30aSPaolo Bonzini */ 113*0434e30aSPaolo Bonzini DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96), 114*0434e30aSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 115*0434e30aSPaolo Bonzini }; 116*0434e30aSPaolo Bonzini 117*0434e30aSPaolo Bonzini static void a9mp_priv_class_init(ObjectClass *klass, void *data) 118*0434e30aSPaolo Bonzini { 119*0434e30aSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 120*0434e30aSPaolo Bonzini SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 121*0434e30aSPaolo Bonzini 122*0434e30aSPaolo Bonzini k->init = a9mp_priv_init; 123*0434e30aSPaolo Bonzini dc->props = a9mp_priv_properties; 124*0434e30aSPaolo Bonzini } 125*0434e30aSPaolo Bonzini 126*0434e30aSPaolo Bonzini static const TypeInfo a9mp_priv_info = { 127*0434e30aSPaolo Bonzini .name = "a9mpcore_priv", 128*0434e30aSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 129*0434e30aSPaolo Bonzini .instance_size = sizeof(A9MPPrivState), 130*0434e30aSPaolo Bonzini .class_init = a9mp_priv_class_init, 131*0434e30aSPaolo Bonzini }; 132*0434e30aSPaolo Bonzini 133*0434e30aSPaolo Bonzini static void a9mp_register_types(void) 134*0434e30aSPaolo Bonzini { 135*0434e30aSPaolo Bonzini type_register_static(&a9mp_priv_info); 136*0434e30aSPaolo Bonzini } 137*0434e30aSPaolo Bonzini 138*0434e30aSPaolo Bonzini type_init(a9mp_register_types) 139