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