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 "hw/arm/bcm2836.h" 13 #include "hw/arm/raspi_platform.h" 14 #include "hw/sysbus.h" 15 #include "exec/address-spaces.h" 16 17 /* Peripheral base address seen by the CPU */ 18 #define BCM2836_PERI_BASE 0x3F000000 19 20 /* "QA7" (Pi2) interrupt controller and mailboxes etc. */ 21 #define BCM2836_CONTROL_BASE 0x40000000 22 23 static void bcm2836_init(Object *obj) 24 { 25 BCM2836State *s = BCM2836(obj); 26 int n; 27 28 for (n = 0; n < BCM2836_NCPUS; n++) { 29 object_initialize(&s->cpus[n], sizeof(s->cpus[n]), 30 "cortex-a15-" TYPE_ARM_CPU); 31 object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]), 32 &error_abort); 33 } 34 35 object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL); 36 object_property_add_child(obj, "control", OBJECT(&s->control), NULL); 37 qdev_set_parent_bus(DEVICE(&s->control), sysbus_get_default()); 38 39 object_initialize(&s->peripherals, sizeof(s->peripherals), 40 TYPE_BCM2835_PERIPHERALS); 41 object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals), 42 &error_abort); 43 object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals), 44 "board-rev", &error_abort); 45 object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals), 46 "vcram-size", &error_abort); 47 qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default()); 48 } 49 50 static void bcm2836_realize(DeviceState *dev, Error **errp) 51 { 52 BCM2836State *s = BCM2836(dev); 53 Object *obj; 54 Error *err = NULL; 55 int n; 56 57 /* common peripherals from bcm2835 */ 58 59 obj = object_property_get_link(OBJECT(dev), "ram", &err); 60 if (obj == NULL) { 61 error_setg(errp, "%s: required ram link not found: %s", 62 __func__, error_get_pretty(err)); 63 return; 64 } 65 66 object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err); 67 if (err) { 68 error_propagate(errp, err); 69 return; 70 } 71 72 object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err); 73 if (err) { 74 error_propagate(errp, err); 75 return; 76 } 77 78 object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals), 79 "sd-bus", &err); 80 if (err) { 81 error_propagate(errp, err); 82 return; 83 } 84 85 sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0, 86 BCM2836_PERI_BASE, 1); 87 88 /* bcm2836 interrupt controller (and mailboxes, etc.) */ 89 object_property_set_bool(OBJECT(&s->control), true, "realized", &err); 90 if (err) { 91 error_propagate(errp, err); 92 return; 93 } 94 95 sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE); 96 97 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0, 98 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0)); 99 sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1, 100 qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0)); 101 102 for (n = 0; n < BCM2836_NCPUS; n++) { 103 /* Mirror bcm2836, which has clusterid set to 0xf 104 * TODO: this should be converted to a property of ARM_CPU 105 */ 106 s->cpus[n].mp_affinity = 0xF00 | n; 107 108 /* set periphbase/CBAR value for CPU-local registers */ 109 object_property_set_int(OBJECT(&s->cpus[n]), 110 BCM2836_PERI_BASE + MCORE_OFFSET, 111 "reset-cbar", &err); 112 if (err) { 113 error_propagate(errp, err); 114 return; 115 } 116 117 /* start powered off if not enabled */ 118 object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus, 119 "start-powered-off", &err); 120 if (err) { 121 error_propagate(errp, err); 122 return; 123 } 124 125 object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err); 126 if (err) { 127 error_propagate(errp, err); 128 return; 129 } 130 131 /* Connect irq/fiq outputs from the interrupt controller. */ 132 qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n, 133 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ)); 134 qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n, 135 qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ)); 136 137 /* Connect timers from the CPU to the interrupt controller */ 138 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS, 139 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n)); 140 qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT, 141 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n)); 142 } 143 } 144 145 static Property bcm2836_props[] = { 146 DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS), 147 DEFINE_PROP_END_OF_LIST() 148 }; 149 150 static void bcm2836_class_init(ObjectClass *oc, void *data) 151 { 152 DeviceClass *dc = DEVICE_CLASS(oc); 153 154 dc->props = bcm2836_props; 155 dc->realize = bcm2836_realize; 156 157 /* 158 * Reason: creates an ARM CPU, thus use after free(), see 159 * arm_cpu_class_init() 160 */ 161 dc->cannot_destroy_with_object_finalize_yet = true; 162 } 163 164 static const TypeInfo bcm2836_type_info = { 165 .name = TYPE_BCM2836, 166 .parent = TYPE_SYS_BUS_DEVICE, 167 .instance_size = sizeof(BCM2836State), 168 .instance_init = bcm2836_init, 169 .class_init = bcm2836_class_init, 170 }; 171 172 static void bcm2836_register_types(void) 173 { 174 type_register_static(&bcm2836_type_info); 175 } 176 177 type_init(bcm2836_register_types) 178