qemu/hw/arm/bcm2836.c
<<
>>
Prefs
   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
  19typedef 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
  36static Property bcm2836_enabled_cores_property =
  37    DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
  38
  39static 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
  67static 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
  91static 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
 110static 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
 172static 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
 180static 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
 191static 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
 205static 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
 219static 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
 245DEFINE_TYPES(bcm283x_types)
 246