All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support
@ 2016-01-01  0:31 Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 1/7] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
                   ` (6 more replies)
  0 siblings, 7 replies; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This patch series adds initial support for Raspberry Pi 2
(bcm2836). It is heavily based on the original (out of tree) work of
Gregory Estrade, Stefan Weil and others to support Raspberry Pi
1. Thanks are also due to Peter Crosthwaite for the code reviews and
feedback.

At the end of this series, it is possible to boot a recent raspbian
kernel to a serial console using an invocation such as:

  qemu-system-arm -M raspi2 -kernel raspbian-boot/kernel7.img -sd
  2015-09-24-raspbian-jessie.vhd -append "rw earlyprintk loglevel=8
  console=ttyAMA0 root=/dev/mmcblk0p2" -serial stdio

(where raspbian-boot is the boot partition from the matching image,
and after commenting-out or removing /etc/ld.so.preload to avoid an
unimplemented setend instruction).

I plan to add DMA, USB, framebuffer, timers, and other system devices
(power, mphi, aux/uart1) in future patches. In the meantime, the
complete code is available at: https://github.com/0xabu/qemu

Although this series includes many of the peripherals common to Pi1
(aka bcm2835 aka Pi0), it's not yet possible to boot a Pi1, because it
requires additional peripherals, so I'll also add that SoC and machine
in a later patch.

v2 changes:
 * cleanup based on reviews of mbox and ic devices by Peter Crosthwaite
   (see specific notes on each patch)
 * removed custom SD controller in favour of sdhci

v3 changes:
 * cleanup/tweaks to mbox, ic, peripherals and bcm2836_control devices from v2 review
 * changed how I allocate and pass ram from the board through to the SoC
 * cleanup raspi_platform.h
 * s/_/-/ in device/property/type names

Cheers,
Andrew

Andrew Baumann (7):
  bcm2835_mbox: add BCM2835 mailboxes
  bcm2835_property: add bcm2835 property channel
  bcm2835_ic: add bcm2835 interrupt controller
  bcm2835_peripherals: add rollup device for bcm2835 peripherals
  bcm2836_control: add bcm2836 ARM control logic
  bcm2836: add bcm2836 soc device
  raspi: add raspberry pi 2 machine

 default-configs/arm-softmmu.mak      |   1 +
 hw/arm/Makefile.objs                 |   1 +
 hw/arm/bcm2835_peripherals.c         | 205 +++++++++++++++++++++
 hw/arm/bcm2836.c                     | 155 ++++++++++++++++
 hw/arm/raspi.c                       | 180 +++++++++++++++++++
 hw/intc/Makefile.objs                |   1 +
 hw/intc/bcm2835_ic.c                 | 236 +++++++++++++++++++++++++
 hw/intc/bcm2836_control.c            | 317 +++++++++++++++++++++++++++++++++
 hw/misc/Makefile.objs                |   2 +
 hw/misc/bcm2835_mbox.c               | 333 +++++++++++++++++++++++++++++++++++
 hw/misc/bcm2835_property.c           | 277 +++++++++++++++++++++++++++++
 include/hw/arm/bcm2835_peripherals.h |  42 +++++
 include/hw/arm/bcm2836.h             |  33 ++++
 include/hw/arm/raspi_platform.h      | 128 ++++++++++++++
 include/hw/intc/bcm2835_ic.h         |  33 ++++
 include/hw/intc/bcm2836_control.h    |  51 ++++++
 include/hw/misc/bcm2835_mbox.h       |  37 ++++
 include/hw/misc/bcm2835_mbox_defs.h  |  27 +++
 include/hw/misc/bcm2835_property.h   |  29 +++
 19 files changed, 2088 insertions(+)
 create mode 100644 hw/arm/bcm2835_peripherals.c
 create mode 100644 hw/arm/bcm2836.c
 create mode 100644 hw/arm/raspi.c
 create mode 100644 hw/intc/bcm2835_ic.c
 create mode 100644 hw/intc/bcm2836_control.c
 create mode 100644 hw/misc/bcm2835_mbox.c
 create mode 100644 hw/misc/bcm2835_property.c
 create mode 100644 include/hw/arm/bcm2835_peripherals.h
 create mode 100644 include/hw/arm/bcm2836.h
 create mode 100644 include/hw/arm/raspi_platform.h
 create mode 100644 include/hw/intc/bcm2835_ic.h
 create mode 100644 include/hw/intc/bcm2836_control.h
 create mode 100644 include/hw/misc/bcm2835_mbox.h
 create mode 100644 include/hw/misc/bcm2835_mbox_defs.h
 create mode 100644 include/hw/misc/bcm2835_property.h

-- 
2.5.3

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 1/7] bcm2835_mbox: add BCM2835 mailboxes
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel Andrew Baumann
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This adds the system mailboxes which are used to communicate with a
number of GPU peripherals on Pi/Pi2.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---

Notes:
    v3:
     * #define register offsets
     * rename mbox_init -> mbox_reset
     * s/_/-/ in property and type names
     * avoid hw_error
     * minor style tweaks
    
    v2:
     * renamed bcm2835_sbm to bcm2835_mbox
     * dropped bcm2835_arm_control.h (needed defs moved to bcm2835_mbox.c)
     * documented use of private address space through defines in bcm2835_mbox_defs.h
     * remove unused fields from BCM2835Mbox
     * s/int/bool/ where appropriate
     * cleaned up logic in _update and _mbox_update_status for clarity/simplicity
     * added vmstate
     * misc cleanup

 default-configs/arm-softmmu.mak     |   1 +
 hw/misc/Makefile.objs               |   1 +
 hw/misc/bcm2835_mbox.c              | 333 ++++++++++++++++++++++++++++++++++++
 include/hw/misc/bcm2835_mbox.h      |  37 ++++
 include/hw/misc/bcm2835_mbox_defs.h |  27 +++
 5 files changed, 399 insertions(+)
 create mode 100644 hw/misc/bcm2835_mbox.c
 create mode 100644 include/hw/misc/bcm2835_mbox.h
 create mode 100644 include/hw/misc/bcm2835_mbox_defs.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index d9b90a5..a9f82a1 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -79,6 +79,7 @@ CONFIG_TUSB6010=y
 CONFIG_IMX=y
 CONFIG_MAINSTONE=y
 CONFIG_NSERIES=y
+CONFIG_RASPI=y
 CONFIG_REALVIEW=y
 CONFIG_ZAURUS=y
 CONFIG_ZYNQ=y
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index d4765c2..d0ea105 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -36,6 +36,7 @@ obj-$(CONFIG_OMAP) += omap_gpmc.o
 obj-$(CONFIG_OMAP) += omap_l4.o
 obj-$(CONFIG_OMAP) += omap_sdrc.o
 obj-$(CONFIG_OMAP) += omap_tap.o
+obj-$(CONFIG_RASPI) += bcm2835_mbox.o
 obj-$(CONFIG_SLAVIO) += slavio_misc.o
 obj-$(CONFIG_ZYNQ) += zynq_slcr.o
 obj-$(CONFIG_ZYNQ) += zynq-xadc.o
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
new file mode 100644
index 0000000..167bf59
--- /dev/null
+++ b/hw/misc/bcm2835_mbox.c
@@ -0,0 +1,333 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ *
+ * This file models the system mailboxes, which are used for
+ * communication with low-bandwidth GPU peripherals. Refs:
+ *   https://github.com/raspberrypi/firmware/wiki/Mailboxes
+ *   https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes
+ */
+
+#include "hw/misc/bcm2835_mbox.h"
+
+#define MAIL0_PEEK   0x90
+#define MAIL0_SENDER 0x94
+#define MAIL1_STATUS 0xb8
+
+/* Mailbox status register */
+#define MAIL0_STATUS 0x98
+#define ARM_MS_FULL       0x80000000
+#define ARM_MS_EMPTY      0x40000000
+#define ARM_MS_LEVEL      0x400000FF /* Max. value depends on mailbox depth */
+
+/* MAILBOX config/status register */
+#define MAIL0_CONFIG 0x9c
+/* ANY write to this register clears the error bits! */
+#define ARM_MC_IHAVEDATAIRQEN    0x00000001 /* mbox irq enable:  has data */
+#define ARM_MC_IHAVESPACEIRQEN   0x00000002 /* mbox irq enable:  has space */
+#define ARM_MC_OPPISEMPTYIRQEN   0x00000004 /* mbox irq enable: Opp is empty */
+#define ARM_MC_MAIL_CLEAR        0x00000008 /* mbox clear write 1, then  0 */
+#define ARM_MC_IHAVEDATAIRQPEND  0x00000010 /* mbox irq pending:  has space */
+#define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mbox irq pending: Opp is empty */
+#define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mbox irq pending */
+/* Bit 7 is unused */
+#define ARM_MC_ERRNOOWN   0x00000100 /* error : none owner read from mailbox */
+#define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */
+#define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */
+
+static void mbox_update_status(BCM2835Mbox *mb)
+{
+    mb->status &= ~(ARM_MS_EMPTY | ARM_MS_FULL);
+    if (mb->count == 0) {
+        mb->status |= ARM_MS_EMPTY;
+    } else if (mb->count == MBOX_SIZE) {
+        mb->status |= ARM_MS_FULL;
+    }
+}
+
+static void mbox_reset(BCM2835Mbox *mb)
+{
+    int n;
+
+    mb->count = 0;
+    mb->config = 0;
+    for (n = 0; n < MBOX_SIZE; n++) {
+        mb->reg[n] = MBOX_INVALID_DATA;
+    }
+    mbox_update_status(mb);
+}
+
+static uint32_t mbox_pull(BCM2835Mbox *mb, int index)
+{
+    int n;
+    uint32_t val;
+
+    assert(mb->count > 0);
+    assert(index < mb->count);
+
+    val = mb->reg[index];
+    for (n = index + 1; n < mb->count; n++) {
+        mb->reg[n - 1] = mb->reg[n];
+    }
+    mb->count--;
+    mb->reg[mb->count] = MBOX_INVALID_DATA;
+
+    mbox_update_status(mb);
+
+    return val;
+}
+
+static void mbox_push(BCM2835Mbox *mb, uint32_t val)
+{
+    assert(mb->count < MBOX_SIZE);
+    mb->reg[mb->count++] = val;
+    mbox_update_status(mb);
+}
+
+static void bcm2835_mbox_update(BCM2835MboxState *s)
+{
+    uint32_t value;
+    bool set;
+    int n;
+
+    s->mbox_irq_disabled = true;
+
+    /* Get pending responses and put them in the vc->arm mbox,
+     * as long as it's not full */
+    for (n = 0; n < MBOX_CHAN_COUNT; n++) {
+        while (s->available[n] && !(s->mbox[0].status & ARM_MS_FULL)) {
+            value = ldl_phys(&s->mbox_as, n << MBOX_AS_CHAN_SHIFT);
+            assert(value != MBOX_INVALID_DATA); /* Pending interrupt but no data */
+            mbox_push(&s->mbox[0], value);
+        }
+    }
+
+    /* Try to push pending requests from the arm->vc mbox */
+    /* TODO (?) */
+
+    /* Re-enable calls from the IRQ routine */
+    s->mbox_irq_disabled = false;
+
+    /* Update ARM IRQ status */
+    set = false;
+    s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQPEND;
+    if (!(s->mbox[0].status & ARM_MS_EMPTY)) {
+        s->mbox[0].config |= ARM_MC_IHAVEDATAIRQPEND;
+        if (s->mbox[0].config & ARM_MC_IHAVEDATAIRQEN) {
+            set = true;
+        }
+    }
+    qemu_set_irq(s->arm_irq, set);
+}
+
+static void bcm2835_mbox_set_irq(void *opaque, int irq, int level)
+{
+    BCM2835MboxState *s = opaque;
+
+    s->available[irq] = level;
+
+    /* avoid recursively calling bcm2835_mbox_update when the interrupt
+     * status changes due to the ldl_phys call within that function
+     */
+    if (!s->mbox_irq_disabled) {
+        bcm2835_mbox_update(s);
+    }
+}
+
+static uint64_t bcm2835_mbox_read(void *opaque, hwaddr offset, unsigned size)
+{
+    BCM2835MboxState *s = opaque;
+    uint32_t res = 0;
+
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x80 ... 0x8c: /* MAIL0_READ */
+        if (s->mbox[0].status & ARM_MS_EMPTY) {
+            res = MBOX_INVALID_DATA;
+        } else {
+            res = mbox_pull(&s->mbox[0], 0);
+        }
+        break;
+
+    case MAIL0_PEEK:
+        res = s->mbox[0].reg[0];
+        break;
+
+    case MAIL0_SENDER:
+        break;
+
+    case MAIL0_STATUS:
+        res = s->mbox[0].status;
+        break;
+
+    case MAIL0_CONFIG:
+        res = s->mbox[0].config;
+        break;
+
+    case MAIL1_STATUS:
+        res = s->mbox[1].status;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return 0;
+    }
+
+    bcm2835_mbox_update(s);
+
+    return res;
+}
+
+static void bcm2835_mbox_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    BCM2835MboxState *s = opaque;
+    hwaddr childaddr;
+    uint8_t ch;
+
+    offset &= 0xff;
+
+    switch (offset) {
+    case MAIL0_SENDER:
+        break;
+
+    case MAIL0_CONFIG:
+        s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQEN;
+        s->mbox[0].config |= value & ARM_MC_IHAVEDATAIRQEN;
+        break;
+
+    case 0xa0 ... 0xac: /* MAIL1_WRITE */
+        if (s->mbox[1].status & ARM_MS_FULL) {
+            /* Mailbox full */
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: mailbox full\n", __func__);
+        } else {
+            ch = value & 0xf;
+            if (ch < MBOX_CHAN_COUNT) {
+                childaddr = ch << MBOX_AS_CHAN_SHIFT;
+                if (ldl_phys(&s->mbox_as, childaddr + MBOX_AS_PENDING)) {
+                    /* Child busy, push delayed. Push it in the arm->vc mbox */
+                    mbox_push(&s->mbox[1], value);
+                } else {
+                    /* Push it directly to the child device */
+                    stl_phys(&s->mbox_as, childaddr, value);
+                }
+            } else {
+                /* Invalid channel number */
+                qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid channel %u\n",
+                              __func__, ch);
+            }
+        }
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return;
+    }
+
+    bcm2835_mbox_update(s);
+}
+
+static const MemoryRegionOps bcm2835_mbox_ops = {
+    .read = bcm2835_mbox_read,
+    .write = bcm2835_mbox_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
+/* vmstate of a single mailbox */
+static const VMStateDescription vmstate_bcm2835_mbox_box = {
+    .name = TYPE_BCM2835_MBOX "_box",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(reg, BCM2835Mbox, MBOX_SIZE),
+        VMSTATE_UINT32(count, BCM2835Mbox),
+        VMSTATE_UINT32(status, BCM2835Mbox),
+        VMSTATE_UINT32(config, BCM2835Mbox),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* vmstate of the entire device */
+static const VMStateDescription vmstate_bcm2835_mbox = {
+    .name = TYPE_BCM2835_MBOX,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT),
+        VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1,
+                             vmstate_bcm2835_mbox_box, BCM2835Mbox),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2835_mbox_init(Object *obj)
+{
+    BCM2835MboxState *s = BCM2835_MBOX(obj);
+
+    memory_region_init_io(&s->iomem, obj, &bcm2835_mbox_ops, s,
+                          TYPE_BCM2835_MBOX, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->arm_irq);
+    qdev_init_gpio_in(DEVICE(s), bcm2835_mbox_set_irq, MBOX_CHAN_COUNT);
+}
+
+static void bcm2835_mbox_reset(DeviceState *dev)
+{
+    BCM2835MboxState *s = BCM2835_MBOX(dev);
+    int n;
+
+    mbox_reset(&s->mbox[0]);
+    mbox_reset(&s->mbox[1]);
+    s->mbox_irq_disabled = false;
+    for (n = 0; n < MBOX_CHAN_COUNT; n++) {
+        s->available[n] = false;
+    }
+}
+
+static void bcm2835_mbox_realize(DeviceState *dev, Error **errp)
+{
+    BCM2835MboxState *s = BCM2835_MBOX(dev);
+    Object *obj;
+    Error *err = NULL;
+
+    obj = object_property_get_link(OBJECT(dev), "mbox-mr", &err);
+    if (obj == NULL) {
+        error_setg(errp, "%s: required mbox-mr link not found: %s",
+                   __func__, error_get_pretty(err));
+        return;
+    }
+
+    s->mbox_mr = MEMORY_REGION(obj);
+    address_space_init(&s->mbox_as, s->mbox_mr, NULL);
+    bcm2835_mbox_reset(dev);
+}
+
+static void bcm2835_mbox_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = bcm2835_mbox_realize;
+    dc->reset = bcm2835_mbox_reset;
+    dc->vmsd = &vmstate_bcm2835_mbox;
+}
+
+static TypeInfo bcm2835_mbox_info = {
+    .name          = TYPE_BCM2835_MBOX,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2835MboxState),
+    .class_init    = bcm2835_mbox_class_init,
+    .instance_init = bcm2835_mbox_init,
+};
+
+static void bcm2835_mbox_register_types(void)
+{
+    type_register_static(&bcm2835_mbox_info);
+}
+
+type_init(bcm2835_mbox_register_types)
diff --git a/include/hw/misc/bcm2835_mbox.h b/include/hw/misc/bcm2835_mbox.h
new file mode 100644
index 0000000..32ae077
--- /dev/null
+++ b/include/hw/misc/bcm2835_mbox.h
@@ -0,0 +1,37 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_MBOX_H
+#define BCM2835_MBOX_H
+
+#include "bcm2835_mbox_defs.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+#define TYPE_BCM2835_MBOX "bcm2835-mbox"
+#define BCM2835_MBOX(obj) \
+        OBJECT_CHECK(BCM2835MboxState, (obj), TYPE_BCM2835_MBOX)
+
+typedef struct {
+    uint32_t reg[MBOX_SIZE];
+    uint32_t count;
+    uint32_t status;
+    uint32_t config;
+} BCM2835Mbox;
+
+typedef struct {
+    /*< private >*/
+    SysBusDevice busdev;
+    /*< public >*/
+    MemoryRegion *mbox_mr;
+    AddressSpace mbox_as;
+    MemoryRegion iomem;
+    qemu_irq arm_irq;
+    bool mbox_irq_disabled;
+    bool available[MBOX_CHAN_COUNT];
+    BCM2835Mbox mbox[2];
+} BCM2835MboxState;
+
+#endif
diff --git a/include/hw/misc/bcm2835_mbox_defs.h b/include/hw/misc/bcm2835_mbox_defs.h
new file mode 100644
index 0000000..a18e520
--- /dev/null
+++ b/include/hw/misc/bcm2835_mbox_defs.h
@@ -0,0 +1,27 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_MBOX_DEFS_H
+#define BCM2835_MBOX_DEFS_H
+
+/* Constants shared with the ARM identifying separate mailbox channels */
+#define MBOX_CHAN_POWER    0 /* for use by the power management interface */
+#define MBOX_CHAN_FB       1 /* for use by the frame buffer */
+#define MBOX_CHAN_VCHIQ    3 /* for use by the VCHIQ interface */
+#define MBOX_CHAN_PROPERTY 8 /* for use by the property channel */
+#define MBOX_CHAN_COUNT    9
+
+#define MBOX_SIZE          32
+#define MBOX_INVALID_DATA  0x0f
+
+/* Layout of the private address space used for communication between
+ * the mbox device emulation, and child devices: each channel occupies
+ * 16 bytes of address space, but only two registers are presently defined.
+ */
+#define MBOX_AS_CHAN_SHIFT 4
+#define MBOX_AS_DATA       0 /* request / response data (RW at offset 0) */
+#define MBOX_AS_PENDING    4 /* pending response status (RO at offset 4) */
+
+#endif /* BCM2835_MBOX_DEFS_H */
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 1/7] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-12  3:53   ` Peter Crosthwaite
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 3/7] bcm2835_ic: add bcm2835 interrupt controller Andrew Baumann
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This sits behind the mailbox interface, and implements
request/response queries for system properties. The
framebuffer-related properties will be added in a later patch.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
 hw/misc/Makefile.objs              |   1 +
 hw/misc/bcm2835_property.c         | 277 +++++++++++++++++++++++++++++++++++++
 include/hw/misc/bcm2835_property.h |  29 ++++
 3 files changed, 307 insertions(+)
 create mode 100644 hw/misc/bcm2835_property.c
 create mode 100644 include/hw/misc/bcm2835_property.h

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index d0ea105..ea6cd3c 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -37,6 +37,7 @@ obj-$(CONFIG_OMAP) += omap_l4.o
 obj-$(CONFIG_OMAP) += omap_sdrc.o
 obj-$(CONFIG_OMAP) += omap_tap.o
 obj-$(CONFIG_RASPI) += bcm2835_mbox.o
