1 /* 2 * Xilinx Zynq MPSoC emulation 3 * 4 * Copyright (C) 2015 Xilinx Inc 5 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * for more details. 16 */ 17 18 #include "hw/arm/xlnx-zynqmp.h" 19 #include "hw/intc/arm_gic_common.h" 20 #include "exec/address-spaces.h" 21 22 #define GIC_NUM_SPI_INTR 160 23 24 #define ARM_PHYS_TIMER_PPI 30 25 #define ARM_VIRT_TIMER_PPI 27 26 27 #define GIC_BASE_ADDR 0xf9000000 28 #define GIC_DIST_ADDR 0xf9010000 29 #define GIC_CPU_ADDR 0xf9020000 30 31 static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { 32 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, 33 }; 34 35 static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = { 36 57, 59, 61, 63, 37 }; 38 39 typedef struct XlnxZynqMPGICRegion { 40 int region_index; 41 uint32_t address; 42 } XlnxZynqMPGICRegion; 43 44 static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions[] = { 45 { .region_index = 0, .address = GIC_DIST_ADDR, }, 46 { .region_index = 1, .address = GIC_CPU_ADDR, }, 47 }; 48 49 static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) 50 { 51 return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index; 52 } 53 54 static void xlnx_zynqmp_init(Object *obj) 55 { 56 XlnxZynqMPState *s = XLNX_ZYNQMP(obj); 57 int i; 58 59 for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) { 60 object_initialize(&s->cpu[i], sizeof(s->cpu[i]), 61 "cortex-a53-" TYPE_ARM_CPU); 62 object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpu[i]), 63 &error_abort); 64 } 65 66 object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); 67 qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); 68 69 for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { 70 object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM); 71 qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default()); 72 } 73 } 74 75 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) 76 { 77 XlnxZynqMPState *s = XLNX_ZYNQMP(dev); 78 MemoryRegion *system_memory = get_system_memory(); 79 uint8_t i; 80 qemu_irq gic_spi[GIC_NUM_SPI_INTR]; 81 Error *err = NULL; 82 83 qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); 84 qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); 85 qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_CPUS); 86 object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); 87 if (err) { 88 error_propagate((errp), (err)); 89 return; 90 } 91 assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS); 92 for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) { 93 SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic); 94 const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i]; 95 MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index); 96 uint32_t addr = r->address; 97 int j; 98 99 sysbus_mmio_map(gic, r->region_index, addr); 100 101 for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) { 102 MemoryRegion *alias = &s->gic_mr[i][j]; 103 104 addr += XLNX_ZYNQMP_GIC_REGION_SIZE; 105 memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr, 106 0, XLNX_ZYNQMP_GIC_REGION_SIZE); 107 memory_region_add_subregion(system_memory, addr, alias); 108 } 109 } 110 111 for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) { 112 qemu_irq irq; 113 114 object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC, 115 "psci-conduit", &error_abort); 116 if (i > 0) { 117 /* Secondary CPUs start in PSCI powered-down state */ 118 object_property_set_bool(OBJECT(&s->cpu[i]), true, 119 "start-powered-off", &error_abort); 120 } 121 122 object_property_set_int(OBJECT(&s->cpu[i]), GIC_BASE_ADDR, 123 "reset-cbar", &err); 124 if (err) { 125 error_propagate((errp), (err)); 126 return; 127 } 128 129 object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); 130 if (err) { 131 error_propagate((errp), (err)); 132 return; 133 } 134 135 sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, 136 qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ)); 137 irq = qdev_get_gpio_in(DEVICE(&s->gic), 138 arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI)); 139 qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 0, irq); 140 irq = qdev_get_gpio_in(DEVICE(&s->gic), 141 arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI)); 142 qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 1, irq); 143 } 144 145 for (i = 0; i < GIC_NUM_SPI_INTR; i++) { 146 gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i); 147 } 148 149 for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { 150 NICInfo *nd = &nd_table[i]; 151 152 if (nd->used) { 153 qemu_check_nic_model(nd, TYPE_CADENCE_GEM); 154 qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); 155 } 156 object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); 157 if (err) { 158 error_propagate((errp), (err)); 159 return; 160 } 161 sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]); 162 sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0, 163 gic_spi[gem_intr[i]]); 164 } 165 } 166 167 static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data) 168 { 169 DeviceClass *dc = DEVICE_CLASS(oc); 170 171 dc->realize = xlnx_zynqmp_realize; 172 } 173 174 static const TypeInfo xlnx_zynqmp_type_info = { 175 .name = TYPE_XLNX_ZYNQMP, 176 .parent = TYPE_DEVICE, 177 .instance_size = sizeof(XlnxZynqMPState), 178 .instance_init = xlnx_zynqmp_init, 179 .class_init = xlnx_zynqmp_class_init, 180 }; 181 182 static void xlnx_zynqmp_register_types(void) 183 { 184 type_register_static(&xlnx_zynqmp_type_info); 185 } 186 187 type_init(xlnx_zynqmp_register_types) 188