1 /* 2 * Raspberry Pi emulation (c) 2012 Gregory Estrade 3 * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous 4 * 5 * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft 6 * Written by Andrew Baumann 7 * 8 * This code is licensed under the GNU GPLv2 and later. 9 */ 10 11 #include "qemu/osdep.h" 12 #include "qapi/error.h" 13 #include "qemu-common.h" 14 #include "cpu.h" 15 #include "hw/arm/bcm2836.h" 16 #include "hw/arm/raspi_platform.h" 17 #include "hw/sysbus.h" 18 19 /* Peripheral base address seen by the CPU */ 20 #define BCM2836_PERI_BASE 0x3F000000 21 22 /* "QA7" (Pi2) interrupt controller and mailboxes etc. */ 23 #define BCM2836_CONTROL_BASE 0x40000000 24 25 struct BCM283XInfo { 26 const char *name; 27 const char *cpu_type; 28 int clusterid; 29 }; 30 31 static const BCM283XInfo bcm283x_socs[] = { 32 { 33 .name = TYPE_BCM2836, 34 .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"), 35 .clusterid = 0xf, 36 }, 37 #ifdef TARGET_AARCH64 38 { 39 .name = TYPE_BCM2837, 40 .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"), 41 .clusterid = 0x0, 42 }, 43 #endif 44 }; 45 46 static void bcm2836_init(Object *obj) 47 { 48 BCM283XState *s = BCM283X(obj); 49 BCM283XClass *bc = BCM283X_GET_CLASS(obj); 50 const BCM283XInfo *info = bc->info; 51 int n; 52 53 for (n = 0; n < BCM283X_NCPUS; n++) { 54 object_initialize(&s->cpus[n], sizeof(s->cpus[n]), 55 info->cpu_type); 56 object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]), 57 &error_abort); 58 } 59 60 object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL); 61 object_property_add_child(obj, "control", OBJECT(&s->control), NULL); 62 qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default()); 63 64 object_initialize(&s->peripherals, sizeof(s->peripherals), 65 TYPE_BCM2835_PERIPHERALS); 66 object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals), 67 &error_abort); 68 object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), 69 "board-rev", &error_abort); 70 object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), 71 "vcram-size", &error_abort); 72 qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default()); 73 } 74 75 static void bcm2836_realize(DeviceState *dev, Error **errp) 76 { 77 BCM283XState *s = BCM283X(dev); 78 BCM283XClass *bc = BCM283X_GET_CLASS(dev); 79 const BCM283XInfo *info = bc->info; 80 Object *obj; 81 Error *err = NULL; 82 int n; 83 84 /* common peripherals from bcm2835 */ 85 86 obj = object_property_get_link(OBJECT(dev), "ram", &err); 87 if (obj == NULL) { 88 error_setg(errp, "%s: required ram link not found: %s", 89 __func__, error_get_pretty(err)); 90 return; 91 } 92 93 object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); 94 if (err) { 95 error_propagate(errp, err); 96 return; 97 } 98 99 object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); 100 if (err) { 101 error_propagate(errp, err); 102 return; 103 } 104 105 object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), 106 "sd-bus", &err); 107 if (err) { 108 error_propagate(errp, err); 109 return; 110 } 111 112 sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, 113 BCM2836_PERI_BASE, 1); 114 115 /* bcm2836 interrupt controller (and mailboxes, etc.) */ 116 object_property_set_bool(OBJECT(&s->control), true, "realized", &err); 117 if (err) { 118 error_propagate(errp, err); 119 return; 120 } 121 122 sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); 123 124 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, 125 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); 126 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, 127 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); 128 129 for (n = 0; n < BCM283X_NCPUS; n++) { 130 /* TODO: this should be converted to a property of ARM_CPU */ 131 s->cpus[n].mp_affinity = (info->clusterid << 8) | n; 132 133 /* set periphbase/CBAR value for CPU-local registers */ 134 object_property_set_int(OBJECT(&s->cpus[n]), 135 BCM2836_PERI_BASE + MCORE_OFFSET, 136 "reset-cbar", &err); 137 if (err) { 138 error_propagate(errp, err); 139 return; 140 } 141 142 /* start powered off if not enabled */ 143 object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, 144 "start-powered-off", &err); 145 if (err) { 146 error_propagate(errp, err); 147 return; 148 } 149 150 object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); 151 if (err) { 152 error_propagate(errp, err); 153 return; 154 } 155 156 /* Connect irq/fiq outputs from the interrupt controller. */ 157 qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, 158 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); 159 qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, 160 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); 161 162 /* Connect timers from the CPU to the interrupt controller */ 163 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, 164 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); 165 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, 166 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); 167 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP, 168 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); 169 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC, 170 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); 171 } 172 } 173 174 static Property bcm2836_props[] = { 175 DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 176 BCM283X_NCPUS), 177 DEFINE_PROP_END_OF_LIST() 178 }; 179 180 static void bcm283x_class_init(ObjectClass *oc, void *data) 181 { 182 DeviceClass *dc = DEVICE_CLASS(oc); 183 BCM283XClass *bc = BCM283X_CLASS(oc); 184 185 bc->info = data; 186 dc->realize = bcm2836_realize; 187 dc->props = bcm2836_props; 188 } 189 190 static const TypeInfo bcm283x_type_info = { 191 .name = TYPE_BCM283X, 192 .parent = TYPE_DEVICE, 193 .instance_size = sizeof(BCM283XState), 194 .instance_init = bcm2836_init, 195 .class_size = sizeof(BCM283XClass), 196 .abstract = true, 197 }; 198 199 static void bcm2836_register_types(void) 200 { 201 int i; 202 203 type_register_static(&bcm283x_type_info); 204 for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) { 205 TypeInfo ti = { 206 .name = bcm283x_socs[i].name, 207 .parent = TYPE_BCM283X, 208 .class_init = bcm283x_class_init, 209 .class_data = (void *) &bcm283x_socs[i], 210 }; 211 type_register(&ti); 212 } 213 } 214 215 type_init(bcm2836_register_types) 216