+obj-$(CONFIG_RASPI) += bcm2835_property.o
 obj-$(CONFIG_SLAVIO) += slavio_misc.o
 obj-$(CONFIG_ZYNQ) += zynq_slcr.o
 obj-$(CONFIG_ZYNQ) += zynq-xadc.o
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
new file mode 100644
index 0000000..2385be4
--- /dev/null
+++ b/hw/misc/bcm2835_property.c
@@ -0,0 +1,277 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/misc/bcm2835_property.h"
+#include "hw/misc/bcm2835_mbox_defs.h"
+
+/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
+
+static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
+{
+    uint32_t tag;
+    uint32_t bufsize;
+    uint32_t tot_len;
+    size_t resplen;
+    uint32_t tmp;
+
+    value &= ~0xf;
+
+    s->addr = value;
+
+    tot_len = ldl_phys(&s->dma_as, value);
+
+    /* @(addr + 4) : Buffer response code */
+    value = s->addr + 8;
+    while (value + 8 <= s->addr + tot_len) {
+        tag = ldl_phys(&s->dma_as, value);
+        bufsize = ldl_phys(&s->dma_as, value + 4);
+        /* @(value + 8) : Request/response indicator */
+        resplen = 0;
+        switch (tag) {
+        case 0x00000000: /* End tag */
+            break;
+        case 0x00000001: /* Get firmware revision */
+            stl_phys(&s->dma_as, value + 12, 346337);
+            resplen = 4;
+            break;
+
+        case 0x00010001: /* Get board model */
+            resplen = 4;
+            break;
+        case 0x00010002: /* Get board revision */
+            resplen = 4;
+            break;
+        case 0x00010003: /* Get board MAC address */
+            /* write the first four bytes of the 6-byte MAC */
+            stl_phys(&s->dma_as, value + 12, 0xB827EBD0);
+            /* write the last two bytes, avoid any write past the buffer end */
+            stb_phys(&s->dma_as, value + 16, 0xEE);
+            stb_phys(&s->dma_as, value + 17, 0xDF);
+            resplen = 6;
+            break;
+        case 0x00010004: /* Get board serial */
+            resplen = 8;
+            break;
+        case 0x00010005: /* Get ARM memory */
+            /* base */
+            stl_phys(&s->dma_as, value + 12, 0);
+            /* size */
+            stl_phys(&s->dma_as, value + 16, s->ram_size);
+            resplen = 8;
+            break;
+        case 0x00028001: /* Set power state */
+            /* Assume that whatever device they asked for exists,
+             * and we'll just claim we set it to the desired state */
+            tmp = ldl_phys(&s->dma_as, value + 16);
+            stl_phys(&s->dma_as, value + 16, (tmp & 1));
+            resplen = 8;
+            break;
+
+        /* Clocks */
+
+        case 0x00030001: /* Get clock state */
+            stl_phys(&s->dma_as, value + 16, 0x1);
+            resplen = 8;
+            break;
+
+        case 0x00038001: /* Set clock state */
+            resplen = 8;
+            break;
+
+        case 0x00030002: /* Get clock rate */
+        case 0x00030004: /* Get max clock rate */
+        case 0x00030007: /* Get min clock rate */
+            switch (ldl_phys(&s->dma_as, value + 12)) {
+            case 1: /* EMMC */
+                stl_phys(&s->dma_as, value + 16, 50000000);
+                break;
+            case 2: /* UART */
+                stl_phys(&s->dma_as, value + 16, 3000000);
+                break;
+            default:
+                stl_phys(&s->dma_as, value + 16, 700000000);
+                break;
+            }
+            resplen = 8;
+            break;
+
+        case 0x00038002: /* Set clock rate */
+        case 0x00038004: /* Set max clock rate */
+        case 0x00038007: /* Set min clock rate */
+            resplen = 8;
+            break;
+
+        /* Temperature */
+
+        case 0x00030006: /* Get temperature */
+            stl_phys(&s->dma_as, value + 16, 25000);
+            resplen = 8;
+            break;
+
+        case 0x0003000A: /* Get max temperature */
+            stl_phys(&s->dma_as, value + 16, 99000);
+            resplen = 8;
+            break;
+
+
+        case 0x00060001: /* Get DMA channels */
+            /* channels 2-5 */
+            stl_phys(&s->dma_as, value + 12, 0x003C);
+            resplen = 4;
+            break;
+
+        case 0x00050001: /* Get command line */
+            resplen = 0;
+            break;
+
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "bcm2835_property: unhandled tag %08x\n", tag);
+            break;
+        }
+
+        if (tag == 0) {
+            break;
+        }
+
+        stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
+        value += bufsize + 12;
+    }
+
+    /* Buffer response code */
+    stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
+}
+
+static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    BCM2835PropertyState *s = opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case MBOX_AS_DATA:
+        res = MBOX_CHAN_PROPERTY | s->addr;
+        s->pending = false;
+        qemu_set_irq(s->mbox_irq, 0);
+        break;
+
+    case MBOX_AS_PENDING:
+        res = s->pending;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return 0;
+    }
+
+    return res;
+}
+
+static void bcm2835_property_write(void *opaque, hwaddr offset,
+                                   uint64_t value, unsigned size)
+{
+    BCM2835PropertyState *s = opaque;
+
+    switch (offset) {
+    case MBOX_AS_DATA:
+        if (!s->pending) {
+            s->pending = true;
+            bcm2835_property_mbox_push(s, value);
+            qemu_set_irq(s->mbox_irq, 1);
+        }
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return;
+    }
+
+}
+
+static const MemoryRegionOps bcm2835_property_ops = {
+    .read = bcm2835_property_read,
+    .write = bcm2835_property_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_bcm2835_property = {
+    .name = TYPE_BCM2835_PROPERTY,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(addr, BCM2835PropertyState),
+        VMSTATE_BOOL(pending, BCM2835PropertyState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2835_property_init(Object *obj)
+{
+    BCM2835PropertyState *s = BCM2835_PROPERTY(obj);
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
+                          TYPE_BCM2835_PROPERTY, 0x10);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
+}
+
+static void bcm2835_property_reset(DeviceState *dev)
+{
+    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
+
+    s->pending = false;
+}
+
+static void bcm2835_property_realize(DeviceState *dev, Error **errp)
+{
+    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
+    Object *obj;
+    Error *err = NULL;
+
+    obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
+    if (obj == NULL) {
+        error_setg(errp, "%s: required dma-mr link not found: %s",
+                   __func__, error_get_pretty(err));
+        return;
+    }
+
+    s->dma_mr = MEMORY_REGION(obj);
+    address_space_init(&s->dma_as, s->dma_mr, NULL);
+
+    bcm2835_property_reset(dev);
+}
+
+static Property bcm2835_property_props[] = {
+    DEFINE_PROP_UINT32("ram-size", BCM2835PropertyState, ram_size, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void bcm2835_property_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = bcm2835_property_props;
+    dc->realize = bcm2835_property_realize;
+    dc->vmsd = &vmstate_bcm2835_property;
+}
+
+static TypeInfo bcm2835_property_info = {
+    .name          = TYPE_BCM2835_PROPERTY,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2835PropertyState),
+    .class_init    = bcm2835_property_class_init,
+    .instance_init = bcm2835_property_init,
+};
+
+static void bcm2835_property_register_types(void)
+{
+    type_register_static(&bcm2835_property_info);
+}
+
+type_init(bcm2835_property_register_types)
diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h
new file mode 100644
index 0000000..d7a9856
--- /dev/null
+++ b/include/hw/misc/bcm2835_property.h
@@ -0,0 +1,29 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_PROPERTY_H
+#define BCM2835_PROPERTY_H
+
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+
+#define TYPE_BCM2835_PROPERTY "bcm2835-property"
+#define BCM2835_PROPERTY(obj) \
+        OBJECT_CHECK(BCM2835PropertyState, (obj), TYPE_BCM2835_PROPERTY)
+
+typedef struct {
+    /*< private >*/
+    SysBusDevice busdev;
+    /*< public >*/
+    MemoryRegion *dma_mr;
+    AddressSpace dma_as;
+    MemoryRegion iomem;
+    qemu_irq mbox_irq;
+    uint32_t ram_size;
+    uint32_t addr;
+    bool pending;
+} BCM2835PropertyState;
+
+#endif
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 3/7] bcm2835_ic: add bcm2835 interrupt controller
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 1/7] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
---

Notes:
    v3:
     * minor style tweaks
     * use extract32 in place of manual shift/masking
    
    v2 changes:
     * split inputs to named gpu_irq and arm_irq gpio inputs
     * use 64-bit gpu_irq and 8-bit arm_irq status rather than 3*32-bit bitfields
     * added defined names for register offsets
     * deleted nop realize method
     * other misc cleanup suggested in review

 hw/intc/Makefile.objs        |   1 +
 hw/intc/bcm2835_ic.c         | 236 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/intc/bcm2835_ic.h |  33 ++++++
 3 files changed, 270 insertions(+)
 create mode 100644 hw/intc/bcm2835_ic.c
 create mode 100644 include/hw/intc/bcm2835_ic.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 004b0c2..2ad1204 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -24,6 +24,7 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
 obj-$(CONFIG_IOAPIC) += ioapic.o
 obj-$(CONFIG_OMAP) += omap_intc.o
 obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
+obj-$(CONFIG_RASPI) += bcm2835_ic.o
 obj-$(CONFIG_SH4) += sh_intc.o
 obj-$(CONFIG_XICS) += xics.o
 obj-$(CONFIG_XICS_KVM) += xics_kvm.o
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
new file mode 100644
index 0000000..005a72b
--- /dev/null
+++ b/hw/intc/bcm2835_ic.c
@@ -0,0 +1,236 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
+ * This code is licensed under the GNU GPLv2 and later.
+ * Heavily based on pl190.c, copyright terms below:
+ *
+ * Arm PrimeCell PL190 Vector Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/intc/bcm2835_ic.h"
+
+#define GPU_IRQS 64
+#define ARM_IRQS 8
+
+#define IRQ_PENDING_BASIC       0x00 /* IRQ basic pending */
+#define IRQ_PENDING_1           0x04 /* IRQ pending 1 */
+#define IRQ_PENDING_2           0x08 /* IRQ pending 2 */
+#define FIQ_CONTROL             0x0C /* FIQ register */
+#define IRQ_ENABLE_1            0x10 /* Interrupt enable register 1 */
+#define IRQ_ENABLE_2            0x14 /* Interrupt enable register 2 */
+#define IRQ_ENABLE_BASIC        0x18 /* Base interrupt enable register */
+#define IRQ_DISABLE_1           0x1C /* Interrupt disable register 1 */
+#define IRQ_DISABLE_2           0x20 /* Interrupt disable register 2 */
+#define IRQ_DISABLE_BASIC       0x24 /* Base interrupt disable register */
+
+/* Update interrupts.  */
+static void bcm2835_ic_update(BCM2835ICState *s)
+{
+    bool set = false;
+
+    if (s->fiq_enable) {
+        if (s->fiq_select >= GPU_IRQS) {
+            /* ARM IRQ */
+            set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
+        } else {
+            set = extract64(s->gpu_irq_level, s->fiq_select, 1);
+        }
+    }
+    qemu_set_irq(s->fiq, set);
+
+    set = (s->gpu_irq_level & s->gpu_irq_enable)
+        || (s->arm_irq_level & s->arm_irq_enable);
+    qemu_set_irq(s->irq, set);
+
+}
+
+static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
+{
+    BCM2835ICState *s = opaque;
+
+    assert(irq >= 0 && irq < 64);
+    s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
+    bcm2835_ic_update(s);
+}
+
+static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
+{
+    BCM2835ICState *s = opaque;
+
+    assert(irq >= 0 && irq < 8);
+    s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
+    bcm2835_ic_update(s);
+}
+
+static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
+
+static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
+{
+    BCM2835ICState *s = opaque;
+    uint32_t res = 0;
+    uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
+    int i;
+
+    switch (offset) {
+    case IRQ_PENDING_BASIC:
+        /* bits 0-7: ARM irqs */
+        res = s->arm_irq_level & s->arm_irq_enable;
+
+        /* bits 8 & 9: pending registers 1 & 2 */
+        res |= (((uint32_t)gpu_pending) != 0) << 8;
+        res |= ((gpu_pending >> 32) != 0) << 9;
+
+        /* bits 10-20: selected GPU IRQs */
+        for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
+            res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
+        }
+        break;
+    case IRQ_PENDING_1:
+        res = gpu_pending;
+        break;
+    case IRQ_PENDING_2:
+        res = gpu_pending >> 32;
+        break;
+    case FIQ_CONTROL:
+        res = (s->fiq_enable << 7) | s->fiq_select;
+        break;
+    case IRQ_ENABLE_1:
+        res = s->gpu_irq_enable;
+        break;
+    case IRQ_ENABLE_2:
+        res = s->gpu_irq_enable >> 32;
+        break;
+    case IRQ_ENABLE_BASIC:
+        res = s->arm_irq_enable;
+        break;
+    case IRQ_DISABLE_1:
+        res = ~s->gpu_irq_enable;
+        break;
+    case IRQ_DISABLE_2:
+        res = ~s->gpu_irq_enable >> 32;
+        break;
+    case IRQ_DISABLE_BASIC:
+        res = ~s->arm_irq_enable;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return 0;
+    }
+
+    return res;
+}
+
+static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
+                             unsigned size)
+{
+    BCM2835ICState *s = opaque;
+
+    switch (offset) {
+    case FIQ_CONTROL:
+        s->fiq_select = extract32(val, 0, 7);
+        s->fiq_enable = extract32(val, 7, 1);
+        break;
+    case IRQ_ENABLE_1:
+        s->gpu_irq_enable |= val;
+        break;
+    case IRQ_ENABLE_2:
+        s->gpu_irq_enable |= val << 32;
+        break;
+    case IRQ_ENABLE_BASIC:
+        s->arm_irq_enable |= val & 0xff;
+        break;
+    case IRQ_DISABLE_1:
+        s->gpu_irq_enable &= ~val;
+        break;
+    case IRQ_DISABLE_2:
+        s->gpu_irq_enable &= ~(val << 32);
+        break;
+    case IRQ_DISABLE_BASIC:
+        s->arm_irq_enable &= ~val & 0xff;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return;
+    }
+    bcm2835_ic_update(s);
+}
+
+static const MemoryRegionOps bcm2835_ic_ops = {
+    .read = bcm2835_ic_read,
+    .write = bcm2835_ic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
+static void bcm2835_ic_reset(DeviceState *d)
+{
+    BCM2835ICState *s = BCM2835_IC(d);
+
+    s->gpu_irq_enable = 0;
+    s->arm_irq_enable = 0;
+    s->fiq_enable = false;
+    s->fiq_select = 0;
+}
+
+static void bcm2835_ic_init(Object *obj)
+{
+    BCM2835ICState *s = BCM2835_IC(obj);
+
+    memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
+                          0x200);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+
+    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
+                            BCM2835_IC_GPU_IRQ, GPU_IRQS);
+    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
+                            BCM2835_IC_ARM_IRQ, ARM_IRQS);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
+}
+
+static const VMStateDescription vmstate_bcm2835_ic = {
+    .name = TYPE_BCM2835_IC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
+        VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
+        VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
+        VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
+        VMSTATE_BOOL(fiq_enable, BCM2835ICState),
+        VMSTATE_UINT8(fiq_select, BCM2835ICState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = bcm2835_ic_reset;
+    dc->vmsd = &vmstate_bcm2835_ic;
+}
+
+static TypeInfo bcm2835_ic_info = {
+    .name          = TYPE_BCM2835_IC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2835ICState),
+    .class_init    = bcm2835_ic_class_init,
+    .instance_init = bcm2835_ic_init,
+};
+
+static void bcm2835_ic_register_types(void)
+{
+    type_register_static(&bcm2835_ic_info);
+}
+
+type_init(bcm2835_ic_register_types)
diff --git a/include/hw/intc/bcm2835_ic.h b/include/hw/intc/bcm2835_ic.h
new file mode 100644
index 0000000..fb75fa0
--- /dev/null
+++ b/include/hw/intc/bcm2835_ic.h
@@ -0,0 +1,33 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_IC_H
+#define BCM2835_IC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_BCM2835_IC "bcm2835-ic"
+#define BCM2835_IC(obj) OBJECT_CHECK(BCM2835ICState, (obj), TYPE_BCM2835_IC)
+
+#define BCM2835_IC_GPU_IRQ "gpu-irq"
+#define BCM2835_IC_ARM_IRQ "arm-irq"
+
+typedef struct BCM2835ICState {
+    /*< private >*/
+    SysBusDevice busdev;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq fiq;
+
+    /* 64 GPU IRQs + 8 ARM IRQs = 72 total (GPU first) */
+    uint64_t gpu_irq_level, gpu_irq_enable;
+    uint8_t arm_irq_level, arm_irq_enable;
+    bool fiq_enable;
+    uint8_t fiq_select;
+} BCM2835ICState;
+
+#endif
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
                   ` (2 preceding siblings ...)
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 3/7] bcm2835_ic: add bcm2835 interrupt controller Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-06  2:13   ` Alistair Francis
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This device maintains all the non-CPU peripherals on bcm2835 (Pi1)
which are also present on bcm2836 (Pi2). It also implements the
private address spaces used for DMA and mailboxes.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---

Notes:
    v3:
     * clean up raspi_platform.h
     * s/_/-/ in type/property/child names
     * use memory_region_init where appropriate rather than memory_region_init_io
     * pass ram as link property
    
    v2 changes:
     * adapted to use common SDHCI emulation

 hw/arm/Makefile.objs                 |   1 +
 hw/arm/bcm2835_peripherals.c         | 205 +++++++++++++++++++++++++++++++++++
 include/hw/arm/bcm2835_peripherals.h |  42 +++++++
 include/hw/arm/raspi_platform.h      | 128 ++++++++++++++++++++++
 4 files changed, 376 insertions(+)
 create mode 100644 hw/arm/bcm2835_peripherals.c
 create mode 100644 include/hw/arm/bcm2835_peripherals.h
 create mode 100644 include/hw/arm/raspi_platform.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 2195b60..82cc142 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -11,6 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
