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 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
  19struct 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
  27static 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
  46static 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
  70static 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
 170static Property bcm2836_props[] = {
 171    DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
 172                       BCM283X_NCPUS),
 173    DEFINE_PROP_END_OF_LIST()
 174};
 175
 176static 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    dc->props = bcm2836_props;
 184    /* Reason: Must be wired up in code (see raspi_init() function) */
 185    dc->user_creatable = false;
 186}
 187
 188static 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
 197static 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
 213type_init(bcm2836_register_types)
 214