qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

bcm2836.c (8022B)


      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 work is licensed under the terms of the GNU GPL, version 2 or later.
      9  * See the COPYING file in the top-level directory.
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "qapi/error.h"
     14 #include "qemu/module.h"
     15 #include "hw/arm/bcm2836.h"
     16 #include "hw/arm/raspi_platform.h"
     17 #include "hw/sysbus.h"
     18 
     19 typedef struct BCM283XClass {
     20     /*< private >*/
     21     DeviceClass parent_class;
     22     /*< public >*/
     23     const char *name;
     24     const char *cpu_type;
     25     unsigned core_count;
     26     hwaddr peri_base; /* Peripheral base address seen by the CPU */
     27     hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
     28     int clusterid;
     29 } BCM283XClass;
     30 
     31 #define BCM283X_CLASS(klass) \
     32     OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
     33 #define BCM283X_GET_CLASS(obj) \
     34     OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
     35 
     36 static Property bcm2836_enabled_cores_property =
     37     DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
     38 
     39 static void bcm2836_init(Object *obj)
     40 {
     41     BCM283XState *s = BCM283X(obj);
     42     BCM283XClass *bc = BCM283X_GET_CLASS(obj);
     43     int n;
     44 
     45     for (n = 0; n < bc->core_count; n++) {
     46         object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
     47                                 bc->cpu_type);
     48     }
     49     if (bc->core_count > 1) {
     50         qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
     51         qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
     52     }
     53 
     54     if (bc->ctrl_base) {
     55         object_initialize_child(obj, "control", &s->control,
     56                                 TYPE_BCM2836_CONTROL);
     57     }
     58 
     59     object_initialize_child(obj, "peripherals", &s->peripherals,
     60                             TYPE_BCM2835_PERIPHERALS);
     61     object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
     62                               "board-rev");
     63     object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
     64                               "vcram-size");
     65 }
     66 
     67 static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
     68 {
     69     BCM283XState *s = BCM283X(dev);
     70     BCM283XClass *bc = BCM283X_GET_CLASS(dev);
     71     Object *obj;
     72 
     73     /* common peripherals from bcm2835 */
     74 
     75     obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
     76 
     77     object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
     78 
     79     if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
     80         return false;
     81     }
     82 
     83     object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
     84                               "sd-bus");
     85 
     86     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
     87                             bc->peri_base, 1);
     88     return true;
     89 }
     90 
     91 static void bcm2835_realize(DeviceState *dev, Error **errp)
     92 {
     93     BCM283XState *s = BCM283X(dev);
     94 
     95     if (!bcm283x_common_realize(dev, errp)) {
     96         return;
     97     }
     98 
     99     if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
    100         return;
    101     }
    102 
    103     /* Connect irq/fiq outputs from the interrupt controller. */
    104     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
    105             qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
    106     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
    107             qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
    108 }
    109 
    110 static void bcm2836_realize(DeviceState *dev, Error **errp)
    111 {
    112     BCM283XState *s = BCM283X(dev);
    113     BCM283XClass *bc = BCM283X_GET_CLASS(dev);
    114     int n;
    115 
    116     if (!bcm283x_common_realize(dev, errp)) {
    117         return;
    118     }
    119 
    120     /* bcm2836 interrupt controller (and mailboxes, etc.) */
    121     if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
    122         return;
    123     }
    124 
    125     sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
    126 
    127     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
    128         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
    129     sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
    130         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
    131 
    132     for (n = 0; n < BCM283X_NCPUS; n++) {
    133         /* TODO: this should be converted to a property of ARM_CPU */
    134         s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
    135 
    136         /* set periphbase/CBAR value for CPU-local registers */
    137         if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
    138                                      bc->peri_base, errp)) {
    139             return;
    140         }
    141 
    142         /* start powered off if not enabled */
    143         if (!object_property_set_bool(OBJECT(&s->cpu[n].core),
    144                                       "start-powered-off",
    145                                       n >= s->enabled_cpus,
    146                                       errp)) {
    147             return;
    148         }
    149 
    150         if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, errp)) {
    151             return;
    152         }
    153 
    154         /* Connect irq/fiq outputs from the interrupt controller. */
    155         qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
    156                 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ));
    157         qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
    158                 qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ));
    159 
    160         /* Connect timers from the CPU to the interrupt controller */
    161         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS,
    162                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
    163         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT,
    164                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
    165         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP,
    166                 qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
    167         qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC,
    168                 qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
    169     }
    170 }
    171 
    172 static void bcm283x_class_init(ObjectClass *oc, void *data)
    173 {
    174     DeviceClass *dc = DEVICE_CLASS(oc);
    175 
    176     /* Reason: Must be wired up in code (see raspi_init() function) */
    177     dc->user_creatable = false;
    178 }
    179 
    180 static void bcm2835_class_init(ObjectClass *oc, void *data)
    181 {
    182     DeviceClass *dc = DEVICE_CLASS(oc);
    183     BCM283XClass *bc = BCM283X_CLASS(oc);
    184 
    185     bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
    186     bc->core_count = 1;
    187     bc->peri_base = 0x20000000;
    188     dc->realize = bcm2835_realize;
    189 };
    190 
    191 static void bcm2836_class_init(ObjectClass *oc, void *data)
    192 {
    193     DeviceClass *dc = DEVICE_CLASS(oc);
    194     BCM283XClass *bc = BCM283X_CLASS(oc);
    195 
    196     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
    197     bc->core_count = BCM283X_NCPUS;
    198     bc->peri_base = 0x3f000000;
    199     bc->ctrl_base = 0x40000000;
    200     bc->clusterid = 0xf;
    201     dc->realize = bcm2836_realize;
    202 };
    203 
    204 #ifdef TARGET_AARCH64
    205 static void bcm2837_class_init(ObjectClass *oc, void *data)
    206 {
    207     DeviceClass *dc = DEVICE_CLASS(oc);
    208     BCM283XClass *bc = BCM283X_CLASS(oc);
    209 
    210     bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
    211     bc->core_count = BCM283X_NCPUS;
    212     bc->peri_base = 0x3f000000;
    213     bc->ctrl_base = 0x40000000;
    214     bc->clusterid = 0x0;
    215     dc->realize = bcm2836_realize;
    216 };
    217 #endif
    218 
    219 static const TypeInfo bcm283x_types[] = {
    220     {
    221         .name           = TYPE_BCM2835,
    222         .parent         = TYPE_BCM283X,
    223         .class_init     = bcm2835_class_init,
    224     }, {
    225         .name           = TYPE_BCM2836,
    226         .parent         = TYPE_BCM283X,
    227         .class_init     = bcm2836_class_init,
    228 #ifdef TARGET_AARCH64
    229     }, {
    230         .name           = TYPE_BCM2837,
    231         .parent         = TYPE_BCM283X,
    232         .class_init     = bcm2837_class_init,
    233 #endif
    234     }, {
    235         .name           = TYPE_BCM283X,
    236         .parent         = TYPE_DEVICE,
    237         .instance_size  = sizeof(BCM283XState),
    238         .instance_init  = bcm2836_init,
    239         .class_size     = sizeof(BCM283XClass),
    240         .class_init     = bcm283x_class_init,
    241         .abstract       = true,
    242     }
    243 };
    244 
    245 DEFINE_TYPES(bcm283x_types)