+obj-$(CONFIG_RASPI) += bcm2835_peripherals.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
new file mode 100644
index 0000000..879a41d
--- /dev/null
+++ b/hw/arm/bcm2835_peripherals.c
@@ -0,0 +1,205 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/arm/bcm2835_peripherals.h"
+#include "hw/misc/bcm2835_mbox_defs.h"
+#include "hw/arm/raspi_platform.h"
+
+/* Peripheral base address on the VC (GPU) system bus */
+#define BCM2835_VC_PERI_BASE 0x7e000000
+
+/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
+#define BCM2835_SDHC_CAPAREG 0x52034b4
+
+static void bcm2835_peripherals_init(Object *obj)
+{
+    BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
+
+    /* Memory region for peripheral devices, which we export to our parent */
+    memory_region_init_io(&s->peri_mr, obj, NULL, s, "bcm2835-peripherals",
+                          0x1000000);
+    object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
+
+    /* Internal memory region for peripheral bus addresses (not exported) */
+    memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32);
+    object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL);
+
+    /* Internal memory region for request/response communication with
+     * mailbox-addressable peripherals (not exported)
+     */
+    memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox",
+                       MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT);
+
+    /* Interrupt Controller */
+    object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
+    object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);
+    qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
+
+    /* UART0 */
+    s->uart0 = SYS_BUS_DEVICE(object_new("pl011"));
+    object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
+    qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
+
+    /* Mailboxes */
+    object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
+    object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
+    qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default());
+
+    object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
+                                   OBJECT(&s->mbox_mr), &error_abort);
+
+    /* Property channel */
+    object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
+    object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
+    qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
+
+    object_property_add_const_link(OBJECT(&s->property), "dma-mr",
+                                   OBJECT(&s->gpu_bus_mr), &error_abort);
+
+    /* Extended Mass Media Controller */
+    object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI);
+    object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL);
+    qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default());
+}
+
+static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
+{
+    BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
+    Object *obj;
+    MemoryRegion *ram;
+    Error *err = NULL;
+    uint32_t ram_size;
+    int n;
+
+    obj = object_property_get_link(OBJECT(dev), "ram", &err);
+    if (obj == NULL) {
+        error_setg(errp, "%s: required ram link not found: %s",
+                   __func__, error_get_pretty(err));
+        return;
+    }
+
+    ram = MEMORY_REGION(obj);
+    ram_size = memory_region_size(ram);
+
+    /* Map peripherals and RAM into the GPU address space. */
+    memory_region_init_alias(&s->peri_mr_alias, OBJECT(s),
+                             "bcm2835-peripherals", &s->peri_mr, 0,
+                             memory_region_size(&s->peri_mr));
+
+    memory_region_add_subregion_overlap(&s->gpu_bus_mr, BCM2835_VC_PERI_BASE,
+                                        &s->peri_mr_alias, 1);
+
+    /* RAM is aliased four times (different cache configurations) on the GPU */
+    for (n = 0; n < 4; n++) {
+        memory_region_init_alias(&s->ram_alias[n], OBJECT(s),
+                                 "bcm2835-gpu-ram-alias[*]", ram, 0, ram_size);
+        memory_region_add_subregion_overlap(&s->gpu_bus_mr, (hwaddr)n << 30,
+                                            &s->ram_alias[n], 0);
+    }
+
+    /* Interrupt Controller */
+    object_property_set_bool(OBJECT(&s->ic), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
+                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
+    sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
+
+    /* UART0 */
+    object_property_set_bool(OBJECT(s->uart0), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    memory_region_add_subregion(&s->peri_mr, UART0_OFFSET,
+                                sysbus_mmio_get_region(s->uart0, 0));
+    sysbus_connect_irq(s->uart0, 0,
+        qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
+                               INTERRUPT_UART));
+
+    /* Mailboxes */
+    object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    memory_region_add_subregion(&s->peri_mr, ARMCTRL_0_SBM_OFFSET,
+                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mboxes), 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->mboxes), 0,
+        qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
+                               INTERRUPT_ARM_MAILBOX));
+
+    /* Property channel */
+    object_property_set_int(OBJECT(&s->property), ram_size, "ram-size", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    memory_region_add_subregion(&s->mbox_mr,
+                MBOX_CHAN_PROPERTY << MBOX_AS_CHAN_SHIFT,
+                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0,
+                      qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY));
+
+    /* Extended Mass Media Controller */
+    object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
+                            &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    memory_region_add_subregion(&s->peri_mr, EMMC_OFFSET,
+                sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
+        qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
+                               INTERRUPT_ARASANSDIO));
+}
+
+static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = bcm2835_peripherals_realize;
+}
+
+static const TypeInfo bcm2835_peripherals_type_info = {
+    .name = TYPE_BCM2835_PERIPHERALS,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2835PeripheralState),
+    .instance_init = bcm2835_peripherals_init,
+    .class_init = bcm2835_peripherals_class_init,
+};
+
+static void bcm2835_peripherals_register_types(void)
+{
+    type_register_static(&bcm2835_peripherals_type_info);
+}
+
+type_init(bcm2835_peripherals_register_types)
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
new file mode 100644
index 0000000..5d888dc
--- /dev/null
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -0,0 +1,42 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_PERIPHERALS_H
+#define BCM2835_PERIPHERALS_H
+
+#include "qemu-common.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "hw/intc/bcm2835_ic.h"
+#include "hw/misc/bcm2835_property.h"
+#include "hw/misc/bcm2835_mbox.h"
+#include "hw/sd/sdhci.h"
+
+#define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals"
+#define BCM2835_PERIPHERALS(obj) \
+    OBJECT_CHECK(BCM2835PeripheralState, (obj), TYPE_BCM2835_PERIPHERALS)
+
+typedef struct BCM2835PeripheralState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion peri_mr, peri_mr_alias, gpu_bus_mr, mbox_mr;
+    MemoryRegion ram_alias[4];
+    qemu_irq irq, fiq;
+
+    SysBusDevice *uart0;
+    BCM2835ICState ic;
+    BCM2835PropertyState property;
+    BCM2835MboxState mboxes;
+    SDHCIState sdhci;
+} BCM2835PeripheralState;
+
+#endif /* BCM2835_PERIPHERALS_H */
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
new file mode 100644
index 0000000..6467e88
--- /dev/null
+++ b/include/hw/arm/raspi_platform.h
@@ -0,0 +1,128 @@
+/*
+ * bcm2708 aka bcm2835/2836 aka Raspberry Pi/Pi2 SoC platform defines
+ *
+ * These definitions are derived from those in Raspbian Linux at
+ * arch/arm/mach-{bcm2708,bcm2709}/include/mach/platform.h
+ * where they carry the following notice:
+ *
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define MCORE_OFFSET            0x0000   /* Fake frame buffer device
+                                          * (the multicore sync block) */
+#define IC0_OFFSET              0x2000
+#define ST_OFFSET               0x3000   /* System Timer */
+#define MPHI_OFFSET             0x6000   /* Message-based Parallel Host Intf. */
+#define DMA_OFFSET              0x7000   /* DMA controller, channels 0-14 */
+#define ARM_OFFSET              0xB000   /* BCM2708 ARM control block */
+#define ARMCTRL_OFFSET          (ARM_OFFSET + 0x000)
+#define ARMCTRL_IC_OFFSET       (ARM_OFFSET + 0x200) /* Interrupt controller */
+#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 */
+#define ARMCTRL_0_SBM_OFFSET    (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
+                                                      * Doorbells & Mailboxes */
+#define PM_OFFSET               0x100000 /* Power Management, Reset controller
+                                          * and Watchdog registers */
+#define PCM_CLOCK_OFFSET        0x101098
+#define RNG_OFFSET              0x104000
+#define GPIO_OFFSET             0x200000
+#define UART0_OFFSET            0x201000
+#define MMCI0_OFFSET            0x202000
+#define I2S_OFFSET              0x203000
+#define SPI0_OFFSET             0x204000
+#define BSC0_OFFSET             0x205000 /* BSC0 I2C/TWI */
+#define UART1_OFFSET            0x215000
+#define EMMC_OFFSET             0x300000
+#define SMI_OFFSET              0x600000
+#define BSC1_OFFSET             0x804000 /* BSC1 I2C/TWI */
+#define USB_OFFSET              0x980000 /* DTC_OTG USB controller */
+#define DMA15_OFFSET            0xE05000 /* DMA controller, channel 15 */
+
+/* GPU interrupts */
+#define INTERRUPT_TIMER0               0
+#define INTERRUPT_TIMER1               1
+#define INTERRUPT_TIMER2               2
+#define INTERRUPT_TIMER3               3
+#define INTERRUPT_CODEC0               4
+#define INTERRUPT_CODEC1               5
+#define INTERRUPT_CODEC2               6
+#define INTERRUPT_JPEG                 7
+#define INTERRUPT_ISP                  8
+#define INTERRUPT_USB                  9
+#define INTERRUPT_3D                   10
+#define INTERRUPT_TRANSPOSER           11
+#define INTERRUPT_MULTICORESYNC0       12
+#define INTERRUPT_MULTICORESYNC1       13
+#define INTERRUPT_MULTICORESYNC2       14
+#define INTERRUPT_MULTICORESYNC3       15
+#define INTERRUPT_DMA0                 16
+#define INTERRUPT_DMA1                 17
+#define INTERRUPT_DMA2                 18
+#define INTERRUPT_DMA3                 19
+#define INTERRUPT_DMA4                 20
+#define INTERRUPT_DMA5                 21
+#define INTERRUPT_DMA6                 22
+#define INTERRUPT_DMA7                 23
+#define INTERRUPT_DMA8                 24
+#define INTERRUPT_DMA9                 25
+#define INTERRUPT_DMA10                26
+#define INTERRUPT_DMA11                27
+#define INTERRUPT_DMA12                28
+#define INTERRUPT_AUX                  29
+#define INTERRUPT_ARM                  30
+#define INTERRUPT_VPUDMA               31
+#define INTERRUPT_HOSTPORT             32
+#define INTERRUPT_VIDEOSCALER          33
+#define INTERRUPT_CCP2TX               34
+#define INTERRUPT_SDC                  35
+#define INTERRUPT_DSI0                 36
+#define INTERRUPT_AVE                  37
+#define INTERRUPT_CAM0                 38
+#define INTERRUPT_CAM1                 39
+#define INTERRUPT_HDMI0                40
+#define INTERRUPT_HDMI1                41
+#define INTERRUPT_PIXELVALVE1          42
+#define INTERRUPT_I2CSPISLV            43
+#define INTERRUPT_DSI1                 44
+#define INTERRUPT_PWA0                 45
+#define INTERRUPT_PWA1                 46
+#define INTERRUPT_CPR                  47
+#define INTERRUPT_SMI                  48
+#define INTERRUPT_GPIO0                49
+#define INTERRUPT_GPIO1                50
+#define INTERRUPT_GPIO2                51
+#define INTERRUPT_GPIO3                52
+#define INTERRUPT_I2C                  53
+#define INTERRUPT_SPI                  54
+#define INTERRUPT_I2SPCM               55
+#define INTERRUPT_SDIO                 56
+#define INTERRUPT_UART                 57
+#define INTERRUPT_SLIMBUS              58
+#define INTERRUPT_VEC                  59
+#define INTERRUPT_CPG                  60
+#define INTERRUPT_RNG                  61
+#define INTERRUPT_ARASANSDIO           62
+#define INTERRUPT_AVSPMON              63
+
+/* ARM CPU IRQs use a private number space */
+#define INTERRUPT_ARM_TIMER            0
+#define INTERRUPT_ARM_MAILBOX          1
+#define INTERRUPT_ARM_DOORBELL_0       2
+#define INTERRUPT_ARM_DOORBELL_1       3
+#define INTERRUPT_VPU0_HALTED          4
+#define INTERRUPT_VPU1_HALTED          5
+#define INTERRUPT_ILLEGAL_TYPE0        6
+#define INTERRUPT_ILLEGAL_TYPE1        7
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
                   ` (3 preceding siblings ...)
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-12  3:54   ` Peter Crosthwaite
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device Andrew Baumann
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine Andrew Baumann
  6 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This module is specific to the bcm2836 (Pi2). It implements the top
level interrupt controller, and mailboxes used for inter-processor
synchronisation.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---

Notes:
    v3:
     * uint8 localirqs
     * style tweaks
     * add MR access size limits

 hw/intc/Makefile.objs             |   2 +-
 hw/intc/bcm2836_control.c         | 317 ++++++++++++++++++++++++++++++++++++++
 include/hw/intc/bcm2836_control.h |  51 ++++++
 3 files changed, 369 insertions(+), 1 deletion(-)
 create mode 100644 hw/intc/bcm2836_control.c
 create mode 100644 include/hw/intc/bcm2836_control.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 2ad1204..6a13a39 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -24,7 +24,7 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
 obj-$(CONFIG_IOAPIC) += ioapic.o
 obj-$(CONFIG_OMAP) += omap_intc.o
 obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
-obj-$(CONFIG_RASPI) += bcm2835_ic.o
+obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
 obj-$(CONFIG_SH4) += sh_intc.o
 obj-$(CONFIG_XICS) += xics.o
 obj-$(CONFIG_XICS_KVM) += xics_kvm.o
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
new file mode 100644
index 0000000..6c93333
--- /dev/null
+++ b/hw/intc/bcm2836_control.c
@@ -0,0 +1,317 @@
+/*
+ * Rasperry Pi 2 emulation ARM control logic module.
+ * Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * Based on bcm2835_ic.c (Raspberry Pi emulation) (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ *
+ * At present, only implements interrupt routing, and mailboxes (i.e.,
+ * not local timer, PMU interrupt, or AXI counters).
+ *
+ * Ref:
+ * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
+ */
+
+#include "hw/intc/bcm2836_control.h"
+
+#define ROUTE_CORE(x) ((x) & 0x3)
+#define ROUTE_FIQ(x)  (((x) & 0x4) != 0)
+
+#define IRQ_BIT(cntrl, num) (((cntrl) & (1 << (num))) != 0)
+#define FIQ_BIT(cntrl, num) (((cntrl) & (1 << ((num) + 4))) != 0)
+
+#define IRQ_CNTPSIRQ    0
+#define IRQ_CNTPNSIRQ   1
+#define IRQ_CNTHPIRQ    2
+#define IRQ_CNTVIRQ     3
+#define IRQ_MAILBOX0    4
+#define IRQ_MAILBOX1    5
+#define IRQ_MAILBOX2    6
+#define IRQ_MAILBOX3    7
+#define IRQ_GPU         8
+#define IRQ_PMU         9
+#define IRQ_AXI         10
+#define IRQ_TIMER       11
+#define IRQ_MAX         IRQ_TIMER
+
+/* Update interrupts.  */
+static void bcm2836_control_update(BCM2836ControlState *s)
+{
+    int i, j;
+
+    /* reset pending IRQs/FIQs */
+    for (i = 0; i < BCM2836_NCORES; i++) {
+        s->irqsrc[i] = s->fiqsrc[i] = 0;
+    }
+
+    /* apply routing logic, update status regs */
+    if (s->gpu_irq) {
+        assert(s->route_gpu_irq < BCM2836_NCORES);
+        s->irqsrc[s->route_gpu_irq] |= (uint32_t)1 << IRQ_GPU;
+    }
+
+    if (s->gpu_fiq) {
+        assert(s->route_gpu_fiq < BCM2836_NCORES);
+        s->fiqsrc[s->route_gpu_fiq] |= (uint32_t)1 << IRQ_GPU;
+    }
+
+    for (i = 0; i < BCM2836_NCORES; i++) {
+        /* handle local interrupts for this core */
+        if (s->localirqs[i]) {
+            /* sanity check localirqs: mailboxes are handled below */
+            assert(s->localirqs[i] < (1 << IRQ_MAILBOX0));
+            for (j = 0; j < IRQ_MAILBOX0; j++) {
+                if ((s->localirqs[i] & (1 << j)) != 0) {
+                    /* local interrupt j is set */
+                    if (FIQ_BIT(s->timercontrol[i], j)) {
+                        /* deliver a FIQ */
+                        s->fiqsrc[i] |= (uint32_t)1 << j;
+                    } else if (IRQ_BIT(s->timercontrol[i], j)) {
+                        /* deliver an IRQ */
+                        s->irqsrc[i] |= (uint32_t)1 << j;
+                    } else {
+                        /* the interrupt is masked */
+                    }
+                }
+            }
+        }
+
+        /* handle mailboxes for this core */
+        for (j = 0; j < BCM2836_MBPERCORE; j++) {
+            if (s->mailboxes[i * BCM2836_MBPERCORE + j] != 0) {
+                /* mailbox j is set */
+                if (FIQ_BIT(s->mailboxcontrol[i], j)) {
+                    /* deliver a FIQ */
+                    s->fiqsrc[i] |= (uint32_t)1 << (j + IRQ_MAILBOX0);
+                } else if (IRQ_BIT(s->mailboxcontrol[i], j)) {
+                    /* deliver an IRQ */
+                    s->irqsrc[i] |= (uint32_t)1 << (j + IRQ_MAILBOX0);
+                } else {
+                    /* the interrupt is masked */
+                }
+            }
+        }
+    }
+
+    /* call set_irq appropriately for each output */
+    for (i = 0; i < BCM2836_NCORES; i++) {
+        qemu_set_irq(s->irq[i], s->irqsrc[i] != 0);
+        qemu_set_irq(s->fiq[i], s->fiqsrc[i] != 0);
+    }
+}
+
+static void bcm2836_control_set_local_irq(void *opaque, int core, int local_irq,
+                                          int level)
+{
+    BCM2836ControlState *s = opaque;
+
+    assert(core >= 0 && core < BCM2836_NCORES);
+    assert(local_irq >= 0 && local_irq <= IRQ_CNTVIRQ);
+
+    if (level) {
+        s->localirqs[core] |= 1 << local_irq;
+    } else {
+        s->localirqs[core] &= ~((uint32_t)1 << local_irq);
+    }
+
+    bcm2836_control_update(s);
+}
+
+/* XXX: the following wrapper functions are a kludgy workaround,
+ * needed because I can't seem to pass useful information in the "irq"
+ * parameter when using named interrupts. Feel free to clean this up!
+ */
+
+static void bcm2836_control_set_local_irq0(void *opaque, int core, int level)
+{
+    bcm2836_control_set_local_irq(opaque, core, 0, level);
+}
+
+static void bcm2836_control_set_local_irq1(void *opaque, int core, int level)
+{
+    bcm2836_control_set_local_irq(opaque, core, 1, level);
+}
+
+static void bcm2836_control_set_local_irq2(void *opaque, int core, int level)
+{
+    bcm2836_control_set_local_irq(opaque, core, 2, level);
+}
+
+static void bcm2836_control_set_local_irq3(void *opaque, int core, int level)
+{
+    bcm2836_control_set_local_irq(opaque, core, 3, level);
+}
+
+static void bcm2836_control_set_gpu_irq(void *opaque, int irq, int level)
+{
+    BCM2836ControlState *s = opaque;
+
+    s->gpu_irq = level;
+
+    bcm2836_control_update(s);
+}
+
+static void bcm2836_control_set_gpu_fiq(void *opaque, int irq, int level)
+{
+    BCM2836ControlState *s = opaque;
+
+    s->gpu_fiq = level;
+
+    bcm2836_control_update(s);
+}
+
+static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned size)
+{
+    BCM2836ControlState *s = opaque;
+
+    if (offset == 0xc) {
+        /* GPU interrupt routing */
+        assert(s->route_gpu_fiq < BCM2836_NCORES
+               && s->route_gpu_irq < BCM2836_NCORES);
+        return ((uint32_t)s->route_gpu_fiq << 2) | s->route_gpu_irq;
+    } else if (offset >= 0x40 && offset < 0x50) {
+        /* Timer interrupt control registers */
+        return s->timercontrol[(offset - 0x40) >> 2];
+    } else if (offset >= 0x50 && offset < 0x60) {
+        /* Mailbox interrupt control registers */
+        return s->mailboxcontrol[(offset - 0x50) >> 2];
+    } else if (offset >= 0x60 && offset < 0x70) {
+        /* IRQ source registers */
+        return s->irqsrc[(offset - 0x60) >> 2];
+    } else if (offset >= 0x70 && offset < 0x80) {
+        /* FIQ source registers */
+        return s->fiqsrc[(offset - 0x70) >> 2];
+    } else if (offset >= 0xc0 && offset < 0x100) {
+        /* Mailboxes */
+        return s->mailboxes[(offset - 0xc0) >> 2];
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return 0;
+    }
+}
+
+static void bcm2836_control_write(void *opaque, hwaddr offset,
+                                  uint64_t val, unsigned size)
+{
+    BCM2836ControlState *s = opaque;
+
+    if (offset == 0xc) {
+        /* GPU interrupt routing */
+        s->route_gpu_irq = val & 0x3;
+        s->route_gpu_fiq = (val >> 2) & 0x3;
+    } else if (offset >= 0x40 && offset < 0x50) {
+        /* Timer interrupt control registers */
+        s->timercontrol[(offset - 0x40) >> 2] = val & 0xff;
+    } else if (offset >= 0x50 && offset < 0x60) {
+        /* Mailbox interrupt control registers */
+        s->mailboxcontrol[(offset - 0x50) >> 2] = val & 0xff;
+    } else if (offset >= 0x80 && offset < 0xc0) {
+        /* Mailbox set registers */
+        s->mailboxes[(offset - 0x80) >> 2] |= val;
+    } else if (offset >= 0xc0 && offset < 0x100) {
+        /* Mailbox clear registers */
+        s->mailboxes[(offset - 0xc0) >> 2] &= ~val;
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        return;
+    }
+
+    bcm2836_control_update(s);
+}
+
+static const MemoryRegionOps bcm2836_control_ops = {
+    .read = bcm2836_control_read,
+    .write = bcm2836_control_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
+static void bcm2836_control_reset(DeviceState *d)
+{
+    BCM2836ControlState *s = BCM2836_CONTROL(d);
+    int i;
+
+    s->route_gpu_irq = s->route_gpu_fiq = 0;
+
+    for (i = 0; i < BCM2836_NCORES; i++) {
+        s->timercontrol[i] = 0;
+        s->mailboxcontrol[i] = 0;
+    }
+
+    for (i = 0; i < BCM2836_NCORES * BCM2836_MBPERCORE; i++) {
+        s->mailboxes[i] = 0;
+    }
+}
+
+static void bcm2836_control_init(Object *obj)
+{
+    BCM2836ControlState *s = BCM2836_CONTROL(obj);
+    DeviceState *dev = DEVICE(obj);
+
+    memory_region_init_io(&s->iomem, obj, &bcm2836_control_ops, s,
+                          TYPE_BCM2836_CONTROL, 0x100);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+
+    /* inputs from each CPU core */
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq0, "cntpsirq",
+                            BCM2836_NCORES);
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq1, "cntpnsirq",
+                            BCM2836_NCORES);
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq2, "cnthpirq",
+                            BCM2836_NCORES);
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq3, "cntvirq",
+                            BCM2836_NCORES);
+    /* qdev_init_gpio_in_named(dev, bcm2836_control_set_pmu_irq, "pmuirq",
+                            BCM2836_NCORES); */
+
+    /* IRQ and FIQ inputs from upstream bcm2835 controller */
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_irq, "gpu_irq", 1);
+    qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_fiq, "gpu_fiq", 1);
+
+    /* outputs to CPU cores */
+    qdev_init_gpio_out_named(dev, s->irq, "irq", BCM2836_NCORES);
+    qdev_init_gpio_out_named(dev, s->fiq, "fiq", BCM2836_NCORES);
+}
+
+static const VMStateDescription vmstate_bcm2836_control = {
+    .name = TYPE_BCM2836_CONTROL,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(mailboxes, BCM2836ControlState,
+                             BCM2836_NCORES * BCM2836_MBPERCORE),
+        VMSTATE_UINT8(route_gpu_irq, BCM2836ControlState),
+        VMSTATE_UINT8(route_gpu_fiq, BCM2836ControlState),
+        VMSTATE_UINT32_ARRAY(timercontrol, BCM2836ControlState, BCM2836_NCORES),
+        VMSTATE_UINT32_ARRAY(mailboxcontrol, BCM2836ControlState,
+                             BCM2836_NCORES),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2836_control_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = bcm2836_control_reset;
+    dc->vmsd = &vmstate_bcm2836_control;
+}
+
+static TypeInfo bcm2836_control_info = {
+    .name          = TYPE_BCM2836_CONTROL,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2836ControlState),
+    .class_init    = bcm2836_control_class_init,
+    .instance_init = bcm2836_control_init,
+};
+
+static void bcm2836_control_register_types(void)
+{
+    type_register_static(&bcm2836_control_info);
+}
+
+type_init(bcm2836_control_register_types)
diff --git a/include/hw/intc/bcm2836_control.h b/include/hw/intc/bcm2836_control.h
new file mode 100644
index 0000000..9dbfc9f
--- /dev/null
+++ b/include/hw/intc/bcm2836_control.h
@@ -0,0 +1,51 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2836_CONTROL_H
+#define BCM2836_CONTROL_H
+
+#include "hw/sysbus.h"
+
+/* 4 mailboxes per core, for 16 total */
+#define BCM2836_NCORES 4
+#define BCM2836_MBPERCORE 4
+
+#define TYPE_BCM2836_CONTROL "bcm2836-control"
+#define BCM2836_CONTROL(obj) \
+    OBJECT_CHECK(BCM2836ControlState, (obj), TYPE_BCM2836_CONTROL)
+
+typedef struct BCM2836ControlState {
+    /*< private >*/
+    SysBusDevice busdev;
+    /*< public >*/
+    MemoryRegion iomem;
+
+    /* interrupt status registers (not directly visible to user) */
+    bool gpu_irq, gpu_fiq;
+    uint8_t localirqs[BCM2836_NCORES];
+
+    /* mailboxes */
+    uint32_t mailboxes[BCM2836_NCORES * BCM2836_MBPERCORE];
+
+    /* interrupt routing/control registers */
+    uint8_t route_gpu_irq, route_gpu_fiq;
+    uint32_t timercontrol[BCM2836_NCORES];
+    uint32_t mailboxcontrol[BCM2836_NCORES];
+
+    /* interrupt source registers, post-routing (visible) */
+    uint32_t irqsrc[BCM2836_NCORES];
+    uint32_t fiqsrc[BCM2836_NCORES];
+
+    /* outputs to CPU cores */
+    qemu_irq irq[BCM2836_NCORES];
+    qemu_irq fiq[BCM2836_NCORES];
+} BCM2836ControlState;
+
+#endif
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
                   ` (4 preceding siblings ...)
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-12  3:56   ` Peter Crosthwaite
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine Andrew Baumann
  6 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

