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/module.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 struct BCM283XInfo { 20 const char *name; 21 const char *cpu_type; 22 hwaddr peri_base; /* Peripheral base address seen by the CPU */ 23 hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */ 24 int clusterid; 25 }; 26 27 static const BCM283XInfo bcm283x_socs[] = { 28 { 29 .name = TYPE_BCM2836, 30 .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"), 31 .peri_base = 0x3f000000, 32 .ctrl_base = 0x40000000, 33 .clusterid = 0xf, 34 }, 35 #ifdef TARGET_AARCH64 36 { 37 .name = TYPE_BCM2837, 38 .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"), 39 .peri_base = 0x3f000000, 40 .ctrl_base = 0x40000000, 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_child(obj, "cpu[*]", &s->cpu[n].core, 55 sizeof(s->cpu[n].core), info->cpu_type, 56 &error_abort, NULL); 57 } 58 59 sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control), 60 TYPE_BCM2836_CONTROL); 61 62 sysbus_init_child_obj(obj, "peripherals", &s->peripherals, 63 sizeof(s->peripherals), TYPE_BCM2835_PERIPHERALS); 64 object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), 65 "board-rev", &error_abort); 66 object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), 67 "vcram-size", &error_abort); 68 } 69 70 static void bcm2836_realize(DeviceState *dev, Error **errp) 71 { 72 BCM283XState *s = BCM283X(dev); 73 BCM283XClass *bc = BCM283X_GET_CLASS(dev); 74 const BCM283XInfo *info = bc->info; 75 Object *obj; 76 Error *err = NULL; 77 int n; 78 79 /* common peripherals from bcm2835 */ 80 81 obj = object_property_get_link(OBJECT(dev), "ram", &err); 82 if (obj == NULL) { 83 error_setg(errp, "%s: required ram link not found: %s", 84 __func__, error_get_pretty(err)); 85 return; 86 } 87 88 object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); 89 if (err) { 90 error_propagate(errp, err); 91 return; 92 } 93 94 object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); 95 if (err) { 96 error_propagate(errp, err); 97 return; 98 } 99 100 object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), 101 "sd-bus", &err); 102 if (err) { 103 error_propagate(errp, err); 104 return; 105 } 106 107 sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, 108 info->peri_base, 1); 109 110 /* bcm2836 interrupt controller (and mailboxes, etc.) */ 111 object_property_set_bool(OBJECT(&s->control), true, "realized", &err); 112 if (err) { 113 error_propagate(errp, err); 114 return; 115 } 116 117 sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base); 118 119 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, 120 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); 121 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, 122 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); 123 124 for (n = 0; n < BCM283X_NCPUS; n++) { 125 /* TODO: this should be converted to a property of ARM_CPU */ 126 s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n; 127 128 /* set periphbase/CBAR value for CPU-local registers */ 129 object_property_set_int(OBJECT(&s->cpu[n].core), 130 info->peri_base, 131 "reset-cbar", &err); 132 if (err) { 133 error_propagate(errp, err); 134 return; 135 } 136 137 /* start powered off if not enabled */ 138 object_property_set_bool(OBJECT(&s->cpu[n].core), n >= s->enabled_cpus, 139 "start-powered-off", &err); 140 if (err) { 141 error_propagate(errp, err); 142 return; 143 } 144 145 object_property_set_bool(OBJECT(&s->cpu[n].core), true, 146 "realized", &err); 147 if (err) { 148 error_propagate(errp, err); 149 return; 150 } 151 152 /* Connect irq/fiq outputs from the interrupt controller. */ 153 qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, 154 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ)); 155 qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, 156 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ)); 157 158 /* Connect timers from the CPU to the interrupt controller */ 159 qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS, 160 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n)); 161 qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT, 162 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); 163 qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP, 164 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n)); 165 qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC, 166 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); 167 } 168 } 169 170 static Property bcm2836_props[] = { 171 DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 172 BCM283X_NCPUS), 173 DEFINE_PROP_END_OF_LIST() 174 }; 175 176 static void bcm283x_class_init(ObjectClass *oc, void *data) 177 { 178 DeviceClass *dc = DEVICE_CLASS(oc); 179 BCM283XClass *bc = BCM283X_CLASS(oc); 180 181 bc->info = data; 182 dc->realize = bcm2836_realize; 183 device_class_set_props(dc, bcm2836_props); 184 /* Reason: Must be wired up in code (see raspi_init() function) */ 185 dc->user_creatable = false; 186 } 187 188 static const TypeInfo bcm283x_type_info = { 189 .name = TYPE_BCM283X, 190 .parent = TYPE_DEVICE, 191 .instance_size = sizeof(BCM283XState), 192 .instance_init = bcm2836_init, 193 .class_size = sizeof(BCM283XClass), 194 .abstract = true, 195 }; 196 197 static void bcm2836_register_types(void) 198 { 199 int i; 200 201 type_register_static(&bcm283x_type_info); 202 for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) { 203 TypeInfo ti = { 204 .name = bcm283x_socs[i].name, 205 .parent = TYPE_BCM283X, 206 .class_init = bcm283x_class_init, 207 .class_data = (void *) &bcm283x_socs[i], 208 }; 209 type_register(&ti); 210 } 211 } 212 213 type_init(bcm2836_register_types) 214