This is the SoC for Raspberry Pi 2.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
The use of smp_cpus is dubious here. Ideally it should be passed as a
property from the board, but I found that simply initialising (and not
later realizing) an ARM cpu had unintended side-effects. Is it ok to
defer the object_initialize call to the realize method, when we know
how many CPUs are configured?

 hw/arm/Makefile.objs     |   2 +-
 hw/arm/bcm2836.c         | 155 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/bcm2836.h |  33 ++++++++++
 3 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/bcm2836.c
 create mode 100644 include/hw/arm/bcm2836.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 82cc142..f55f8d2 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -11,7 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
-obj-$(CONFIG_RASPI) += bcm2835_peripherals.o
+obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
new file mode 100644
index 0000000..bec7667
--- /dev/null
+++ b/hw/arm/bcm2836.c
@@ -0,0 +1,155 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/arm/bcm2836.h"
+#include "hw/arm/raspi_platform.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h" /* for smp_cpus */
+#include "exec/address-spaces.h"
+
+/* Peripheral base address seen by the CPU */
+#define BCM2836_PERI_BASE       0x3F000000
+
+/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
+#define BCM2836_CONTROL_BASE    0x40000000
+
+static void bcm2836_init(Object *obj)
+{
+    BCM2836State *s = BCM2836(obj);
+    int n;
+
+    /* TODO: probably shouldn't be using smp_cpus here */
+    assert(smp_cpus <= BCM2836_NCPUS);
+    for (n = 0; n < smp_cpus; n++) {
+        object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
+                          "cortex-a15-" TYPE_ARM_CPU);
+        object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
+                                  &error_abort);
+    }
+
+    object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2836_CONTROL);
+    object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);
+    qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
+
+    object_initialize(&s->peripherals, sizeof(s->peripherals),
+                      TYPE_BCM2835_PERIPHERALS);
+    object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals),
+                              &error_abort);
+    qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
+}
+
+static void bcm2836_realize(DeviceState *dev, Error **errp)
+{
+    BCM2836State *s = BCM2836(dev);
+    Object *obj;
+    Error *err = NULL;
+    int n;
+
+    /* common peripherals from bcm2835 */
+    obj = object_property_get_link(OBJECT(dev), "ram", &err);
+    if (obj == NULL) {
+        error_setg(errp, "%s: required ram link not found: %s",
+                   __func__, error_get_pretty(err));
+        return;
+    }
+
+    object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
+                            BCM2836_PERI_BASE, 1);
+
+    /* bcm2836 interrupt controller (and mailboxes, etc.) */
+    object_property_set_bool(OBJECT(&s->ic), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ic), 0, BCM2836_CONTROL_BASE);
+
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
+                       qdev_get_gpio_in_named(DEVICE(&s->ic), "gpu_irq", 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
+                       qdev_get_gpio_in_named(DEVICE(&s->ic), "gpu_fiq", 0));
+
+    /* TODO: probably shouldn't be using smp_cpus here */
+    assert(smp_cpus <= BCM2836_NCPUS);
+    for (n = 0; n < smp_cpus; n++) {
+        /* Mirror bcm2836, which has clusterid set to 0xf */
+        s->cpus[n].mp_affinity = 0xF00 | n;
+
+        /* set periphbase/CBAR value for CPU-local registers */
+        object_property_set_int(OBJECT(&s->cpus[n]),
+                                BCM2836_PERI_BASE + MCORE_OFFSET,
+                                "reset-cbar", &err);
+        if (err) {
+            error_report_err(err);
+            exit(1);
+        }
+
+        object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
+        if (err) {
+            error_report_err(err);
+            exit(1);
+        }
+
+        /* Connect irq/fiq outputs from the interrupt controller. */
+        qdev_connect_gpio_out_named(DEVICE(&s->ic), "irq", n,
+                                    qdev_get_gpio_in(DEVICE(&s->cpus[n]),
+                                                     ARM_CPU_IRQ));
+        qdev_connect_gpio_out_named(DEVICE(&s->ic), "fiq", n,
+                                    qdev_get_gpio_in(DEVICE(&s->cpus[n]),
+                                                     ARM_CPU_FIQ));
+
+        /* Connect timers from the CPU to the interrupt controller */
+        s->cpus[n].gt_timer_outputs[GTIMER_PHYS]
+            = qdev_get_gpio_in_named(DEVICE(&s->ic), "cntpsirq", 0);
+        s->cpus[n].gt_timer_outputs[GTIMER_VIRT]
+            = qdev_get_gpio_in_named(DEVICE(&s->ic), "cntvirq", 0);
+    }
+}
+
+static void bcm2836_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = bcm2836_realize;
+
+    /*
+     * Reason: creates an ARM CPU, thus use after free(), see
+     * arm_cpu_class_init()
+     */
+    dc->cannot_destroy_with_object_finalize_yet = true;
+}
+
+static const TypeInfo bcm2836_type_info = {
+    .name = TYPE_BCM2836,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2836State),
+    .instance_init = bcm2836_init,
+    .class_init = bcm2836_class_init,
+};
+
+static void bcm2836_register_types(void)
+{
+    type_register_static(&bcm2836_type_info);
+}
+
+type_init(bcm2836_register_types)
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
new file mode 100644
index 0000000..a78e919
--- /dev/null
+++ b/include/hw/arm/bcm2836.h
@@ -0,0 +1,33 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2836_H
+#define BCM2836_H
+
+#include "hw/arm/arm.h"
+#include "hw/arm/bcm2835_peripherals.h"
+#include "hw/intc/bcm2836_control.h"
+
+#define TYPE_BCM2836 "bcm2836"
+#define BCM2836(obj) OBJECT_CHECK(BCM2836State, (obj), TYPE_BCM2836)
+
+#define BCM2836_NCPUS 4
+
+typedef struct BCM2836State {
+    /*< private >*/
+    DeviceState parent_obj;
+    /*< public >*/
+
+    ARMCPU cpus[BCM2836_NCPUS];
+    BCM2836ControlState ic;
+    BCM2835PeripheralState peripherals;
+} BCM2836State;
+
+#endif /* BCM2836_H */
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
                   ` (5 preceding siblings ...)
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device Andrew Baumann
@ 2016-01-01  0:31 ` Andrew Baumann
  2016-01-12  3:57   ` Peter Crosthwaite
  6 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-01  0:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini

bcm2835/Pi1 requires more peripherals, and will be added in a later
patch series.

Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---

Notes:
    v3:
     * fix board setup to remain Pi1 compatible
     * pass ram property

 hw/arm/Makefile.objs |   2 +-
 hw/arm/raspi.c       | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 181 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/raspi.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index f55f8d2..a711e4d 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -11,7 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
-obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o
+obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
new file mode 100644
index 0000000..b73f544
--- /dev/null
+++ b/hw/arm/raspi.c
@@ -0,0 +1,180 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Based on versatilepb.c, copyright terms below. */
+
+/*
+ * ARM Versatile Platform/Application Baseboard System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/arm/bcm2836.h"
+#include "qemu/error-report.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/arm/arm.h"
+#include "sysemu/sysemu.h"
+
+#define SMPBOOT_ADDR    0x300 /* this should leave enough space for ATAGS */
+#define MVBAR_ADDR      0x400 /* secure vectors */
+#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
+#define FIRMWARE_ADDR   0x8000 /* Pi loads kernel.img here by default */
+
+/* Table of Linux board IDs for different Pi versions */
+static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43};
+
+typedef struct RaspiMachineState {
+    union {
+        Object obj;
+        BCM2836State pi2;
+    } soc;
+    MemoryRegion ram;
+} RaspiMachineState;
+
+static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    static const uint32_t smpboot[] = {
+        0xE1A0E00F, /*    mov     lr, pc */
+        0xE3A0FE42, /*    mov     pc, #0x420           ;call BOARDSETUP_ADDR */
+        0xEE100FB0, /*    mrc     p15, 0, r0, c0, c0, 5;get core ID */
+        0xE7E10050, /*    ubfx    r0, r0, #0, #2       ;extract LSB */
+        0xE59F5014, /*    ldr     r5, =0x400000CC      ;load mbox base */
+        0xE320F001, /* 1: yield */
+        0xE7953200, /*    ldr     r3, [r5, r0, lsl #4] ;read mbox for our core*/
+        0xE3530000, /*    cmp     r3, #0               ;spin while zero */
+        0x0AFFFFFB, /*    beq     1b */
+        0xE7853200, /*    str     r3, [r5, r0, lsl #4] ;clear mbox */
+        0xE12FFF13, /*    bx      r3                   ;jump to target */
+        0x400000CC, /* (constant: mailbox 3 read/clear base) */
+    };
+
+    assert(SMPBOOT_ADDR + sizeof(smpboot) <= MVBAR_ADDR);
+    rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
+                       info->smp_loader_start);
+}
+
+static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    static const uint32_t board_setup[] = {
+        /* MVBAR_ADDR: secure monitor vectors */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        /* BOARDSETUP_ADDR */
+        0xE3A00B01, /* mov     r0, #0x400             ;MVBAR_ADDR */
+        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
+        0xE3A00031, /* mov     r0, #0x31              ;enable AW, FW, NS */
+        0xEE010F11, /* mcr     p15, 0, r0, c1, c1, 0  ;write SCR */
+        0xE1A0100E, /* mov     r1, lr                 ;save LR across SMC */
+        0xE1600070, /* smc     #0                     ;monitor call */
+        0xE1A0F001, /* mov     pc, r1                 ;return */
+    };
+
+    rom_add_blob_fixed("raspi_boardsetup", board_setup, sizeof(board_setup),
+                       MVBAR_ADDR);
+}
+
+static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    CPUState *cs = CPU(cpu);
+    cpu_set_pc(cs, info->smp_loader_start);
+}
+
+static void setup_boot(MachineState *machine, int version, size_t ram_size)
+{
+    static struct arm_boot_info binfo;
+    int r;
+
+    binfo.board_id = raspi_boardid[version];
+    binfo.ram_size = ram_size;
+    binfo.nb_cpus = smp_cpus;
+    binfo.board_setup_addr = BOARDSETUP_ADDR;
+    binfo.write_board_setup = write_board_setup;
+    binfo.secure_board_setup = true;
+    binfo.secure_boot = true;
+
+    /* Pi2 requires SMP setup */
+    if (version == 2) {
+        binfo.smp_loader_start = SMPBOOT_ADDR;
+        binfo.write_secondary_boot = write_smpboot;
+        binfo.secondary_cpu_reset_hook = reset_secondary;
+    }
+
+    /* If the user specified a "firmware" image (e.g. UEFI), we bypass
+       the normal Linux boot process */
+    if (machine->firmware) {
+        /* load the firmware image (typically kernel.img) */
+        r = load_image_targphys(machine->firmware, FIRMWARE_ADDR,
+                                ram_size - FIRMWARE_ADDR);
+        if (r < 0) {
+            error_report("Failed to load firmware from %s", machine->firmware);
+            exit(1);
+        }
+
+        /* set variables so arm_load_kernel does the right thing */
+        binfo.entry = FIRMWARE_ADDR;
+        binfo.firmware_loaded = true;
+    } else {
+        /* Just let arm_load_kernel do everything for us... */
+        binfo.kernel_filename = machine->kernel_filename;
+        binfo.kernel_cmdline = machine->kernel_cmdline;
+        binfo.initrd_filename = machine->initrd_filename;
+    }
+
+    arm_load_kernel(ARM_CPU(first_cpu), &binfo);
+}
+
+static void raspi2_init(MachineState *machine)
+{
+    RaspiMachineState *s = g_new0(RaspiMachineState, 1);
+
+    /* Initialise the SOC */
+    object_initialize(&s->soc.pi2, sizeof(s->soc.pi2), TYPE_BCM2836);
+    object_property_add_child(OBJECT(machine), "soc", &s->soc.obj,
+                              &error_abort);
+
+    /* Allocate and map RAM */
+    memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram",
+                                         machine->ram_size);
+    memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);
+
+    /* Setup the SOC */
+    object_property_add_const_link(&s->soc.obj, "ram", OBJECT(&s->ram),
+                                   &error_abort);
+    object_property_set_bool(&s->soc.obj, true, "realized", &error_abort);
+
+    /* Boot! */
+    setup_boot(machine, 2, machine->ram_size);
+}
+
+static void raspi2_machine_init(MachineClass *mc)
+{
+    mc->desc = "Raspberry Pi 2";
+    mc->init = raspi2_init;
+    mc->block_default_type = IF_SD;
+    mc->no_parallel = 1;
+    mc->no_floppy = 1;
+    mc->no_cdrom = 1;
+    mc->max_cpus = BCM2836_NCPUS;
+    /* XXX: Temporary restriction in RAM size from the full 1GB. Since
+     * we do not yet support the framebuffer / GPU, we need to limit
+     * RAM usable by the OS to sit below the peripherals. */
+    mc->default_ram_size = 0x3F000000; /* BCM2836_PERI_BASE */
+};
+DEFINE_MACHINE("raspi2", raspi2_machine_init)
-- 
2.5.3

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
@ 2016-01-06  2:13   ` Alistair Francis
  2016-01-06  6:07     ` Andrew Baumann
  0 siblings, 1 reply; 26+ messages in thread
From: Alistair Francis @ 2016-01-06  2:13 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Peter Crosthwaite, Stefan Weil,
	Grégory ESTRADE, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini

On Thu, Dec 31, 2015 at 4:31 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> This device maintains all the non-CPU peripherals on bcm2835 (Pi1)
> which are also present on bcm2836 (Pi2). It also implements the
> private address spaces used for DMA and mailboxes.
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
>
> Notes:
>     v3:
>      * clean up raspi_platform.h
>      * s/_/-/ in type/property/child names
>      * use memory_region_init where appropriate rather than memory_region_init_io
>      * pass ram as link property
>
>     v2 changes:
>      * adapted to use common SDHCI emulation
>
>  hw/arm/Makefile.objs                 |   1 +
>  hw/arm/bcm2835_peripherals.c         | 205 +++++++++++++++++++++++++++++++++++
>  include/hw/arm/bcm2835_peripherals.h |  42 +++++++
>  include/hw/arm/raspi_platform.h      | 128 ++++++++++++++++++++++
>  4 files changed, 376 insertions(+)
>  create mode 100644 hw/arm/bcm2835_peripherals.c
>  create mode 100644 include/hw/arm/bcm2835_peripherals.h
>  create mode 100644 include/hw/arm/raspi_platform.h
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 2195b60..82cc142 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -11,6 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>  obj-$(CONFIG_DIGIC) += digic.o
>  obj-y += omap1.o omap2.o strongarm.o
>  obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
> +obj-$(CONFIG_RASPI) += bcm2835_peripherals.o
>  obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>  obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
>  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
> diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
> new file mode 100644
> index 0000000..879a41d
> --- /dev/null
> +++ b/hw/arm/bcm2835_peripherals.c
> @@ -0,0 +1,205 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
> + *
> + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#include "hw/arm/bcm2835_peripherals.h"
> +#include "hw/misc/bcm2835_mbox_defs.h"
> +#include "hw/arm/raspi_platform.h"
> +
> +/* Peripheral base address on the VC (GPU) system bus */
> +#define BCM2835_VC_PERI_BASE 0x7e000000
> +
> +/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
> +#define BCM2835_SDHC_CAPAREG 0x52034b4
> +
> +static void bcm2835_peripherals_init(Object *obj)
> +{
> +    BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
> +
> +    /* Memory region for peripheral devices, which we export to our parent */
> +    memory_region_init_io(&s->peri_mr, obj, NULL, s, "bcm2835-peripherals",
> +                          0x1000000);
> +    object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
> +
> +    /* Internal memory region for peripheral bus addresses (not exported) */
> +    memory_region_init(&s->gpu_bus_mr, obj, "bcm2835-gpu", (uint64_t)1 << 32);
> +    object_property_add_child(obj, "gpu-bus", OBJECT(&s->gpu_bus_mr), NULL);
> +
> +    /* Internal memory region for request/response communication with
> +     * mailbox-addressable peripherals (not exported)
> +     */
> +    memory_region_init(&s->mbox_mr, obj, "bcm2835-mbox",
> +                       MBOX_CHAN_COUNT << MBOX_AS_CHAN_SHIFT);
> +
> +    /* Interrupt Controller */
> +    object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
> +    object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);
> +    qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
> +
> +    /* UART0 */
> +    s->uart0 = SYS_BUS_DEVICE(object_new("pl011"));
> +    object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
> +    qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
> +
> +    /* Mailboxes */
> +    object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
> +    object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
> +    qdev_set_parent_bus(DEVICE(&s->mboxes), sysbus_get_default());
> +
> +    object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
> +                                   OBJECT(&s->mbox_mr), &error_abort);
> +
> +    /* Property channel */
> +    object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
> +    object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
> +    qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
> +
> +    object_property_add_const_link(OBJECT(&s->property), "dma-mr",
> +                                   OBJECT(&s->gpu_bus_mr), &error_abort);
> +
> +    /* Extended Mass Media Controller */
> +    object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI);
> +    object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL);
> +    qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default());
> +}
> +
> +static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
> +{
> +    BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
> +    Object *obj;
> +    MemoryRegion *ram;
> +    Error *err = NULL;
> +    uint32_t ram_size;
> +    int n;
> +
> +    obj = object_property_get_link(OBJECT(dev), "ram", &err);
> +    if (obj == NULL) {
> +        error_setg(errp, "%s: required ram link not found: %s",
> +                   __func__, error_get_pretty(err));
> +        return;
> +    }

I only had a quick read of this patch, but this RAM linking looks fine
to me. Out of curiosity is there a reason you use
object_property_get_link() instead of object_property_add_link() in
the init?

Thanks,

Alistair

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-06  2:13   ` Alistair Francis
@ 2016-01-06  6:07     ` Andrew Baumann
  2016-01-06 13:32       ` Peter Crosthwaite
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-06  6:07 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, Peter Crosthwaite, Stefan Weil,
	Grégory ESTRADE, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini

> From: Alistair Francis [mailto:alistair23@gmail.com]
> Sent: Tuesday, 5 January 2016 18:14
> On Thu, Dec 31, 2015 at 4:31 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> > This device maintains all the non-CPU peripherals on bcm2835 (Pi1)
> > which are also present on bcm2836 (Pi2). It also implements the
> > private address spaces used for DMA and mailboxes.
[...]
> > +    obj = object_property_get_link(OBJECT(dev), "ram", &err);
> > +    if (obj == NULL) {
> > +        error_setg(errp, "%s: required ram link not found: %s",
> > +                   __func__, error_get_pretty(err));
> > +        return;
> > +    }
> 
> I only had a quick read of this patch, but this RAM linking looks fine
> to me. Out of curiosity is there a reason you use
> object_property_get_link() instead of object_property_add_link() in
> the init?

I'm not sure I understand your question... it wouldn't work the other way. I allocate the ram and add the link using object_property_add_const_link() in hw/arm/raspi.c. This file needs to consume the ram to setup alias mappings, so it is using get_link(). (Note there's also level of indirection; raspi creates bcm2836, which does nothing but get the link set by its parent and add it to its bcm2835_peripherals child.)

I suppose I could do it the other way around (allocate and set link in bcm2835_peripherals, based on a size passed from the board), but it seemed more logical to treat the RAM as created/owned of the board rather than the SoC.

Cheers,
Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-06  6:07     ` Andrew Baumann
@ 2016-01-06 13:32       ` Peter Crosthwaite
  2016-01-06 20:04         ` Alistair Francis
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-06 13:32 UTC (permalink / raw)
  To: Andrew Baumann, Andreas Färber
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Alistair Francis

On Tue, Jan 5, 2016 at 10:07 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Alistair Francis [mailto:alistair23@gmail.com]
>> Sent: Tuesday, 5 January 2016 18:14
>> On Thu, Dec 31, 2015 at 4:31 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> > This device maintains all the non-CPU peripherals on bcm2835 (Pi1)
>> > which are also present on bcm2836 (Pi2). It also implements the
>> > private address spaces used for DMA and mailboxes.
> [...]
>> > +    obj = object_property_get_link(OBJECT(dev), "ram", &err);
>> > +    if (obj == NULL) {
>> > +        error_setg(errp, "%s: required ram link not found: %s",
>> > +                   __func__, error_get_pretty(err));
>> > +        return;
>> > +    }
>>
>> I only had a quick read of this patch, but this RAM linking looks fine
>> to me. Out of curiosity is there a reason you use
>> object_property_get_link() instead of object_property_add_link() in
>> the init?
>

The const link system removes the need for the object to have storage
for the link pointer in state. This means you don't need the state
field or add_link(), but the only way to get the pointer for your own
use is to get_link() on yourself. This is slightly simpler but has the
disadvantage that you cannot unlink and then relink something else (I
think?).

I don't have an opinion over which way is more correct so both are
fine for me but if the QOM people have a preferred style we should
probably make the two patches consistent.

Regards,
Peter

> I'm not sure I understand your question... it wouldn't work the other way. I allocate the ram and add the link using object_property_add_const_link() in hw/arm/raspi.c. This file needs to consume the ram to setup alias mappings, so it is using get_link(). (Note there's also level of indirection; raspi creates bcm2836, which does nothing but get the link set by its parent and add it to its bcm2835_peripherals child.)
>
> I suppose I could do it the other way around (allocate and set link in bcm2835_peripherals, based on a size passed from the board), but it seemed more logical to treat the RAM as created/owned of the board rather than the SoC.
>
> Cheers,
> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-06 13:32       ` Peter Crosthwaite
@ 2016-01-06 20:04         ` Alistair Francis
  0 siblings, 0 replies; 26+ messages in thread
From: Alistair Francis @ 2016-01-06 20:04 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers,
	Andrew Baumann, qemu-arm, Paolo Bonzini, Andreas Färber

On Wed, Jan 6, 2016 at 5:32 AM, Peter Crosthwaite
<crosthwaitepeter@gmail.com> wrote:
> On Tue, Jan 5, 2016 at 10:07 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
>>> From: Alistair Francis [mailto:alistair23@gmail.com]
>>> Sent: Tuesday, 5 January 2016 18:14
>>> On Thu, Dec 31, 2015 at 4:31 PM, Andrew Baumann
>>> <Andrew.Baumann@microsoft.com> wrote:
>>> > This device maintains all the non-CPU peripherals on bcm2835 (Pi1)
>>> > which are also present on bcm2836 (Pi2). It also implements the
>>> > private address spaces used for DMA and mailboxes.
>> [...]
>>> > +    obj = object_property_get_link(OBJECT(dev), "ram", &err);
>>> > +    if (obj == NULL) {
>>> > +        error_setg(errp, "%s: required ram link not found: %s",
>>> > +                   __func__, error_get_pretty(err));
>>> > +        return;
>>> > +    }
>>>
>>> I only had a quick read of this patch, but this RAM linking looks fine
>>> to me. Out of curiosity is there a reason you use
>>> object_property_get_link() instead of object_property_add_link() in
>>> the init?
>>
>
> The const link system removes the need for the object to have storage
> for the link pointer in state. This means you don't need the state
> field or add_link(), but the only way to get the pointer for your own
> use is to get_link() on yourself. This is slightly simpler but has the
> disadvantage that you cannot unlink and then relink something else (I
> think?).

Ok, that makes sense.

Thanks,

Alistair

>
> I don't have an opinion over which way is more correct so both are
> fine for me but if the QOM people have a preferred style we should
> probably make the two patches consistent.
>
> Regards,
> Peter
>
>> I'm not sure I understand your question... it wouldn't work the other way. I allocate the ram and add the link using object_property_add_const_link() in hw/arm/raspi.c. This file needs to consume the ram to setup alias mappings, so it is using get_link(). (Note there's also level of indirection; raspi creates bcm2836, which does nothing but get the link set by its parent and add it to its bcm2835_peripherals child.)
>>
>> I suppose I could do it the other way around (allocate and set link in bcm2835_peripherals, based on a size passed from the board), but it seemed more logical to treat the RAM as created/owned of the board rather than the SoC.
>>
>> Cheers,
>> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel Andrew Baumann
@ 2016-01-12  3:53   ` Peter Crosthwaite
  0 siblings, 0 replies; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-12  3:53 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Thu, Dec 31, 2015 at 04:31:29PM -0800, Andrew Baumann wrote:
> This sits behind the mailbox interface, and implements
> request/response queries for system properties. The
> framebuffer-related properties will be added in a later patch.
> 
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
>  hw/misc/Makefile.objs              |   1 +
>  hw/misc/bcm2835_property.c         | 277 +++++++++++++++++++++++++++++++++++++
>  include/hw/misc/bcm2835_property.h |  29 ++++
>  3 files changed, 307 insertions(+)
>  create mode 100644 hw/misc/bcm2835_property.c
>  create mode 100644 include/hw/misc/bcm2835_property.h
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index d0ea105..ea6cd3c 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -37,6 +37,7 @@ obj-$(CONFIG_OMAP) += omap_l4.o
>  obj-$(CONFIG_OMAP) += omap_sdrc.o
>  obj-$(CONFIG_OMAP) += omap_tap.o
>  obj-$(CONFIG_RASPI) += bcm2835_mbox.o
> +obj-$(CONFIG_RASPI) += bcm2835_property.o
>  obj-$(CONFIG_SLAVIO) += slavio_misc.o
>  obj-$(CONFIG_ZYNQ) += zynq_slcr.o
>  obj-$(CONFIG_ZYNQ) += zynq-xadc.o
> diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
> new file mode 100644
> index 0000000..2385be4
> --- /dev/null
> +++ b/hw/misc/bcm2835_property.c
> @@ -0,0 +1,277 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#include "hw/misc/bcm2835_property.h"
> +#include "hw/misc/bcm2835_mbox_defs.h"
> +
> +/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
> +
> +static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
> +{
> +    uint32_t tag;
> +    uint32_t bufsize;
> +    uint32_t tot_len;
> +    size_t resplen;
> +    uint32_t tmp;
> +
> +    value &= ~0xf;
> +
> +    s->addr = value;
> +
> +    tot_len = ldl_phys(&s->dma_as, value);
> +
> +    /* @(addr + 4) : Buffer response code */
> +    value = s->addr + 8;
> +    while (value + 8 <= s->addr + tot_len) {
> +        tag = ldl_phys(&s->dma_as, value);
> +        bufsize = ldl_phys(&s->dma_as, value + 4);
> +        /* @(value + 8) : Request/response indicator */
> +        resplen = 0;
> +        switch (tag) {
> +        case 0x00000000: /* End tag */
> +            break;
> +        case 0x00000001: /* Get firmware revision */
> +            stl_phys(&s->dma_as, value + 12, 346337);
> +            resplen = 4;
> +            break;
> +
> +        case 0x00010001: /* Get board model */

You are not populating a response here so should this LOG_UNIMP?

> +            resplen = 4;
> +            break;
> +        case 0x00010002: /* Get board revision */
> +            resplen = 4;
> +            break;
> +        case 0x00010003: /* Get board MAC address */

Tricky, as QEMU has support for setting MAC addresses on NICs I
think. Should this LOG_UNIMP for the moment and later when we have
network we revisit? Can still return the dummy value with the unimp.

> +            /* write the first four bytes of the 6-byte MAC */
> +            stl_phys(&s->dma_as, value + 12, 0xB827EBD0);
> +            /* write the last two bytes, avoid any write past the buffer end */
> +            stb_phys(&s->dma_as, value + 16, 0xEE);
> +            stb_phys(&s->dma_as, value + 17, 0xDF);

Can you just use:

dma_memory_write(&s->dma_as, value + 12, mac_addr, 6);

Where mac_addr is uint8_t[6] with the mac address?

> +            resplen = 6;
> +            break;
> +        case 0x00010004: /* Get board serial */
> +            resplen = 8;
> +            break;
> +        case 0x00010005: /* Get ARM memory */
> +            /* base */
> +            stl_phys(&s->dma_as, value + 12, 0);
> +            /* size */
> +            stl_phys(&s->dma_as, value + 16, s->ram_size);
> +            resplen = 8;
> +            break;
> +        case 0x00028001: /* Set power state */
> +            /* Assume that whatever device they asked for exists,
> +             * and we'll just claim we set it to the desired state */
> +            tmp = ldl_phys(&s->dma_as, value + 16);
> +            stl_phys(&s->dma_as, value + 16, (tmp & 1));
> +            resplen = 8;
> +            break;
> +
> +        /* Clocks */
> +
> +        case 0x00030001: /* Get clock state */
> +            stl_phys(&s->dma_as, value + 16, 0x1);
> +            resplen = 8;
> +            break;
> +
> +        case 0x00038001: /* Set clock state */

UNIMP

> +            resplen = 8;
> +            break;
> +
> +        case 0x00030002: /* Get clock rate */
> +        case 0x00030004: /* Get max clock rate */
> +        case 0x00030007: /* Get min clock rate */
> +            switch (ldl_phys(&s->dma_as, value + 12)) {
> +            case 1: /* EMMC */
> +                stl_phys(&s->dma_as, value + 16, 50000000);
> +                break;
> +            case 2: /* UART */
> +                stl_phys(&s->dma_as, value + 16, 3000000);
> +                break;
> +            default:
> +                stl_phys(&s->dma_as, value + 16, 700000000);
> +                break;
> +            }
> +            resplen = 8;
> +            break;
> +
> +        case 0x00038002: /* Set clock rate */
> +        case 0x00038004: /* Set max clock rate */
> +        case 0x00038007: /* Set min clock rate */

UNIMP

> +            resplen = 8;
> +            break;
> +
> +        /* Temperature */
> +
> +        case 0x00030006: /* Get temperature */
> +            stl_phys(&s->dma_as, value + 16, 25000);
> +            resplen = 8;
> +            break;
> +
> +        case 0x0003000A: /* Get max temperature */
> +            stl_phys(&s->dma_as, value + 16, 99000);
> +            resplen = 8;
> +            break;
> +
> +
> +        case 0x00060001: /* Get DMA channels */
> +            /* channels 2-5 */
> +            stl_phys(&s->dma_as, value + 12, 0x003C);
> +            resplen = 4;
> +            break;
> +
> +        case 0x00050001: /* Get command line */
> +            resplen = 0;
> +            break;
> +
> +        default:
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "bcm2835_property: unhandled tag %08x\n", tag);
> +            break;
> +        }
> +
> +        if (tag == 0) {
> +            break;
> +        }
> +
> +        stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
> +        value += bufsize + 12;
> +    }
> +
> +    /* Buffer response code */
> +    stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
> +}
> +
> +static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
> +                                      unsigned size)
> +{
> +    BCM2835PropertyState *s = opaque;
> +    uint32_t res = 0;
> +
> +    switch (offset) {
> +    case MBOX_AS_DATA:
> +        res = MBOX_CHAN_PROPERTY | s->addr;
> +        s->pending = false;
> +        qemu_set_irq(s->mbox_irq, 0);
> +        break;
> +
> +    case MBOX_AS_PENDING:
> +        res = s->pending;
> +        break;
> +
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return 0;
> +    }
> +
> +    return res;
> +}
> +
> +static void bcm2835_property_write(void *opaque, hwaddr offset,
> +                                   uint64_t value, unsigned size)
> +{
> +    BCM2835PropertyState *s = opaque;
> +
> +    switch (offset) {
> +    case MBOX_AS_DATA:
> +        if (!s->pending) {
> +            s->pending = true;
> +            bcm2835_property_mbox_push(s, value);
> +            qemu_set_irq(s->mbox_irq, 1);
> +        }

So if it already is pending, the new data is dropped? Should this be a
GUEST_ERROR?

> +        break;
> +
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return;
> +    }
> +
> +}
> +
> +static const MemoryRegionOps bcm2835_property_ops = {
> +    .read = bcm2835_property_read,
> +    .write = bcm2835_property_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 4,
> +};
> +
> +static const VMStateDescription vmstate_bcm2835_property = {
> +    .name = TYPE_BCM2835_PROPERTY,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields      = (VMStateField[]) {
> +        VMSTATE_UINT32(addr, BCM2835PropertyState),
> +        VMSTATE_BOOL(pending, BCM2835PropertyState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void bcm2835_property_init(Object *obj)
> +{
> +    BCM2835PropertyState *s = BCM2835_PROPERTY(obj);

blank line.

Regards,
Peter

> +    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
> +                          TYPE_BCM2835_PROPERTY, 0x10);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
> +    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
> +}
> +
> +static void bcm2835_property_reset(DeviceState *dev)
> +{
> +    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
> +
> +    s->pending = false;
> +}
> +
> +static void bcm2835_property_realize(DeviceState *dev, Error **errp)
> +{
> +    BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
> +    Object *obj;
> +    Error *err = NULL;
> +
> +    obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
> +    if (obj == NULL) {
> +        error_setg(errp, "%s: required dma-mr link not found: %s",
> +                   __func__, error_get_pretty(err));
> +        return;
> +    }
> +
> +    s->dma_mr = MEMORY_REGION(obj);
> +    address_space_init(&s->dma_as, s->dma_mr, NULL);
> +
> +    bcm2835_property_reset(dev);
> +}
> +
> +static Property bcm2835_property_props[] = {
> +    DEFINE_PROP_UINT32("ram-size", BCM2835PropertyState, ram_size, 0),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void bcm2835_property_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = bcm2835_property_props;
> +    dc->realize = bcm2835_property_realize;
> +    dc->vmsd = &vmstate_bcm2835_property;
> +}
> +
> +static TypeInfo bcm2835_property_info = {
> +    .name          = TYPE_BCM2835_PROPERTY,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(BCM2835PropertyState),
> +    .class_init    = bcm2835_property_class_init,
> +    .instance_init = bcm2835_property_init,
> +};
> +
> +static void bcm2835_property_register_types(void)
> +{
> +    type_register_static(&bcm2835_property_info);
> +}
> +
> +type_init(bcm2835_property_register_types)
> diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h
> new file mode 100644
> index 0000000..d7a9856
> --- /dev/null
> +++ b/include/hw/misc/bcm2835_property.h
> @@ -0,0 +1,29 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#ifndef BCM2835_PROPERTY_H
> +#define BCM2835_PROPERTY_H
> +
> +#include "hw/sysbus.h"
> +#include "exec/address-spaces.h"
> +
> +#define TYPE_BCM2835_PROPERTY "bcm2835-property"
> +#define BCM2835_PROPERTY(obj) \
> +        OBJECT_CHECK(BCM2835PropertyState, (obj), TYPE_BCM2835_PROPERTY)
> +
> +typedef struct {
> +    /*< private >*/
> +    SysBusDevice busdev;
> +    /*< public >*/
> +    MemoryRegion *dma_mr;
> +    AddressSpace dma_as;
> +    MemoryRegion iomem;
> +    qemu_irq mbox_irq;
> +    uint32_t ram_size;
> +    uint32_t addr;
> +    bool pending;
> +} BCM2835PropertyState;
> +
> +#endif
> -- 
> 2.5.3
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
@ 2016-01-12  3:54   ` Peter Crosthwaite
  0 siblings, 0 replies; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-12  3:54 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Thu, Dec 31, 2015 at 04:31:32PM -0800, Andrew Baumann wrote:
> This module is specific to the bcm2836 (Pi2). It implements the top
> level interrupt controller, and mailboxes used for inter-processor
> synchronisation.
> 
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> 
> Notes:
>     v3:
>      * uint8 localirqs
>      * style tweaks
>      * add MR access size limits
> 
>  hw/intc/Makefile.objs             |   2 +-
>  hw/intc/bcm2836_control.c         | 317 ++++++++++++++++++++++++++++++++++++++
>  include/hw/intc/bcm2836_control.h |  51 ++++++
>  3 files changed, 369 insertions(+), 1 deletion(-)
>  create mode 100644 hw/intc/bcm2836_control.c
>  create mode 100644 include/hw/intc/bcm2836_control.h
> 
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 2ad1204..6a13a39 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -24,7 +24,7 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
>  obj-$(CONFIG_IOAPIC) += ioapic.o
>  obj-$(CONFIG_OMAP) += omap_intc.o
>  obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
> -obj-$(CONFIG_RASPI) += bcm2835_ic.o
> +obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
>  obj-$(CONFIG_SH4) += sh_intc.o
>  obj-$(CONFIG_XICS) += xics.o
>  obj-$(CONFIG_XICS_KVM) += xics_kvm.o
> diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
> new file mode 100644
> index 0000000..6c93333
> --- /dev/null
> +++ b/hw/intc/bcm2836_control.c
> @@ -0,0 +1,317 @@
> +/*
> + * Rasperry Pi 2 emulation ARM control logic module.
> + * Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * Based on bcm2835_ic.c (Raspberry Pi emulation) (c) 2012 Gregory Estrade
> + * This code is licensed under the GNU GPLv2 and later.
> + *
> + * At present, only implements interrupt routing, and mailboxes (i.e.,
> + * not local timer, PMU interrupt, or AXI counters).
> + *
> + * Ref:
> + * https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
> + */
> +
> +#include "hw/intc/bcm2836_control.h"
> +
> +#define ROUTE_CORE(x) ((x) & 0x3)
> +#define ROUTE_FIQ(x)  (((x) & 0x4) != 0)
> +

Where are these used?

> +#define IRQ_BIT(cntrl, num) (((cntrl) & (1 << (num))) != 0)
> +#define FIQ_BIT(cntrl, num) (((cntrl) & (1 << ((num) + 4))) != 0)
> +
> +#define IRQ_CNTPSIRQ    0
> +#define IRQ_CNTPNSIRQ   1
> +#define IRQ_CNTHPIRQ    2
> +#define IRQ_CNTVIRQ     3
> +#define IRQ_MAILBOX0    4
> +#define IRQ_MAILBOX1    5
> +#define IRQ_MAILBOX2    6
> +#define IRQ_MAILBOX3    7
> +#define IRQ_GPU         8
> +#define IRQ_PMU         9
> +#define IRQ_AXI         10
> +#define IRQ_TIMER       11
> +#define IRQ_MAX         IRQ_TIMER
> +
> +/* Update interrupts.  */
> +static void bcm2836_control_update(BCM2836ControlState *s)
> +{
> +    int i, j;
> +
> +    /* reset pending IRQs/FIQs */
> +    for (i = 0; i < BCM2836_NCORES; i++) {
> +        s->irqsrc[i] = s->fiqsrc[i] = 0;
> +    }
> +
> +    /* apply routing logic, update status regs */
> +    if (s->gpu_irq) {
> +        assert(s->route_gpu_irq < BCM2836_NCORES);
> +        s->irqsrc[s->route_gpu_irq] |= (uint32_t)1 << IRQ_GPU;
> +    }
> +
> +    if (s->gpu_fiq) {
> +        assert(s->route_gpu_fiq < BCM2836_NCORES);
> +        s->fiqsrc[s->route_gpu_fiq] |= (uint32_t)1 << IRQ_GPU;
> +    }
> +
> +    for (i = 0; i < BCM2836_NCORES; i++) {
> +        /* handle local interrupts for this core */
> +        if (s->localirqs[i]) {
> +            /* sanity check localirqs: mailboxes are handled below */

Remove comment about mailboxes being below (comments about code
that is not in the immediate neighbourhood are hard to maintain).

Is this really generic handling of localirqs or is it timer-specific?

> +            assert(s->localirqs[i] < (1 << IRQ_MAILBOX0));
> +            for (j = 0; j < IRQ_MAILBOX0; j++) {
> +                if ((s->localirqs[i] & (1 << j)) != 0) {
> +                    /* local interrupt j is set */
> +                    if (FIQ_BIT(s->timercontrol[i], j)) {
> +                        /* deliver a FIQ */
> +                        s->fiqsrc[i] |= (uint32_t)1 << j;
> +                    } else if (IRQ_BIT(s->timercontrol[i], j)) {
> +                        /* deliver an IRQ */
> +                        s->irqsrc[i] |= (uint32_t)1 << j;
> +                    } else {
> +                        /* the interrupt is masked */
> +                    }
> +                }
> +            }
> +        }
> +
> +        /* handle mailboxes for this core */
> +        for (j = 0; j < BCM2836_MBPERCORE; j++) {
> +            if (s->mailboxes[i * BCM2836_MBPERCORE + j] != 0) {
> +                /* mailbox j is set */
> +                if (FIQ_BIT(s->mailboxcontrol[i], j)) {
> +                    /* deliver a FIQ */
> +                    s->fiqsrc[i] |= (uint32_t)1 << (j + IRQ_MAILBOX0);
> +                } else if (IRQ_BIT(s->mailboxcontrol[i], j)) {
> +                    /* deliver an IRQ */
> +                    s->irqsrc[i] |= (uint32_t)1 << (j + IRQ_MAILBOX0);
> +                } else {
> +                    /* the interrupt is masked */
> +                }

Can we factor out the repeated if-else for FIQ_BIT and IRQ_BIT?

> +            }
> +        }
> +    }
> +
> +    /* call set_irq appropriately for each output */
> +    for (i = 0; i < BCM2836_NCORES; i++) {
> +        qemu_set_irq(s->irq[i], s->irqsrc[i] != 0);
> +        qemu_set_irq(s->fiq[i], s->fiqsrc[i] != 0);
> +    }
> +}
> +
> +static void bcm2836_control_set_local_irq(void *opaque, int core, int local_irq,
> +                                          int level)
> +{
> +    BCM2836ControlState *s = opaque;
> +
> +    assert(core >= 0 && core < BCM2836_NCORES);
> +    assert(local_irq >= 0 && local_irq <= IRQ_CNTVIRQ);
> +
> +    if (level) {
> +        s->localirqs[core] |= 1 << local_irq;
> +    } else {
> +        s->localirqs[core] &= ~((uint32_t)1 << local_irq);
> +    }

deposit.

> +
> +    bcm2836_control_update(s);
> +}
> +
> +/* XXX: the following wrapper functions are a kludgy workaround,
> + * needed because I can't seem to pass useful information in the "irq"
> + * parameter when using named interrupts. Feel free to clean this up!
> + */
> +
> +static void bcm2836_control_set_local_irq0(void *opaque, int core, int level)
> +{
> +    bcm2836_control_set_local_irq(opaque, core, 0, level);
> +}
> +
> +static void bcm2836_control_set_local_irq1(void *opaque, int core, int level)
> +{
> +    bcm2836_control_set_local_irq(opaque, core, 1, level);
> +}
> +
> +static void bcm2836_control_set_local_irq2(void *opaque, int core, int level)
> +{
> +    bcm2836_control_set_local_irq(opaque, core, 2, level);
> +}
> +
> +static void bcm2836_control_set_local_irq3(void *opaque, int core, int level)
> +{
> +    bcm2836_control_set_local_irq(opaque, core, 3, level);
> +}
> +
> +static void bcm2836_control_set_gpu_irq(void *opaque, int irq, int level)
> +{
> +    BCM2836ControlState *s = opaque;
> +
> +    s->gpu_irq = level;
> +
> +    bcm2836_control_update(s);
> +}
> +
> +static void bcm2836_control_set_gpu_fiq(void *opaque, int irq, int level)
> +{
> +    BCM2836ControlState *s = opaque;
> +
> +    s->gpu_fiq = level;
> +
> +    bcm2836_control_update(s);
> +}
> +
> +static uint64_t bcm2836_control_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    BCM2836ControlState *s = opaque;
> +
> +    if (offset == 0xc) {
> +        /* GPU interrupt routing */
> +        assert(s->route_gpu_fiq < BCM2836_NCORES
> +               && s->route_gpu_irq < BCM2836_NCORES);
> +        return ((uint32_t)s->route_gpu_fiq << 2) | s->route_gpu_irq;
> +    } else if (offset >= 0x40 && offset < 0x50) {
> +        /* Timer interrupt control registers */

Definately think that this and below is overcommented. Can we just
have macro defs for registers instead?

Here and for write.

> +        return s->timercontrol[(offset - 0x40) >> 2];
> +    } else if (offset >= 0x50 && offset < 0x60) {
> +        /* Mailbox interrupt control registers */
> +        return s->mailboxcontrol[(offset - 0x50) >> 2];
> +    } else if (offset >= 0x60 && offset < 0x70) {
> +        /* IRQ source registers */
> +        return s->irqsrc[(offset - 0x60) >> 2];
> +    } else if (offset >= 0x70 && offset < 0x80) {
> +        /* FIQ source registers */
> +        return s->fiqsrc[(offset - 0x70) >> 2];
> +    } else if (offset >= 0xc0 && offset < 0x100) {
> +        /* Mailboxes */
> +        return s->mailboxes[(offset - 0xc0) >> 2];
> +    } else {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return 0;
> +    }
> +}
> +
> +static void bcm2836_control_write(void *opaque, hwaddr offset,
> +                                  uint64_t val, unsigned size)
> +{
> +    BCM2836ControlState *s = opaque;
> +
> +    if (offset == 0xc) {
> +        /* GPU interrupt routing */
> +        s->route_gpu_irq = val & 0x3;
> +        s->route_gpu_fiq = (val >> 2) & 0x3;
> +    } else if (offset >= 0x40 && offset < 0x50) {
> +        /* Timer interrupt control registers */
> +        s->timercontrol[(offset - 0x40) >> 2] = val & 0xff;
> +    } else if (offset >= 0x50 && offset < 0x60) {
> +        /* Mailbox interrupt control registers */
> +        s->mailboxcontrol[(offset - 0x50) >> 2] = val & 0xff;
> +    } else if (offset >= 0x80 && offset < 0xc0) {
> +        /* Mailbox set registers */
> +        s->mailboxes[(offset - 0x80) >> 2] |= val;
> +    } else if (offset >= 0xc0 && offset < 0x100) {
> +        /* Mailbox clear registers */
> +        s->mailboxes[(offset - 0xc0) >> 2] &= ~val;
> +    } else {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return;
> +    }
> +
> +    bcm2836_control_update(s);
> +}
> +
> +static const MemoryRegionOps bcm2836_control_ops = {
> +    .read = bcm2836_control_read,
> +    .write = bcm2836_control_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 4,
> +};
> +
> +static void bcm2836_control_reset(DeviceState *d)
> +{
> +    BCM2836ControlState *s = BCM2836_CONTROL(d);
> +    int i;
> +
> +    s->route_gpu_irq = s->route_gpu_fiq = 0;
> +
> +    for (i = 0; i < BCM2836_NCORES; i++) {
> +        s->timercontrol[i] = 0;
> +        s->mailboxcontrol[i] = 0;
> +    }
> +
> +    for (i = 0; i < BCM2836_NCORES * BCM2836_MBPERCORE; i++) {
> +        s->mailboxes[i] = 0;
> +    }
> +}
> +
> +static void bcm2836_control_init(Object *obj)
> +{
> +    BCM2836ControlState *s = BCM2836_CONTROL(obj);
> +    DeviceState *dev = DEVICE(obj);
> +
> +    memory_region_init_io(&s->iomem, obj, &bcm2836_control_ops, s,
> +                          TYPE_BCM2836_CONTROL, 0x100);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
> +
> +    /* inputs from each CPU core */
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq0, "cntpsirq",
> +                            BCM2836_NCORES);
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq1, "cntpnsirq",
> +                            BCM2836_NCORES);
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq2, "cnthpirq",
> +                            BCM2836_NCORES);
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_local_irq3, "cntvirq",
> +                            BCM2836_NCORES);
> +    /* qdev_init_gpio_in_named(dev, bcm2836_control_set_pmu_irq, "pmuirq",
> +                            BCM2836_NCORES); */

Why the commented code?

> +
> +    /* IRQ and FIQ inputs from upstream bcm2835 controller */
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_irq, "gpu_irq", 1);
> +    qdev_init_gpio_in_named(dev, bcm2836_control_set_gpu_fiq, "gpu_fiq", 1);

s/_/-

GPIO names are QOM names which are in turn user visible.

Regards,
Peter

> +
> +    /* outputs to CPU cores */
> +    qdev_init_gpio_out_named(dev, s->irq, "irq", BCM2836_NCORES);
> +    qdev_init_gpio_out_named(dev, s->fiq, "fiq", BCM2836_NCORES);
> +}
> +
> +static const VMStateDescription vmstate_bcm2836_control = {
> +    .name = TYPE_BCM2836_CONTROL,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(mailboxes, BCM2836ControlState,
> +                             BCM2836_NCORES * BCM2836_MBPERCORE),
> +        VMSTATE_UINT8(route_gpu_irq, BCM2836ControlState),
> +        VMSTATE_UINT8(route_gpu_fiq, BCM2836ControlState),
> +        VMSTATE_UINT32_ARRAY(timercontrol, BCM2836ControlState, BCM2836_NCORES),
> +        VMSTATE_UINT32_ARRAY(mailboxcontrol, BCM2836ControlState,
> +                             BCM2836_NCORES),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void bcm2836_control_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = bcm2836_control_reset;
> +    dc->vmsd = &vmstate_bcm2836_control;
> +}
> +
> +static TypeInfo bcm2836_control_info = {
> +    .name          = TYPE_BCM2836_CONTROL,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(BCM2836ControlState),
> +    .class_init    = bcm2836_control_class_init,
> +    .instance_init = bcm2836_control_init,
> +};
> +
> +static void bcm2836_control_register_types(void)
> +{
> +    type_register_static(&bcm2836_control_info);
> +}
> +
> +type_init(bcm2836_control_register_types)
> diff --git a/include/hw/intc/bcm2836_control.h b/include/hw/intc/bcm2836_control.h
> new file mode 100644
> index 0000000..9dbfc9f
> --- /dev/null
> +++ b/include/hw/intc/bcm2836_control.h
> @@ -0,0 +1,51 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
> + *
> + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#ifndef BCM2836_CONTROL_H
> +#define BCM2836_CONTROL_H
> +
> +#include "hw/sysbus.h"
> +
> +/* 4 mailboxes per core, for 16 total */
> +#define BCM2836_NCORES 4
> +#define BCM2836_MBPERCORE 4
> +
> +#define TYPE_BCM2836_CONTROL "bcm2836-control"
> +#define BCM2836_CONTROL(obj) \
> +    OBJECT_CHECK(BCM2836ControlState, (obj), TYPE_BCM2836_CONTROL)
> +
> +typedef struct BCM2836ControlState {
> +    /*< private >*/
> +    SysBusDevice busdev;
> +    /*< public >*/
> +    MemoryRegion iomem;
> +
> +    /* interrupt status registers (not directly visible to user) */
> +    bool gpu_irq, gpu_fiq;
> +    uint8_t localirqs[BCM2836_NCORES];
> +
> +    /* mailboxes */
> +    uint32_t mailboxes[BCM2836_NCORES * BCM2836_MBPERCORE];
> +
> +    /* interrupt routing/control registers */
> +    uint8_t route_gpu_irq, route_gpu_fiq;
> +    uint32_t timercontrol[BCM2836_NCORES];
> +    uint32_t mailboxcontrol[BCM2836_NCORES];
> +
> +    /* interrupt source registers, post-routing (visible) */
> +    uint32_t irqsrc[BCM2836_NCORES];
> +    uint32_t fiqsrc[BCM2836_NCORES];
> +
> +    /* outputs to CPU cores */
> +    qemu_irq irq[BCM2836_NCORES];
> +    qemu_irq fiq[BCM2836_NCORES];
> +} BCM2836ControlState;
> +
> +#endif
> -- 
> 2.5.3
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device Andrew Baumann
@ 2016-01-12  3:56   ` Peter Crosthwaite
  2016-01-12 22:56     ` Andrew Baumann
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-12  3:56 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Thu, Dec 31, 2015 at 04:31:33PM -0800, Andrew Baumann wrote:
> This is the SoC for Raspberry Pi 2.
> 
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> The use of smp_cpus is dubious here. Ideally it should be passed as a
> property from the board, but I found that simply initialising (and not
> later realizing) an ARM cpu had unintended side-effects. Is it ok to
> defer the object_initialize call to the realize method, when we know
> how many CPUs are configured?
> 
>  hw/arm/Makefile.objs     |   2 +-
>  hw/arm/bcm2836.c         | 155 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/arm/bcm2836.h |  33 ++++++++++
>  3 files changed, 189 insertions(+), 1 deletion(-)
>  create mode 100644 hw/arm/bcm2836.c
>  create mode 100644 include/hw/arm/bcm2836.h
> 
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 82cc142..f55f8d2 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -11,7 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>  obj-$(CONFIG_DIGIC) += digic.o
>  obj-y += omap1.o omap2.o strongarm.o
>  obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
> -obj-$(CONFIG_RASPI) += bcm2835_peripherals.o
> +obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o
>  obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>  obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
>  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
> diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
> new file mode 100644
> index 0000000..bec7667
> --- /dev/null
> +++ b/hw/arm/bcm2836.c
> @@ -0,0 +1,155 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
> + *
> + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#include "hw/arm/bcm2836.h"
> +#include "hw/arm/raspi_platform.h"
> +#include "hw/sysbus.h"
> +#include "sysemu/sysemu.h" /* for smp_cpus */
> +#include "exec/address-spaces.h"
> +
> +/* Peripheral base address seen by the CPU */
> +#define BCM2836_PERI_BASE       0x3F000000
> +
> +/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
> +#define BCM2836_CONTROL_BASE    0x40000000
> +
> +static void bcm2836_init(Object *obj)
> +{
> +    BCM2836State *s = BCM2836(obj);
> +    int n;
> +
> +    /* TODO: probably shouldn't be using smp_cpus here */

I agree. I have started ignoring smp_cpus completely for new ARM SoCs,
as if you change the number of CPUs for a SoC, it is not that SoC
anymore. The virt platform is suitable for CPU scalability, whereas
with ARM SoCs, cpu # variation is invalid.

> +    assert(smp_cpus <= BCM2836_NCPUS);
> +    for (n = 0; n < smp_cpus; n++) {

So can we just use BCM2836_NCPUS here as the loop bound? Any
conditionals out there check the existance of CPUs can be removed or
promoted to assert() as a BCM2836 must always have 4 CPUs.

> +        object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
> +                          "cortex-a15-" TYPE_ARM_CPU);
> +        object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
> +                                  &error_abort);
> +    }
> +
> +    object_initialize(&s->ic, sizeof(s->ic), TYPE_BCM2836_CONTROL);
> +    object_property_add_child(obj, "ic", OBJECT(&s->ic), NULL);

Why "ic"? The TYPE_ and the field name are inconsistent. Is it specifically
and interrupt controller or is it generic controller? (My scan of the doc
made me think its a home-grown mpcore). Maybe the field name and string name
should be "cntl"?

> +    qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default());
> +
> +    object_initialize(&s->peripherals, sizeof(s->peripherals),
> +                      TYPE_BCM2835_PERIPHERALS);
> +    object_property_add_child(obj, "peripherals", OBJECT(&s->peripherals),
> +                              &error_abort);
> +    qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
> +}
> +
> +static void bcm2836_realize(DeviceState *dev, Error **errp)
> +{
> +    BCM2836State *s = BCM2836(dev);
> +    Object *obj;
> +    Error *err = NULL;
> +    int n;
> +
> +    /* common peripherals from bcm2835 */

Blank line here (otherwise the comment looks like it only applies to up to
the next line-break whereas this goes further).

> +    obj = object_property_get_link(OBJECT(dev), "ram", &err);
> +    if (obj == NULL) {
> +        error_setg(errp, "%s: required ram link not found: %s",
> +                   __func__, error_get_pretty(err));
> +        return;
> +    }
> +
> +    object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    object_property_set_bool(OBJECT(&s->peripherals), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
> +                            BCM2836_PERI_BASE, 1);
> +
> +    /* bcm2836 interrupt controller (and mailboxes, etc.) */
> +    object_property_set_bool(OBJECT(&s->ic), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ic), 0, BCM2836_CONTROL_BASE);
> +
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
> +                       qdev_get_gpio_in_named(DEVICE(&s->ic), "gpu_irq", 0));
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
> +                       qdev_get_gpio_in_named(DEVICE(&s->ic), "gpu_fiq", 0));
> +
> +    /* TODO: probably shouldn't be using smp_cpus here */
> +    assert(smp_cpus <= BCM2836_NCPUS);
> +    for (n = 0; n < smp_cpus; n++) {
> +        /* Mirror bcm2836, which has clusterid set to 0xf */
> +        s->cpus[n].mp_affinity = 0xF00 | n;
> +

This is probably ok for the moment, but the correct solution is to propertyify
mp_affinity for ARM CPUs and then set via prop as for the reset-cbar below.

There is some stuff in target-arm that sets the higher order affinities based
on CPU numbers on a fixed wrap-around scheme, but that needs to go away, and
be push up to the virt machine. Then virt uses the same property setter to
implement that wrap-around while SoC can get their affinity right.

The Highbank machine has the same problem, and SMP linux boot is blocked by
the same.

> +        /* set periphbase/CBAR value for CPU-local registers */
> +        object_property_set_int(OBJECT(&s->cpus[n]),
> +                                BCM2836_PERI_BASE + MCORE_OFFSET,
> +                                "reset-cbar", &err);
> +        if (err) {
> +            error_report_err(err);
> +            exit(1);

You should just propagate as-above. Original report-and-exit is probably from
machine-model code where there is no-one to propagate too.

> +        }
> +
> +        object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
> +        if (err) {
> +            error_report_err(err);

propagate.

Regards,
Peter

> +            exit(1);
> +        }
> +
> +        /* Connect irq/fiq outputs from the interrupt controller. */
> +        qdev_connect_gpio_out_named(DEVICE(&s->ic), "irq", n,
> +                                    qdev_get_gpio_in(DEVICE(&s->cpus[n]),
> +                                                     ARM_CPU_IRQ));
> +        qdev_connect_gpio_out_named(DEVICE(&s->ic), "fiq", n,
> +                                    qdev_get_gpio_in(DEVICE(&s->cpus[n]),
> +                                                     ARM_CPU_FIQ));
> +
> +        /* Connect timers from the CPU to the interrupt controller */
> +        s->cpus[n].gt_timer_outputs[GTIMER_PHYS]
> +            = qdev_get_gpio_in_named(DEVICE(&s->ic), "cntpsirq", 0);
> +        s->cpus[n].gt_timer_outputs[GTIMER_VIRT]
> +            = qdev_get_gpio_in_named(DEVICE(&s->ic), "cntvirq", 0);
> +    }
> +}
> +
> +static void bcm2836_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->realize = bcm2836_realize;
> +
> +    /*
> +     * Reason: creates an ARM CPU, thus use after free(), see
> +     * arm_cpu_class_init()
> +     */
> +    dc->cannot_destroy_with_object_finalize_yet = true;
> +}
> +
> +static const TypeInfo bcm2836_type_info = {
> +    .name = TYPE_BCM2836,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(BCM2836State),
> +    .instance_init = bcm2836_init,
> +    .class_init = bcm2836_class_init,
> +};
> +
> +static void bcm2836_register_types(void)
> +{
> +    type_register_static(&bcm2836_type_info);
> +}
> +
> +type_init(bcm2836_register_types)
> diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
> new file mode 100644
> index 0000000..a78e919
> --- /dev/null
> +++ b/include/hw/arm/bcm2836.h
> @@ -0,0 +1,33 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
> + *
> + * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#ifndef BCM2836_H
> +#define BCM2836_H
> +
> +#include "hw/arm/arm.h"
> +#include "hw/arm/bcm2835_peripherals.h"
> +#include "hw/intc/bcm2836_control.h"
> +
> +#define TYPE_BCM2836 "bcm2836"
> +#define BCM2836(obj) OBJECT_CHECK(BCM2836State, (obj), TYPE_BCM2836)
> +
> +#define BCM2836_NCPUS 4
> +
> +typedef struct BCM2836State {
> +    /*< private >*/
> +    DeviceState parent_obj;
> +    /*< public >*/
> +
> +    ARMCPU cpus[BCM2836_NCPUS];
> +    BCM2836ControlState ic;
> +    BCM2835PeripheralState peripherals;
> +} BCM2836State;
> +
> +#endif /* BCM2836_H */
> -- 
> 2.5.3
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine Andrew Baumann
@ 2016-01-12  3:57   ` Peter Crosthwaite
  2016-01-12 23:53     ` Andrew Baumann
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-12  3:57 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Thu, Dec 31, 2015 at 04:31:34PM -0800, Andrew Baumann wrote:
> bcm2835/Pi1 requires more peripherals, and will be added in a later
> patch series.
> 
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> 
> Notes:
>     v3:
>      * fix board setup to remain Pi1 compatible
>      * pass ram property
> 
>  hw/arm/Makefile.objs |   2 +-
>  hw/arm/raspi.c       | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 181 insertions(+), 1 deletion(-)
>  create mode 100644 hw/arm/raspi.c
> 
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index f55f8d2..a711e4d 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -11,7 +11,7 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>  obj-$(CONFIG_DIGIC) += digic.o
>  obj-y += omap1.o omap2.o strongarm.o
>  obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
> -obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o
> +obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
>  obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>  obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
>  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
> diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
> new file mode 100644
> index 0000000..b73f544
> --- /dev/null
> +++ b/hw/arm/raspi.c
> @@ -0,0 +1,180 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
> + *
> + * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + *
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +/* Based on versatilepb.c, copyright terms below. */
> +
> +/*

No need to break and restart comments.

> + * ARM Versatile Platform/Application Baseboard System emulation.
> + *

Looks unrelated, I think this has reached total-rewrite status.

> + * Copyright (c) 2005-2007 CodeSourcery.
> + * Written by Paul Brook
> + *
> + * This code is licensed under the GPL.
> + */
> +
> +#include "hw/arm/bcm2836.h"
> +#include "qemu/error-report.h"
> +#include "hw/boards.h"
> +#include "hw/loader.h"
> +#include "hw/arm/arm.h"
> +#include "sysemu/sysemu.h"
> +
> +#define SMPBOOT_ADDR    0x300 /* this should leave enough space for ATAGS */
> +#define MVBAR_ADDR      0x400 /* secure vectors */
> +#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
> +#define FIRMWARE_ADDR   0x8000 /* Pi loads kernel.img here by default */
> +
> +/* Table of Linux board IDs for different Pi versions */
> +static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43};
> +
> +typedef struct RaspiMachineState {
> +    union {
> +        Object obj;
> +        BCM2836State pi2;
> +    } soc;
> +    MemoryRegion ram;
> +} RaspiMachineState;
> +
> +static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
> +{
> +    static const uint32_t smpboot[] = {
> +        0xE1A0E00F, /*    mov     lr, pc */
> +        0xE3A0FE42, /*    mov     pc, #0x420           ;call BOARDSETUP_ADDR */

Check highbank blobs to see how machine code addresses can be done as
relocatable. We should try and make these blobs relocatable from the top
level address definitions where possible.

> +        0xEE100FB0, /*    mrc     p15, 0, r0, c0, c0, 5;get core ID */
> +        0xE7E10050, /*    ubfx    r0, r0, #0, #2       ;extract LSB */
> +        0xE59F5014, /*    ldr     r5, =0x400000CC      ;load mbox base */
> +        0xE320F001, /* 1: yield */
> +        0xE7953200, /*    ldr     r3, [r5, r0, lsl #4] ;read mbox for our core*/
> +        0xE3530000, /*    cmp     r3, #0               ;spin while zero */
> +        0x0AFFFFFB, /*    beq     1b */
> +        0xE7853200, /*    str     r3, [r5, r0, lsl #4] ;clear mbox */
> +        0xE12FFF13, /*    bx      r3                   ;jump to target */
> +        0x400000CC, /* (constant: mailbox 3 read/clear base) */
> +    };
> +
> +    assert(SMPBOOT_ADDR + sizeof(smpboot) <= MVBAR_ADDR);
> +    rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
> +                       info->smp_loader_start);
> +}
> +
> +static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)

This is almost identical to Highbank, I'm guessing you are stubbing monitor
firmware where you get away with nopping all the SMCs? Maybe we should split
Highbanks version off to common code, and parameterise the few differences.

write_board_setup_dummy_monitior(ARMCPU *cpu ..., uint32_t scr_flags);

or something like it. Makes sense to be in arm/boot.c .

> +{
> +    static const uint32_t board_setup[] = {
> +        /* MVBAR_ADDR: secure monitor vectors */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        /* BOARDSETUP_ADDR */
> +        0xE3A00B01, /* mov     r0, #0x400             ;MVBAR_ADDR */
> +        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
> +        0xE3A00031, /* mov     r0, #0x31              ;enable AW, FW, NS */
> +        0xEE010F11, /* mcr     p15, 0, r0, c1, c1, 0  ;write SCR */

If combining with HB, could you do this as read-modify-write?

> +        0xE1A0100E, /* mov     r1, lr                 ;save LR across SMC */
> +        0xE1600070, /* smc     #0                     ;monitor call */
> +        0xE1A0F001, /* mov     pc, r1                 ;return */

I'm looking at the Highbank version which doesn't save lr across the SMC and
wondering why it doesn't. Is this banked by CPU mode and do you get from
already-in-monitor-mode? Or simply, that Highbank code may have a bug?

> +    };
> +
> +    rom_add_blob_fixed("raspi_boardsetup", board_setup, sizeof(board_setup),
> +                       MVBAR_ADDR);
> +}
> +
> +static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
> +{
> +    CPUState *cs = CPU(cpu);
> +    cpu_set_pc(cs, info->smp_loader_start);
> +}
> +
> +static void setup_boot(MachineState *machine, int version, size_t ram_size)
> +{
> +    static struct arm_boot_info binfo;
> +    int r;
> +
> +    binfo.board_id = raspi_boardid[version];
> +    binfo.ram_size = ram_size;
> +    binfo.nb_cpus = smp_cpus;
> +    binfo.board_setup_addr = BOARDSETUP_ADDR;
> +    binfo.write_board_setup = write_board_setup;
> +    binfo.secure_board_setup = true;
> +    binfo.secure_boot = true;
> +
> +    /* Pi2 requires SMP setup */
> +    if (version == 2) {
> +        binfo.smp_loader_start = SMPBOOT_ADDR;
> +        binfo.write_secondary_boot = write_smpboot;
> +        binfo.secondary_cpu_reset_hook = reset_secondary;
> +    }
> +
> +    /* If the user specified a "firmware" image (e.g. UEFI), we bypass
> +       the normal Linux boot process */

Multi-line comment style should be

/* text
 * text
 */

> +    if (machine->firmware) {
> +        /* load the firmware image (typically kernel.img) */
> +        r = load_image_targphys(machine->firmware, FIRMWARE_ADDR,
> +                                ram_size - FIRMWARE_ADDR);
> +        if (r < 0) {
> +            error_report("Failed to load firmware from %s", machine->firmware);
> +            exit(1);
> +        }
> +
> +        /* set variables so arm_load_kernel does the right thing */
> +        binfo.entry = FIRMWARE_ADDR;
> +        binfo.firmware_loaded = true;
> +    } else {
> +        /* Just let arm_load_kernel do everything for us... */
> +        binfo.kernel_filename = machine->kernel_filename;
> +        binfo.kernel_cmdline = machine->kernel_cmdline;
> +        binfo.initrd_filename = machine->initrd_filename;
> +    }
> +
> +    arm_load_kernel(ARM_CPU(first_cpu), &binfo);
> +}
> +
> +static void raspi2_init(MachineState *machine)
> +{
> +    RaspiMachineState *s = g_new0(RaspiMachineState, 1);

Use of the MachineState name-stem suggest that you are QOM inheriting from
MachineState but you are not. So the struct just needs a rename to something
without "MachineState"

> +
> +    /* Initialise the SOC */
> +    object_initialize(&s->soc.pi2, sizeof(s->soc.pi2), TYPE_BCM2836);
> +    object_property_add_child(OBJECT(machine), "soc", &s->soc.obj,
> +                              &error_abort);
> +
> +    /* Allocate and map RAM */
> +    memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram",
> +                                         machine->ram_size);
> +    memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);

I thought the SoC handled this now? Why do you need to add to system_memory?

> +
> +    /* Setup the SOC */
> +    object_property_add_const_link(&s->soc.obj, "ram", OBJECT(&s->ram),
> +                                   &error_abort);

Just cast using OBJECT() rather than having the union.

> +    object_property_set_bool(&s->soc.obj, true, "realized", &error_abort);
> +
> +    /* Boot! */

Not really. You just setup the boot for core code to do it later.

> +    setup_boot(machine, 2, machine->ram_size);
> +}
> +
> +static void raspi2_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Raspberry Pi 2";
> +    mc->init = raspi2_init;
> +    mc->block_default_type = IF_SD;

> +    mc->no_parallel = 1;
> +    mc->no_floppy = 1;
> +    mc->no_cdrom = 1;

Curious, what do these do from a user-visible point of view? Maybe we should
add them to more ARM boards as they certainly make sense.

Regards,
Peter

> +    mc->max_cpus = BCM2836_NCPUS;
> +    /* XXX: Temporary restriction in RAM size from the full 1GB. Since
> +     * we do not yet support the framebuffer / GPU, we need to limit
> +     * RAM usable by the OS to sit below the peripherals. */
> +    mc->default_ram_size = 0x3F000000; /* BCM2836_PERI_BASE */
> +};
> +DEFINE_MACHINE("raspi2", raspi2_machine_init)
> -- 
> 2.5.3
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device
  2016-01-12  3:56   ` Peter Crosthwaite
@ 2016-01-12 22:56     ` Andrew Baumann
  2016-01-12 23:14       ` Peter Crosthwaite
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-12 22:56 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

Hi Peter,

Thanks again for the reviews.

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Monday, 11 January 2016 19:57
> On Thu, Dec 31, 2015 at 04:31:33PM -0800, Andrew Baumann wrote:
> > +    /* TODO: probably shouldn't be using smp_cpus here */
> 
> I agree. I have started ignoring smp_cpus completely for new ARM SoCs,
> as if you change the number of CPUs for a SoC, it is not that SoC
> anymore. The virt platform is suitable for CPU scalability, whereas
> with ARM SoCs, cpu # variation is invalid.
> 
> > +    assert(smp_cpus <= BCM2836_NCPUS);
> > +    for (n = 0; n < smp_cpus; n++) {
> 
> So can we just use BCM2836_NCPUS here as the loop bound? Any
> conditionals out there check the existance of CPUs can be removed or
> promoted to assert() as a BCM2836 must always have 4 CPUs.

I'd love to do that, but there's at least one good reason to respect the -smp parameter and not start all the CPUs: with full-system emulation, qemu is noticeably faster emulating a single-core target than multi-core. E.g., Linux boots fine with -smp 1 (it fails to start the other CPUs but proceeds with just one), and many users will be better off running it this way, so I definitely don't want to break that.

I tried always initing all 4 CPUs in bcm2836_init, and only starting a configurable number (based on a property) in realize. However, arm cpu_exec_init already adds the cpu to the global list of all CPUs, and if you try to start the system in this state it quickly segfaults on uninitialized state in the CPU, so it seems we shouldn't even init CPUs that won't later be started. However, I can't refer to properties in the _init method, which is why I'm stuck using the smp_cpus global.

If you have a better suggestion, I'm all ears :) Would it make sense to defer calling init() until the realize method, when we can access a property?

Cheers,
Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device
  2016-01-12 22:56     ` Andrew Baumann
@ 2016-01-12 23:14       ` Peter Crosthwaite
  2016-01-13  0:09         ` Andrew Baumann
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-12 23:14 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Tue, Jan 12, 2016 at 2:56 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> Hi Peter,
>
> Thanks again for the reviews.
>
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Monday, 11 January 2016 19:57
>> On Thu, Dec 31, 2015 at 04:31:33PM -0800, Andrew Baumann wrote:
>> > +    /* TODO: probably shouldn't be using smp_cpus here */
>>
>> I agree. I have started ignoring smp_cpus completely for new ARM SoCs,
>> as if you change the number of CPUs for a SoC, it is not that SoC
>> anymore. The virt platform is suitable for CPU scalability, whereas
>> with ARM SoCs, cpu # variation is invalid.
>>
>> > +    assert(smp_cpus <= BCM2836_NCPUS);
>> > +    for (n = 0; n < smp_cpus; n++) {
>>
>> So can we just use BCM2836_NCPUS here as the loop bound? Any
>> conditionals out there check the existance of CPUs can be removed or
>> promoted to assert() as a BCM2836 must always have 4 CPUs.
>
> I'd love to do that, but there's at least one good reason to respect the -smp parameter and not start all the CPUs: with full-system emulation, qemu is noticeably faster emulating a single-core target than multi-core. E.g., Linux boots fine with -smp 1 (it fails to start the other CPUs but proceeds with just one), and many users will be better off running it this way, so I definitely don't want to break that.
>

What are the secondary CPUs doing in this case? In most systems they
end up penning on a WFI/WFE. Is Linux actually trying to do the SMP
bringup - are you are getting a secondary entry point?

If not and it is just a busy wait killing perf, start-powered-off
property might help. Is the firmware responsible for secondary-penning
an actual busy-wait or does it involve power-control periphs etc?

Regards,
Peter

> I tried always initing all 4 CPUs in bcm2836_init, and only starting a configurable number (based on a property) in realize. However, arm cpu_exec_init already adds the cpu to the global list of all CPUs, and if you try to start the system in this state it quickly segfaults on uninitialized state in the CPU, so it seems we shouldn't even init CPUs that won't later be started. However, I can't refer to properties in the _init method, which is why I'm stuck using the smp_cpus global.
>
> If you have a better suggestion, I'm all ears :) Would it make sense to defer calling init() until the realize method, when we can access a property?
>
> Cheers,
> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-12  3:57   ` Peter Crosthwaite
@ 2016-01-12 23:53     ` Andrew Baumann
  2016-01-13  0:43       ` Peter Crosthwaite
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-12 23:53 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Monday, 11 January 2016 19:58
[...]
> > +static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info
> *info)
> 
> This is almost identical to Highbank, I'm guessing you are stubbing monitor
> firmware where you get away with nopping all the SMCs? Maybe we should
> split
> Highbanks version off to common code, and parameterise the few
> differences.
> 
> write_board_setup_dummy_monitior(ARMCPU *cpu ..., uint32_t scr_flags);
> 
> or something like it. Makes sense to be in arm/boot.c .

Actually, I added this only to make Linux happy (and yes, it was derived from highbank). Without it, I was seeing complaints about:
Ignoring attempt to switch CPSR_A flag from non-secure world with SCR.AW bit clear
Ignoring attempt to switch CPSR_F flag from non-secure world with SCR.FW bit clear

I don't believe anything actually uses the SMC handler after boot. I think it's just an architectural requirement to flush the change to non-secure mode.

I would prefer not to touch highbank, because I don't know how to test it. Is it better to submit this patch without the board setup?

> 
> > +{
> > +    static const uint32_t board_setup[] = {
> > +        /* MVBAR_ADDR: secure monitor vectors */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xEAFFFFFE, /* (spin) */
> > +        0xEAFFFFFE, /* (spin) */
> > +        /* BOARDSETUP_ADDR */
> > +        0xE3A00B01, /* mov     r0, #0x400             ;MVBAR_ADDR */
> > +        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
> > +        0xE3A00031, /* mov     r0, #0x31              ;enable AW, FW, NS */
> > +        0xEE010F11, /* mcr     p15, 0, r0, c1, c1, 0  ;write SCR */
> 
> If combining with HB, could you do this as read-modify-write?
> 
> > +        0xE1A0100E, /* mov     r1, lr                 ;save LR across SMC */
> > +        0xE1600070, /* smc     #0                     ;monitor call */
> > +        0xE1A0F001, /* mov     pc, r1                 ;return */
> 
> I'm looking at the Highbank version which doesn't save lr across the SMC and
> wondering why it doesn't. Is this banked by CPU mode and do you get from
> already-in-monitor-mode? Or simply, that Highbank code may have a bug?

I think it's needed because I call the board setup blob on each core (from the smpboot blob), but highbank doesn't. I found that I needed to do this to avoid the above warnings on an SMP boot; I don't know why highbank doesn't.

[...]
> > +    /* Allocate and map RAM */
> > +    memory_region_allocate_system_memory(&s->ram,
> OBJECT(machine), "ram",
> > +                                         machine->ram_size);
> > +    memory_region_add_subregion_overlap(get_system_memory(), 0,
> &s->ram, 0);
> 
> I thought the SoC handled this now? Why do you need to add to
> system_memory?

If I don't map it here, how do RAM accesses from the CPUs work?

Or are you saying that I should still do this, but do it in the SoC not the board level?

[...]
> > +static void raspi2_machine_init(MachineClass *mc)
> > +{
> > +    mc->desc = "Raspberry Pi 2";
> > +    mc->init = raspi2_init;
> > +    mc->block_default_type = IF_SD;
> 
> > +    mc->no_parallel = 1;
> > +    mc->no_floppy = 1;
> > +    mc->no_cdrom = 1;
> 
> Curious, what do these do from a user-visible point of view? Maybe we
> should
> add them to more ARM boards as they certainly make sense.

I think they turn off some redundant stuff in the UI (e.g., there's no View->Parallel menu option). I'm guessing they also disable the -cdrom and  -fd* options, but didn't test that.

Cheers,
Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device
  2016-01-12 23:14       ` Peter Crosthwaite
@ 2016-01-13  0:09         ` Andrew Baumann
  0 siblings, 0 replies; 26+ messages in thread
From: Andrew Baumann @ 2016-01-13  0:09 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Tuesday, 12 January 2016 15:15
> On Tue, Jan 12, 2016 at 2:56 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Monday, 11 January 2016 19:57
> >> On Thu, Dec 31, 2015 at 04:31:33PM -0800, Andrew Baumann wrote:
> >> > +    /* TODO: probably shouldn't be using smp_cpus here */
> >>
> >> I agree. I have started ignoring smp_cpus completely for new ARM SoCs,
> >> as if you change the number of CPUs for a SoC, it is not that SoC
> >> anymore. The virt platform is suitable for CPU scalability, whereas
> >> with ARM SoCs, cpu # variation is invalid.
> >>
> >> > +    assert(smp_cpus <= BCM2836_NCPUS);
> >> > +    for (n = 0; n < smp_cpus; n++) {
> >>
> >> So can we just use BCM2836_NCPUS here as the loop bound? Any
> >> conditionals out there check the existance of CPUs can be removed or
> >> promoted to assert() as a BCM2836 must always have 4 CPUs.
> >
> > I'd love to do that, but there's at least one good reason to respect the -smp
> parameter and not start all the CPUs: with full-system emulation, qemu is
> noticeably faster emulating a single-core target than multi-core. E.g., Linux
> boots fine with -smp 1 (it fails to start the other CPUs but proceeds with just
> one), and many users will be better off running it this way, so I definitely
> don't want to break that.
> >
> 
> What are the secondary CPUs doing in this case? In most systems they
> end up penning on a WFI/WFE. Is Linux actually trying to do the SMP
> bringup - are you are getting a secondary entry point?
> 
> If not and it is just a busy wait killing perf, start-powered-off
> property might help. Is the firmware responsible for secondary-penning
> an actual busy-wait or does it involve power-control periphs etc?

Yes, it is a busy-wait in my smpboot blob. (I suppose I could figure out how to replace it with an interrupt-driven version, but it seemed like a lot of pointless work compared to not starting the CPU.) On a first quick test, that property seems to do the trick, thanks.

Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-12 23:53     ` Andrew Baumann
@ 2016-01-13  0:43       ` Peter Crosthwaite
  2016-01-14 23:04         ` Andrew Baumann
  2016-01-16  0:04         ` Andrew Baumann
  0 siblings, 2 replies; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-13  0:43 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Monday, 11 January 2016 19:58
> [...]
>> > +static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info
>> *info)
>>
>> This is almost identical to Highbank, I'm guessing you are stubbing monitor
>> firmware where you get away with nopping all the SMCs? Maybe we should
>> split
>> Highbanks version off to common code, and parameterise the few
>> differences.
>>
>> write_board_setup_dummy_monitior(ARMCPU *cpu ..., uint32_t scr_flags);
>>
>> or something like it. Makes sense to be in arm/boot.c .
>
> Actually, I added this only to make Linux happy (and yes, it was derived from highbank). Without it, I was seeing complaints about:
> Ignoring attempt to switch CPSR_A flag from non-secure world with SCR.AW bit clear
> Ignoring attempt to switch CPSR_F flag from non-secure world with SCR.FW bit clear
>
> I don't believe anything actually uses the SMC handler after boot. I think it's just an architectural requirement to flush the change to non-secure mode.
>
> I would prefer not to touch highbank, because I don't know how to test it. Is it better to submit this patch without the board setup?
>

I can test Highbank for you, or you can use this project:

https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg00755.html

The build takes a while and costs about 50GB of disk space, but the
amount of setup needed should be pretty low.

FWIW, that was the test system that found the need for this FW in HB.

>>
>> > +{
>> > +    static const uint32_t board_setup[] = {
>> > +        /* MVBAR_ADDR: secure monitor vectors */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        0xEAFFFFFE, /* (spin) */
>> > +        /* BOARDSETUP_ADDR */
>> > +        0xE3A00B01, /* mov     r0, #0x400             ;MVBAR_ADDR */
>> > +        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
>> > +        0xE3A00031, /* mov     r0, #0x31              ;enable AW, FW, NS */
>> > +        0xEE010F11, /* mcr     p15, 0, r0, c1, c1, 0  ;write SCR */
>>
>> If combining with HB, could you do this as read-modify-write?
>>
>> > +        0xE1A0100E, /* mov     r1, lr                 ;save LR across SMC */
>> > +        0xE1600070, /* smc     #0                     ;monitor call */
>> > +        0xE1A0F001, /* mov     pc, r1                 ;return */
>>
>> I'm looking at the Highbank version which doesn't save lr across the SMC and
>> wondering why it doesn't. Is this banked by CPU mode and do you get from
>> already-in-monitor-mode? Or simply, that Highbank code may have a bug?
>
> I think it's needed because I call the board setup blob on each core (from the smpboot blob), but highbank doesn't. I found that I needed to do this to avoid the above warnings on an SMP boot; I don't know why highbank doesn't.
>
> [...]
>> > +    /* Allocate and map RAM */
>> > +    memory_region_allocate_system_memory(&s->ram,
>> OBJECT(machine), "ram",
>> > +                                         machine->ram_size);
>> > +    memory_region_add_subregion_overlap(get_system_memory(), 0,
>> &s->ram, 0);
>>
>> I thought the SoC handled this now? Why do you need to add to
>> system_memory?
>
> If I don't map it here, how do RAM accesses from the CPUs work?
>

Do the CPUs not have their AS'es connected to your custom ASes by the SoC layer?

> Or are you saying that I should still do this, but do it in the SoC not the board level?
>

I was hoping we could get away with 0 use of system_memory.

Regards,
Peter

> [...]
>> > +static void raspi2_machine_init(MachineClass *mc)
>> > +{
>> > +    mc->desc = "Raspberry Pi 2";
>> > +    mc->init = raspi2_init;
>> > +    mc->block_default_type = IF_SD;
>>
>> > +    mc->no_parallel = 1;
>> > +    mc->no_floppy = 1;
>> > +    mc->no_cdrom = 1;
>>
>> Curious, what do these do from a user-visible point of view? Maybe we
>> should
>> add them to more ARM boards as they certainly make sense.
>
> I think they turn off some redundant stuff in the UI (e.g., there's no View->Parallel menu option). I'm guessing they also disable the -cdrom and  -fd* options, but didn't test that.
>
> Cheers,
> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-13  0:43       ` Peter Crosthwaite
@ 2016-01-14 23:04         ` Andrew Baumann
  2016-01-14 23:34           ` Peter Crosthwaite
  2016-01-16  0:04         ` Andrew Baumann
  1 sibling, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-14 23:04 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

Hi Peter,

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Tuesday, 12 January 2016 16:44
> On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Monday, 11 January 2016 19:58
> >> > +    /* Allocate and map RAM */
> >> > +    memory_region_allocate_system_memory(&s->ram,
> >> OBJECT(machine), "ram",
> >> > +                                         machine->ram_size);
> >> > +    memory_region_add_subregion_overlap(get_system_memory(), 0,
> >> &s->ram, 0);
> >>
> >> I thought the SoC handled this now? Why do you need to add to
> >> system_memory?
> >
> > If I don't map it here, how do RAM accesses from the CPUs work?
> >
> 
> Do the CPUs not have their AS'es connected to your custom ASes by the SoC
> layer?
> 
> > Or are you saying that I should still do this, but do it in the SoC not the
> board level?
> >
> 
> I was hoping we could get away with 0 use of system_memory.

On further investigation, I don't think it's possible to wire up CPU ASes explicitly. There's no obvious property to set. Each cpu->as is initialised to point to address_space_memory at the top of cpu_exec_init(), and there is no way I could see to override that.

I think what I have now is pretty clean, but if you'd prefer to do the mapping at into the global AS at SoC level that's fine with me too.

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-14 23:04         ` Andrew Baumann
@ 2016-01-14 23:34           ` Peter Crosthwaite
  2016-01-15  0:43             ` Andrew Baumann
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-14 23:34 UTC (permalink / raw)
  To: Andrew Baumann, Peter Maydell
  Cc: Stefan Weil, qemu-arm, qemu-devel, Paolo Bonzini, Grégory ESTRADE

On Thu, Jan 14, 2016 at 3:04 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> Hi Peter,
>
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Tuesday, 12 January 2016 16:44
>> On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> >> Sent: Monday, 11 January 2016 19:58
>> >> > +    /* Allocate and map RAM */
>> >> > +    memory_region_allocate_system_memory(&s->ram,
>> >> OBJECT(machine), "ram",
>> >> > +                                         machine->ram_size);
>> >> > +    memory_region_add_subregion_overlap(get_system_memory(), 0,
>> >> &s->ram, 0);
>> >>
>> >> I thought the SoC handled this now? Why do you need to add to
>> >> system_memory?
>> >
>> > If I don't map it here, how do RAM accesses from the CPUs work?
>> >
>>
>> Do the CPUs not have their AS'es connected to your custom ASes by the SoC
>> layer?
>>
>> > Or are you saying that I should still do this, but do it in the SoC not the
>> board level?
>> >
>>
>> I was hoping we could get away with 0 use of system_memory.
>
> On further investigation, I don't think it's possible to wire up CPU ASes explicitly. There's no obvious property to set. Each cpu->as is initialised to point to address_space_memory at the top of cpu_exec_init(), and there is no way I could see to override that.
>
> I think what I have now is pretty clean, but if you'd prefer to do the mapping at into the global AS at SoC level that's fine with me too.
>

If it cant be done yet, what is here is a preferable approach. PMM has
some work on list for CPU ASes that may be realted, moreso for the
secure attributes though I think.

Regards,
Peter

> Thanks,
> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-14 23:34           ` Peter Crosthwaite
@ 2016-01-15  0:43             ` Andrew Baumann
  2016-01-15  1:09               ` Peter Crosthwaite
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Baumann @ 2016-01-15  0:43 UTC (permalink / raw)
  To: Peter Crosthwaite, Peter Maydell
  Cc: Stefan Weil, qemu-arm, qemu-devel, Paolo Bonzini, Grégory ESTRADE

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Thursday, 14 January 2016 15:35
> 
> On Thu, Jan 14, 2016 at 3:04 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> > Hi Peter,
> >
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Tuesday, 12 January 2016 16:44
> >> On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
> >> <Andrew.Baumann@microsoft.com> wrote:
> >> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> >> Sent: Monday, 11 January 2016 19:58
> >> >> > +    /* Allocate and map RAM */
> >> >> > +    memory_region_allocate_system_memory(&s->ram,
> >> >> OBJECT(machine), "ram",
> >> >> > +                                         machine->ram_size);
> >> >> > +
> memory_region_add_subregion_overlap(get_system_memory(), 0,
> >> >> &s->ram, 0);
> >> >>
> >> >> I thought the SoC handled this now? Why do you need to add to
> >> >> system_memory?
> >> >
> >> > If I don't map it here, how do RAM accesses from the CPUs work?
> >> >
> >>
> >> Do the CPUs not have their AS'es connected to your custom ASes by the
> SoC
> >> layer?
> >>
> >> > Or are you saying that I should still do this, but do it in the SoC not the
> >> board level?
> >> >
> >>
> >> I was hoping we could get away with 0 use of system_memory.
> >
> > On further investigation, I don't think it's possible to wire up CPU ASes
> explicitly. There's no obvious property to set. Each cpu->as is initialised to
> point to address_space_memory at the top of cpu_exec_init(), and there is
> no way I could see to override that.
> >
> > I think what I have now is pretty clean, but if you'd prefer to do the
> mapping at into the global AS at SoC level that's fine with me too.
> >
> 
> If it cant be done yet, what is here is a preferable approach. PMM has
> some work on list for CPU ASes that may be realted, moreso for the
> secure attributes though I think.

Ok. It looks like the patch you CCed me on would enable this. But I don't really want to wait for that with Pi, and honestly I don't think this is too bad -- there are only a handful of things in the system_memory space (the RAM, the peripherals blob, and the 2836 multi-core controller on pi2), and it seems unlikely to be of great benefit unless some future madman starts building multi-pi boards with bizarre mapping schemes. Let's hope not :)

Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-15  0:43             ` Andrew Baumann
@ 2016-01-15  1:09               ` Peter Crosthwaite
  0 siblings, 0 replies; 26+ messages in thread
From: Peter Crosthwaite @ 2016-01-15  1:09 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

On Thu, Jan 14, 2016 at 4:43 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Thursday, 14 January 2016 15:35
>>
>> On Thu, Jan 14, 2016 at 3:04 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> > Hi Peter,
>> >
>> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> >> Sent: Tuesday, 12 January 2016 16:44
>> >> On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
>> >> <Andrew.Baumann@microsoft.com> wrote:
>> >> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> >> >> Sent: Monday, 11 January 2016 19:58
>> >> >> > +    /* Allocate and map RAM */
>> >> >> > +    memory_region_allocate_system_memory(&s->ram,
>> >> >> OBJECT(machine), "ram",
>> >> >> > +                                         machine->ram_size);
>> >> >> > +
>> memory_region_add_subregion_overlap(get_system_memory(), 0,
>> >> >> &s->ram, 0);
>> >> >>
>> >> >> I thought the SoC handled this now? Why do you need to add to
>> >> >> system_memory?
>> >> >
>> >> > If I don't map it here, how do RAM accesses from the CPUs work?
>> >> >
>> >>
>> >> Do the CPUs not have their AS'es connected to your custom ASes by the
>> SoC
>> >> layer?
>> >>
>> >> > Or are you saying that I should still do this, but do it in the SoC not the
>> >> board level?
>> >> >
>> >>
>> >> I was hoping we could get away with 0 use of system_memory.
>> >
>> > On further investigation, I don't think it's possible to wire up CPU ASes
>> explicitly. There's no obvious property to set. Each cpu->as is initialised to
>> point to address_space_memory at the top of cpu_exec_init(), and there is
>> no way I could see to override that.
>> >
>> > I think what I have now is pretty clean, but if you'd prefer to do the
>> mapping at into the global AS at SoC level that's fine with me too.
>> >
>>
>> If it cant be done yet, what is here is a preferable approach. PMM has
>> some work on list for CPU ASes that may be realted, moreso for the
>> secure attributes though I think.
>
> Ok. It looks like the patch you CCed me on would enable this. But I don't really want to wait for that with Pi, and honestly I don't think this is too bad -- there are only a handful of things in the system_memory space (the RAM, the peripherals blob, and the 2836 multi-core controller on pi2), and it seems unlikely to be of great benefit unless some future madman starts building multi-pi boards with bizarre mapping schemes. Let's hope not :)
>

Agree

Regards,
Peter

> Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine
  2016-01-13  0:43       ` Peter Crosthwaite
  2016-01-14 23:04         ` Andrew Baumann
@ 2016-01-16  0:04         ` Andrew Baumann
  1 sibling, 0 replies; 26+ messages in thread
From: Andrew Baumann @ 2016-01-16  0:04 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil, qemu-devel,
	qemu-arm, Paolo Bonzini

Hi Peter,

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Tuesday, 12 January 2016 16:44
> On Tue, Jan 12, 2016 at 3:53 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Monday, 11 January 2016 19:58
> > [...]
> >> > +static void write_board_setup(ARMCPU *cpu, const struct
> arm_boot_info
> >> *info)
> >>
> >> This is almost identical to Highbank, I'm guessing you are stubbing monitor
> >> firmware where you get away with nopping all the SMCs? Maybe we
> should
> >> split
> >> Highbanks version off to common code, and parameterise the few
> >> differences.
> >>
> >> write_board_setup_dummy_monitior(ARMCPU *cpu ..., uint32_t
> scr_flags);
> >>
> >> or something like it. Makes sense to be in arm/boot.c .
> >
> > Actually, I added this only to make Linux happy (and yes, it was derived
> from highbank). Without it, I was seeing complaints about:
> > Ignoring attempt to switch CPSR_A flag from non-secure world with
> SCR.AW bit clear
> > Ignoring attempt to switch CPSR_F flag from non-secure world with SCR.FW
> bit clear
> >
> > I don't believe anything actually uses the SMC handler after boot. I think it's
> just an architectural requirement to flush the change to non-secure mode.
> >
> > I would prefer not to touch highbank, because I don't know how to test it.
> Is it better to submit this patch without the board setup?
> >
> 
> I can test Highbank for you, or you can use this project:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg00755.html
> 
> The build takes a while and costs about 50GB of disk space, but the
> amount of setup needed should be pretty low.
> 
> FWIW, that was the test system that found the need for this FW in HB.

If it's easy for you, I'd prefer if you could test with Highbank. You should be able to apply patch 7/8 from v4 of the series (sent just now) independently. The changes are minor but significant: mostly avoiding armv7 instructions like movw, and loading the vectors and setup code as separate ROM blobs. Overall, I'm still a little worried about the long-term maintainability of this approach versus separate copies...

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-01-16  0:04 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-01  0:31 [Qemu-devel] [PATCH v3 0/7] Raspberry Pi 2 support Andrew Baumann
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 1/7] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 2/7] bcm2835_property: add bcm2835 property channel Andrew Baumann
2016-01-12  3:53   ` Peter Crosthwaite
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 3/7] bcm2835_ic: add bcm2835 interrupt controller Andrew Baumann
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 4/7] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
2016-01-06  2:13   ` Alistair Francis
2016-01-06  6:07     ` Andrew Baumann
2016-01-06 13:32       ` Peter Crosthwaite
2016-01-06 20:04         ` Alistair Francis
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 5/7] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
2016-01-12  3:54   ` Peter Crosthwaite
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 6/7] bcm2836: add bcm2836 soc device Andrew Baumann
2016-01-12  3:56   ` Peter Crosthwaite
2016-01-12 22:56     ` Andrew Baumann
2016-01-12 23:14       ` Peter Crosthwaite
2016-01-13  0:09         ` Andrew Baumann
2016-01-01  0:31 ` [Qemu-devel] [PATCH v3 7/7] raspi: add raspberry pi 2 machine Andrew Baumann
2016-01-12  3:57   ` Peter Crosthwaite
2016-01-12 23:53     ` Andrew Baumann
2016-01-13  0:43       ` Peter Crosthwaite
2016-01-14 23:04         ` Andrew Baumann
2016-01-14 23:34           ` Peter Crosthwaite
2016-01-15  0:43             ` Andrew Baumann
2016-01-15  1:09               ` Peter Crosthwaite
2016-01-16  0:04         ` Andrew Baumann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.