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

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

v4 changes:
 * refactoring in bcm2836_control
 * minor cleanup / style tweaks in other device emulations
 * use qemu MAC address in bcm2835_property
 * avoid use of smp_cpus outside raspi.c
 * made setup blobs relocatable, and merged with highbank's copy in common code

XXX: patch 7/8 (new in v4) changes the secure boot setup blob for
Highbank to a common version shared with pi, and I have not tested it
with that board.

Cheers,
Andrew

Andrew Baumann (8):
  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
  arm/boot: move highbank secure board setup code to common routine
  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                     | 165 +++++++++++++++++
 hw/arm/boot.c                        |  53 ++++++
 hw/arm/highbank.c                    |  37 +---
 hw/arm/raspi.c                       | 156 ++++++++++++++++
 hw/intc/Makefile.objs                |   1 +
 hw/intc/bcm2835_ic.c                 | 236 +++++++++++++++++++++++++
 hw/intc/bcm2836_control.c            | 303 +++++++++++++++++++++++++++++++
 hw/misc/Makefile.objs                |   2 +
 hw/misc/bcm2835_mbox.c               | 333 +++++++++++++++++++++++++++++++++++
 hw/misc/bcm2835_property.c           | 286 ++++++++++++++++++++++++++++++
 include/hw/arm/arm.h                 |   5 +
 include/hw/arm/bcm2835_peripherals.h |  42 +++++
 include/hw/arm/bcm2836.h             |  34 ++++
 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   |  31 ++++
 22 files changed, 2132 insertions(+), 35 deletions(-)
 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] 25+ messages in thread

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

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] 25+ messages in thread

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

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>
---

Notes:
    v4:
    * added LOG_UNIMP as appropriate
    * use qemu_macaddr_default_if_unset to allocate a MAC address, and dma_memory_write to write it
    * assert that we're not pending, rather than dropping a request on the floor

 hw/misc/Makefile.objs              |   1 +
 hw/misc/bcm2835_property.c         | 286 +++++++++++++++++++++++++++++++++++++
 include/hw/misc/bcm2835_property.h |  31 ++++
 3 files changed, 318 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..52c9b8d
--- /dev/null
+++ b/hw/misc/bcm2835_property.c
@@ -0,0 +1,286 @@
+/*
+ * 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"
+#include "sysemu/dma.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 */
+            qemu_log_mask(LOG_UNIMP,
+                          "bcm2835_property: %x get board model NYI\n", tag);
+            resplen = 4;
+            break;
+        case 0x00010002: /* Get board revision */
+            qemu_log_mask(LOG_UNIMP,
+                          "bcm2835_property: %x get board revision NYI\n", tag);
+            resplen = 4;
+            break;
+        case 0x00010003: /* Get board MAC address */
+            resplen = sizeof(s->macaddr.a);
+            dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen);
+            break;
+        case 0x00010004: /* Get board serial */
+            qemu_log_mask(LOG_UNIMP,
+                          "bcm2835_property: %x get board serial NYI\n", tag);
+            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 */
+            qemu_log_mask(LOG_UNIMP,
+                          "bcm2835_property: %x set clock state NYI\n", tag);
+            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 */
+            qemu_log_mask(LOG_UNIMP,
+                          "bcm2835_property: %x set clock rates NYI\n", tag);
+            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:
+        /* bcm2835_mbox should check our pending status before pushing */
+        assert(!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,
+    .fields      = (VMStateField[]) {
+        VMSTATE_MACADDR(macaddr, BCM2835PropertyState),
+        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);
+
+    /* TODO: connect to MAC address of USB NIC device, once we emulate it */
+    qemu_macaddr_default_if_unset(&s->macaddr);
+
+    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..fcf5f3d
--- /dev/null
+++ b/include/hw/misc/bcm2835_property.h
@@ -0,0 +1,31 @@
+/*
+ * 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"
+#include "net/net.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;
+    MACAddr macaddr;
+    uint32_t ram_size;
+    uint32_t addr;
+    bool pending;
+} BCM2835PropertyState;
+
+#endif
-- 
2.5.3

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

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

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

Notes:
    v3:
     * minor style tweaks
     * use extract32 in place of manual shift/masking
    
    v2:
     * 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] 25+ messages in thread

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

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:
     * 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] 25+ messages in thread

* [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic
  2016-01-15 23:58 [Qemu-devel] [PATCH v4 0/8] Raspberry Pi 2 support Andrew Baumann
                   ` (3 preceding siblings ...)
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
@ 2016-01-15 23:58 ` Andrew Baumann
  2016-01-29  4:37   ` Peter Crosthwaite
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device Andrew Baumann
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-15 23:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini,
	Rob Herring

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:
    v4:
    * delete unused defs
    * s/localirqs/timerirqs/
    * factor out deliver_local() from bcm2836_control_update
    * use deposit32 in place of bit manipulation in set_local_irq
    * introduced register offset defs, and reduced comments in read/write handlers
    * delete commented code
    * s/_/-/ rename GPIOs
    
    v3:
     * uint8 localirqs
     * style tweaks
     * add MR access size limits

 hw/intc/Makefile.objs             |   2 +-
 hw/intc/bcm2836_control.c         | 303 ++++++++++++++++++++++++++++++++++++++
 include/hw/intc/bcm2836_control.h |  51 +++++++
 3 files changed, 355 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..f0b7b0a
--- /dev/null
+++ b/hw/intc/bcm2836_control.c
@@ -0,0 +1,303 @@
+/*
+ * 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 REG_GPU_ROUTE           0x0c
+#define REG_TIMERCONTROL        0x40
+#define REG_MBOXCONTROL         0x50
+#define REG_IRQSRC              0x60
+#define REG_FIQSRC              0x70
+#define REG_MBOX0_WR            0x80
+#define REG_MBOX0_RDCLR         0xc0
+#define REG_LIMIT              0x100
+
+#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
+
+static void deliver_local(BCM2836ControlState *s, uint8_t core, uint8_t irq,
+                          uint32_t controlreg, uint8_t controlidx)
+{
+    if (FIQ_BIT(controlreg, controlidx)) {
+        /* deliver a FIQ */
+        s->fiqsrc[core] |= (uint32_t)1 << irq;
+    } else if (IRQ_BIT(controlreg, controlidx)) {
+        /* deliver an IRQ */
+        s->irqsrc[core] |= (uint32_t)1 << irq;
+    } else {
+        /* the interrupt is masked */
+    }
+}
+
+/* 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 timer interrupts for this core */
+        if (s->timerirqs[i]) {
+            assert(s->timerirqs[i] < (1 << IRQ_MAILBOX0)); /* sanity check */
+            for (j = 0; j < IRQ_MAILBOX0; j++) {
+                if ((s->timerirqs[i] & (1 << j)) != 0) {
+                    /* local interrupt j is set */
+                    deliver_local(s, i, j, s->timercontrol[i], j);
+                }
+            }
+        }
+
+        /* handle mailboxes for this core */
+        for (j = 0; j < BCM2836_MBPERCORE; j++) {
+            if (s->mailboxes[i * BCM2836_MBPERCORE + j] != 0) {
+                /* mailbox j is set */
+                deliver_local(s, i, j + IRQ_MAILBOX0, s->mailboxcontrol[i], j);
+            }
+        }
+    }
+
+    /* 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);
+
+    s->timerirqs[core] = deposit32(s->timerirqs[core], local_irq, 1, !!level);
+
+    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 == REG_GPU_ROUTE) {
+        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 >= REG_TIMERCONTROL && offset < REG_MBOXCONTROL) {
+        return s->timercontrol[(offset - REG_TIMERCONTROL) >> 2];
+    } else if (offset >= REG_MBOXCONTROL && offset < REG_IRQSRC) {
+        return s->mailboxcontrol[(offset - REG_MBOXCONTROL) >> 2];
+    } else if (offset >= REG_IRQSRC && offset < REG_FIQSRC) {
+        return s->irqsrc[(offset - REG_IRQSRC) >> 2];
+    } else if (offset >= REG_FIQSRC && offset < REG_MBOX0_WR) {
+        return s->fiqsrc[(offset - REG_FIQSRC) >> 2];
+    } else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
+        return s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 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 == REG_GPU_ROUTE) {
+        s->route_gpu_irq = val & 0x3;
+        s->route_gpu_fiq = (val >> 2) & 0x3;
+    } else if (offset >= REG_TIMERCONTROL && offset < REG_MBOXCONTROL) {
+        s->timercontrol[(offset - REG_TIMERCONTROL) >> 2] = val & 0xff;
+    } else if (offset >= REG_MBOXCONTROL && offset < REG_IRQSRC) {
+        s->mailboxcontrol[(offset - REG_MBOXCONTROL) >> 2] = val & 0xff;
+    } else if (offset >= REG_MBOX0_WR && offset < REG_MBOX0_RDCLR) {
+        s->mailboxes[(offset - REG_MBOX0_WR) >> 2] |= val;
+    } else if (offset >= REG_MBOX0_RDCLR && offset < REG_LIMIT) {
+        s->mailboxes[(offset - REG_MBOX0_RDCLR) >> 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, REG_LIMIT);
+    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);
+
+    /* 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..144c42f
--- /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 timerirqs[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] 25+ messages in thread

* [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device
  2016-01-15 23:58 [Qemu-devel] [PATCH v4 0/8] Raspberry Pi 2 support Andrew Baumann
                   ` (4 preceding siblings ...)
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
@ 2016-01-15 23:58 ` Andrew Baumann
  2016-01-29  4:50   ` Peter Crosthwaite
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 7/8] arm/boot: move highbank secure board setup code to common routine Andrew Baumann
       [not found] ` <1452902337-13844-9-git-send-email-Andrew.Baumann@microsoft.com>
  7 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-15 23:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini,
	Rob Herring

This is the SoC for Raspberry Pi 2.

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

Notes:
    v4:
    * s/ic/control/
    * replace use of smp_cpus with enabled-cpus property
    * propagate errors rather than exit(1)

 hw/arm/Makefile.objs     |   2 +-
 hw/arm/bcm2836.c         | 165 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/bcm2836.h |  34 ++++++++++
 3 files changed, 200 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..0fd6118
--- /dev/null
+++ b/hw/arm/bcm2836.c
@@ -0,0 +1,165 @@
+/*
+ * 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 "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;
+
+    for (n = 0; n < BCM2836_NCPUS; 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->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
+    object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
+    qdev_set_parent_bus(DEVICE(&s->control), 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->control), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
+
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
+        qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
+        qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
+
+    for (n = 0; n < BCM2836_NCPUS; n++) {
+        /* Mirror bcm2836, which has clusterid set to 0xf
+         * TODO: this should be converted to a property of ARM_CPU
+         */
+        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_propagate(errp, err);
+            return;
+        }
+
+        /* start powered off if not enabled */
+        object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
+                                 "start-powered-off", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+
+        /* Connect irq/fiq outputs from the interrupt controller. */
+        qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
+                qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
+        qdev_connect_gpio_out_named(DEVICE(&s->control), "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->control), "cntpsirq", 0);
+        s->cpus[n].gt_timer_outputs[GTIMER_VIRT]
+            = qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", 0);
+    }
+}
+
+static Property bcm2836_props[] = {
+    DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void bcm2836_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->props = bcm2836_props;
+    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..cd0fd02
--- /dev/null
+++ b/include/hw/arm/bcm2836.h
@@ -0,0 +1,34 @@
+/*
+ * 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 >*/
+
+    uint32_t enabled_cpus;
+    ARMCPU cpus[BCM2836_NCPUS];
+    BCM2836ControlState control;
+    BCM2835PeripheralState peripherals;
+} BCM2836State;
+
+#endif /* BCM2836_H */
-- 
2.5.3

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

* [Qemu-devel] [PATCH v4 7/8] arm/boot: move highbank secure board setup code to common routine
  2016-01-15 23:58 [Qemu-devel] [PATCH v4 0/8] Raspberry Pi 2 support Andrew Baumann
                   ` (5 preceding siblings ...)
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device Andrew Baumann
@ 2016-01-15 23:58 ` Andrew Baumann
  2016-01-29  7:11   ` Peter Crosthwaite
       [not found] ` <1452902337-13844-9-git-send-email-Andrew.Baumann@microsoft.com>
  7 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-15 23:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini,
	Rob Herring

The new version is slightly different, to support Rasbperry Pi (in
particular, Pi1's arm11 core which doesn't support v7 instructions
such as MOVW).

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

Notes:
    This has not yet been tested on Highbank! Peter C -- please help :)
    
    Honestly, I fear that the overhead of maintaining support for two very
    different platforms (including Pi1) may outweigh the value of unifying
    these blobs.

 hw/arm/boot.c        | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/highbank.c    | 37 ++----------------------------------
 include/hw/arm/arm.h |  5 +++++
 3 files changed, 60 insertions(+), 35 deletions(-)

diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 75f69bf..bc1ea4d 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -178,6 +178,59 @@ static void default_write_secondary(ARMCPU *cpu,
                      smpboot, fixupcontext);
 }
 
+void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
+                                            const struct arm_boot_info *info,
+                                            hwaddr mvbar_addr)
+{
+    int n;
+    uint32_t mvbar_blob[] = {
+        /* mvbar_addr: secure monitor vectors
+         * Default unimplemented and unused vectors to spin. Makes it
+         * easier to debug (as opposed to the CPU running away).
+         */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+        0xEAFFFFFE, /* (spin) */
+    };
+    uint32_t board_setup_blob[] = {
+        /* board setup addr */
+        0xE3A00E00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */
+        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
+        0xEE110F11, /* mrc     p15, 0, r0, c1 , c1, 0 ;read SCR */
+        0xE3800031, /* orr     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                     ;call monitor to flush SCR */
+        0xE1A0F001, /* mov     pc, r1                 ;return */
+    };
+
+    /* check that mvbar_addr is correctly aligned and relocatable (using MOV) */
+    assert((mvbar_addr & 0x1f) == 0 && (mvbar_addr >> 4) < 0x100);
+
+    /* check that these blobs don't overlap */
+    assert((mvbar_addr + sizeof(mvbar_blob) <= info->board_setup_addr)
+          || (info->board_setup_addr + sizeof(board_setup_blob) <= mvbar_addr));
+
+    for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) {
+        mvbar_blob[n] = tswap32(mvbar_blob[n]);
+    }
+    rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob),
+                       mvbar_addr);
+
+    for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
+        board_setup_blob[n] = tswap32(board_setup_blob[n]);
+    }
+    rom_add_blob_fixed("board-setup", board_setup_blob,
+                       sizeof(board_setup_blob), info->board_setup_addr);
+}
+
+
+
 static void default_reset_secondary(ARMCPU *cpu,
                                     const struct arm_boot_info *info)
 {
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index cb9926e..e5105fb 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -34,49 +34,16 @@
 #define MPCORE_PERIPHBASE       0xfff10000
 
 #define MVBAR_ADDR              0x200
+#define BOARD_SETUP_ADDR        (MVBAR_ADDR + 8 * sizeof(uint32_t))
 
 #define NIRQ_GIC                160
 
 /* Board init.  */
 
-/* MVBAR_ADDR is limited by precision of movw */
-
-QEMU_BUILD_BUG_ON(MVBAR_ADDR >= (1 << 16));
-
-#define ARMV7_IMM16(x) (extract32((x),  0, 12) | \
-                        extract32((x), 12,  4) << 16)
-
 static void hb_write_board_setup(ARMCPU *cpu,
                                  const struct arm_boot_info *info)
 {
-    int n;
-    uint32_t board_setup_blob[] = {
-        /* MVBAR_ADDR */
-        /* Default unimplemented and unused vectors to spin. Makes it
-         * easier to debug (as opposed to the CPU running away).
-         */
-        0xeafffffe, /* notused1: b notused */
-        0xeafffffe, /* notused2: b notused */
-        0xe1b0f00e, /* smc: movs pc, lr - exception return */
-        0xeafffffe, /* prefetch_abort: b prefetch_abort */
-        0xeafffffe, /* data_abort: b data_abort */
-        0xeafffffe, /* notused3: b notused3 */
-        0xeafffffe, /* irq: b irq */
-        0xeafffffe, /* fiq: b fiq */
-#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t))
-        0xe3000000 + ARMV7_IMM16(MVBAR_ADDR), /* movw r0, MVBAR_ADDR */
-        0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 - set MVBAR */
-        0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 - get SCR */
-        0xe3810001, /* orr r0, #1 - set NS */
-        0xee010f11, /* mcr p15, 0, r0, c1 , c1, 0 - set SCR */
-        0xe1600070, /* smc - go to monitor mode to flush NS change */
-        0xe12fff1e, /* bx lr - return to caller */
-    };
-    for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
-        board_setup_blob[n] = tswap32(board_setup_blob[n]);
-    }
-    rom_add_blob_fixed("board-setup", board_setup_blob,
-                       sizeof(board_setup_blob), MVBAR_ADDR);
+    arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
 }
 
 static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index c26b0e3..75bfe26 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -126,4 +126,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
    ticks.  */
 extern int system_clock_scale;
 
+/* Write a secure board setup routine with a dummy handler for SMCs */
+void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
+                                            const struct arm_boot_info *info,
+                                            hwaddr mvbar_addr);
+
 #endif /* !ARM_MISC_H */
-- 
2.5.3

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

* Re: [Qemu-devel] [PATCH v4 1/8] bcm2835_mbox: add BCM2835 mailboxes
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 1/8] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
@ 2016-01-26  5:54   ` Peter Crosthwaite
  0 siblings, 0 replies; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-26  5:54 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> 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 */

newline before */

(sorry I missed your clarification question on this earlier)

> +    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 (?) */

same.

> +
> +    /* 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;

A nit, but a blank line here to separate the external interfaces from
the internal state.

I haven'y rechecked the logic line-over-line this time, but it was
good last time and the stylistic comments are all addressed. So
otherwise:

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +    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	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/8] bcm2835_property: add bcm2835 property channel
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 2/8] bcm2835_property: add bcm2835 property channel Andrew Baumann
@ 2016-01-26  6:03   ` Peter Crosthwaite
  0 siblings, 0 replies; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-26  6:03 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> 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>
> ---
>
> Notes:
>     v4:
>     * added LOG_UNIMP as appropriate
>     * use qemu_macaddr_default_if_unset to allocate a MAC address, and dma_memory_write to write it
>     * assert that we're not pending, rather than dropping a request on the floor
>
>  hw/misc/Makefile.objs              |   1 +
>  hw/misc/bcm2835_property.c         | 286 +++++++++++++++++++++++++++++++++++++
>  include/hw/misc/bcm2835_property.h |  31 ++++
>  3 files changed, 318 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..52c9b8d
> --- /dev/null
> +++ b/hw/misc/bcm2835_property.c
> @@ -0,0 +1,286 @@
> +/*
> + * 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"
> +#include "sysemu/dma.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 */
> +            qemu_log_mask(LOG_UNIMP,
> +                          "bcm2835_property: %x get board model NYI\n", tag);
> +            resplen = 4;
> +            break;
> +        case 0x00010002: /* Get board revision */
> +            qemu_log_mask(LOG_UNIMP,
> +                          "bcm2835_property: %x get board revision NYI\n", tag);
> +            resplen = 4;
> +            break;
> +        case 0x00010003: /* Get board MAC address */
> +            resplen = sizeof(s->macaddr.a);
> +            dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen);
> +            break;
> +        case 0x00010004: /* Get board serial */
> +            qemu_log_mask(LOG_UNIMP,
> +                          "bcm2835_property: %x get board serial NYI\n", tag);
> +            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 */

blank before */

A grep on "^\+[ \t]*\*.*\*\/$" on the patch series will catch-all.

Otherwise,

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +            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 */
> +            qemu_log_mask(LOG_UNIMP,
> +                          "bcm2835_property: %x set clock state NYI\n", tag);
> +            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 */
> +            qemu_log_mask(LOG_UNIMP,
> +                          "bcm2835_property: %x set clock rates NYI\n", tag);
> +            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:
> +        /* bcm2835_mbox should check our pending status before pushing */
> +        assert(!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,
> +    .fields      = (VMStateField[]) {
> +        VMSTATE_MACADDR(macaddr, BCM2835PropertyState),
> +        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);
> +
> +    /* TODO: connect to MAC address of USB NIC device, once we emulate it */
> +    qemu_macaddr_default_if_unset(&s->macaddr);
> +
> +    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..fcf5f3d
> --- /dev/null
> +++ b/include/hw/misc/bcm2835_property.h
> @@ -0,0 +1,31 @@
> +/*
> + * 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"
> +#include "net/net.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;
> +    MACAddr macaddr;
> +    uint32_t ram_size;
> +    uint32_t addr;
> +    bool pending;
> +} BCM2835PropertyState;
> +
> +#endif
> --
> 2.5.3
>

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

* Re: [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
@ 2016-01-26  6:14   ` Peter Crosthwaite
  2016-01-26  6:23     ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-26  6:14 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 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:
>      * 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);

Should this just be normal memory_region_init?

> +    object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr), NULL);

This seems like a weird parenting, to have the SoC as child to an
object it just created. Is the problem you need a parent before others
can parent to you?

Otherwise,

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +    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	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-26  6:14   ` Peter Crosthwaite
@ 2016-01-26  6:23     ` Andrew Baumann
  2016-01-26  8:03       ` Peter Crosthwaite
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-26  6:23 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Monday, 25 January 2016 22:14
> 
> On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
[...]
> > +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);
> 
> Should this just be normal memory_region_init?

I think so -- it's just a container region, and I probably copy and pasted the API here. The two MR init APIs seem almost but not-quite identical when NULL callbacks are used. Can you briefly explain the difference?

> > +    object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr),
> NULL);
> 
> This seems like a weird parenting, to have the SoC as child to an
> object it just created. Is the problem you need a parent before others
> can parent to you?

I'm confused by this question: Unless I'm mistaken, the parent here is BCM2835PeripheralState, the child is the new memory region we just called init on.

Thanks,
Andrew

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

* Re: [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-26  6:23     ` Andrew Baumann
@ 2016-01-26  8:03       ` Peter Crosthwaite
  2016-01-26 19:12         ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-26  8:03 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Mon, Jan 25, 2016 at 10:23 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Monday, 25 January 2016 22:14
>>
>> On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
> [...]
>> > +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);
>>
>> Should this just be normal memory_region_init?
>
> I think so -- it's just a container region, and I probably copy and pasted the API here. The two MR init APIs seem almost but not-quite identical when NULL callbacks are used. Can you briefly explain the difference?
>

hmm I guess the defaulting to &unassigned_mem_ops. memory_region_init
looks to assume you will populate the usable subregions. Are you
relying on unassigned ops?

>> > +    object_property_add_child(obj, "peripheral-io", OBJECT(&s->peri_mr),
>> NULL);
>>
>> This seems like a weird parenting, to have the SoC as child to an
>> object it just created. Is the problem you need a parent before others
>> can parent to you?
>
> I'm confused by this question: Unless I'm mistaken, the parent here is BCM2835PeripheralState, the child is the new memory region we just called init on.
>

My bad - I have it backwards.

Regards,
Peter

> Thanks,
> Andrew

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

* Re: [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-26  8:03       ` Peter Crosthwaite
@ 2016-01-26 19:12         ` Andrew Baumann
  2016-01-26 19:40           ` Peter Maydell
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-26 19:12 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Tuesday, 26 January 2016 00:03
> 
> On Mon, Jan 25, 2016 at 10:23 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Monday, 25 January 2016 22:14
> >>
> >> On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
> >> <Andrew.Baumann@microsoft.com> wrote:
> > [...]
> >> > +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);
> >>
> >> Should this just be normal memory_region_init?
> >
> > I think so -- it's just a container region, and I probably copy and pasted the
> API here. The two MR init APIs seem almost but not-quite identical when
> NULL callbacks are used. Can you briefly explain the difference?
> >
> 
> hmm I guess the defaulting to &unassigned_mem_ops. memory_region_init
> looks to assume you will populate the usable subregions. Are you
> relying on unassigned ops?

Actually, memory_region_initfn also sets the unassigned_ops, so the only difference appears to be mr->terminates, which is set to true for init_io. This flag affects the behaviour of render_memory_region(), which terminates early if !mr->terminates. So the difference is that the gaps between the subregions (i.e., the actual devices) wouldn't be rendered. But what difference this makes in practice is unclear to me. It can only matter if the CPU accesses an undefined / unimplemented device, but even then it looks to me like it would end up at the same unassigned ops code anyway, so I suspect it's irrelevant.

If memory_region_init works, I'll go with that.

Andrew

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

* Re: [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals
  2016-01-26 19:12         ` Andrew Baumann
@ 2016-01-26 19:40           ` Peter Maydell
  0 siblings, 0 replies; 25+ messages in thread
From: Peter Maydell @ 2016-01-26 19:40 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Rob Herring, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers,
	Peter Crosthwaite, qemu-arm, Paolo Bonzini

On 26 January 2016 at 19:12, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Tuesday, 26 January 2016 00:03
>> On Mon, Jan 25, 2016 at 10:23 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> >> > +    /* Memory region for peripheral devices, which we export to our
>> >> parent */
>> >> > +    memory_region_init_io(&s->peri_mr, obj, NULL, s, "bcm2835-
>> >> peripherals",
>> >> > +                          0x1000000);
>> >>
>> >> Should this just be normal memory_region_init?
>> >
>> > I think so -- it's just a container region, and I probably copy and pasted the
>> API here. The two MR init APIs seem almost but not-quite identical when
>> NULL callbacks are used. Can you briefly explain the difference?

NULL callbacks are the same thing as memory_region_init_reservation(),
which is for defining a "you can't get here" part of the address space.
This is used only when KVM is enabled, by devices whose real implementation
of a bit of memory mapped IO is in the host kernel. The host kernel will
intercept accesses to that region and QEMU never sees accesses to them
(exception: emulated DMA, which is the only reason there's a behaviour
at all rather than an assertion). This is why such regions get marked as
mr->terminates: they really do have no "holes" in them.

So the general rules are:
 * use a plain container (created via memory_region_init())
   for almost any situation where you're creating something whose
   behaviour is built up by adding together subregions
 * use memory_region_init_io() with non-NULL ops for creating straightforward
   "leaf" regions which have defined device behaviour
 * similarly, memory_region_init_ram() for ram, etc
 * use memory_region_init_reservation() or memory_region_init_io() with a
   NULL ops pointer if you're the QEMU part of a KVM in-kernel
   irqchip/etc.
 * If you have a container memory region, but you need a "behaviour for
   the bits that aren't covered by specific subregions" that's specific to
   this device, then you have two choices:
   (a) use a "background" subregion that covers the whole space and
       has a lower priority than any of the other subregions
   (b) create your container with one of the other memory_region_init
       functions and use the IO callbacks/ram/etc to define the background
       behaviour. Such an object will still support subregions being added.
   I think (a) is generally cleaner, but the API permits adding
   subregions to MRs other than pure containers for the benefit of
   the odd few cases where (b) is done.

docs/memory.txt could probably use an update to:
(a) specifically mention the functions to use to create the various
regions listed in the 'Types of regions' section
(b) describe the 'reservation' kind of memory region

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
@ 2016-01-29  4:37   ` Peter Crosthwaite
  2016-01-29  4:42     ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29  4:37 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> 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:
>     v4:
>     * delete unused defs
>     * s/localirqs/timerirqs/
>     * factor out deliver_local() from bcm2836_control_update
>     * use deposit32 in place of bit manipulation in set_local_irq
>     * introduced register offset defs, and reduced comments in read/write handlers
>     * delete commented code
>     * s/_/-/ rename GPIOs
>
>     v3:
>      * uint8 localirqs
>      * style tweaks
>      * add MR access size limits
>
>  hw/intc/Makefile.objs             |   2 +-
>  hw/intc/bcm2836_control.c         | 303 ++++++++++++++++++++++++++++++++++++++
>  include/hw/intc/bcm2836_control.h |  51 +++++++
>  3 files changed, 355 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..f0b7b0a
> --- /dev/null
> +++ b/hw/intc/bcm2836_control.c
> @@ -0,0 +1,303 @@
> +/*
> + * 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 REG_GPU_ROUTE           0x0c
> +#define REG_TIMERCONTROL        0x40
> +#define REG_MBOXCONTROL         0x50
> +#define REG_IRQSRC              0x60
> +#define REG_FIQSRC              0x70
> +#define REG_MBOX0_WR            0x80
> +#define REG_MBOX0_RDCLR         0xc0
> +#define REG_LIMIT              0x100
> +
> +#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
> +
> +static void deliver_local(BCM2836ControlState *s, uint8_t core, uint8_t irq,
> +                          uint32_t controlreg, uint8_t controlidx)
> +{
> +    if (FIQ_BIT(controlreg, controlidx)) {
> +        /* deliver a FIQ */
> +        s->fiqsrc[core] |= (uint32_t)1 << irq;
> +    } else if (IRQ_BIT(controlreg, controlidx)) {
> +        /* deliver an IRQ */
> +        s->irqsrc[core] |= (uint32_t)1 << irq;
> +    } else {
> +        /* the interrupt is masked */
> +    }
> +}
> +
> +/* 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 timer interrupts for this core */
> +        if (s->timerirqs[i]) {
> +            assert(s->timerirqs[i] < (1 << IRQ_MAILBOX0)); /* sanity check */
> +            for (j = 0; j < IRQ_MAILBOX0; j++) {

I think <= IRQ_CNTVIRQ is cleaner, as it keeps "MAILBOX" out of the timer code.

> +                if ((s->timerirqs[i] & (1 << j)) != 0) {
> +                    /* local interrupt j is set */
> +                    deliver_local(s, i, j, s->timercontrol[i], j);
> +                }
> +            }
> +        }
> +
> +        /* handle mailboxes for this core */
> +        for (j = 0; j < BCM2836_MBPERCORE; j++) {
> +            if (s->mailboxes[i * BCM2836_MBPERCORE + j] != 0) {
> +                /* mailbox j is set */
> +                deliver_local(s, i, j + IRQ_MAILBOX0, s->mailboxcontrol[i], j);
> +            }
> +        }
> +    }
> +
> +    /* 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);

Continuing above, this is inconsistent with the above where you use <
IRQ_MAILBOX0 instead for the same check.

> +
> +    s->timerirqs[core] = deposit32(s->timerirqs[core], local_irq, 1, !!level);
> +
> +    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);
> +}
> +

> +    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 timerirqs[BCM2836_NCORES];
> +

This ...

> +    /* 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];
> +

And this are absent from the VMSD, but after some thought they don't
need to be as they are pure functions of the input pin state that is
always refreshable from other state no? I would these together with a
brief comment as to the above, and keep the migratable state (genuine
device state) all together.

Otherwise,

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +    /* outputs to CPU cores */
> +    qemu_irq irq[BCM2836_NCORES];
> +    qemu_irq fiq[BCM2836_NCORES];
> +} BCM2836ControlState;
> +
> +#endif
> --
> 2.5.3
>

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

* Re: [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic
  2016-01-29  4:37   ` Peter Crosthwaite
@ 2016-01-29  4:42     ` Andrew Baumann
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Baumann @ 2016-01-29  4:42 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

Hi Peter,

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Thursday, 28 January 2016 20:38
> 
> On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> > This module is specific to the bcm2836 (Pi2). It implements the top
> > level interrupt controller, and mailboxes used for inter-processor
> > synchronisation.
[...]
> > +    for (i = 0; i < BCM2836_NCORES; i++) {
> > +        /* handle local timer interrupts for this core */
> > +        if (s->timerirqs[i]) {
> > +            assert(s->timerirqs[i] < (1 << IRQ_MAILBOX0)); /* sanity check */
> > +            for (j = 0; j < IRQ_MAILBOX0; j++) {
> 
> I think <= IRQ_CNTVIRQ is cleaner, as it keeps "MAILBOX" out of the timer
> code.

Ok.

[...]
> > +typedef struct BCM2836ControlState {
> > +    /*< private >*/
> > +    SysBusDevice busdev;
> > +    /*< public >*/
> > +    MemoryRegion iomem;
> > +
> 
> > +    /* interrupt status registers (not directly visible to user) */
> > +    bool gpu_irq, gpu_fiq;
> > +    uint8_t timerirqs[BCM2836_NCORES];
> > +
> 
> This ...
> 
> > +    /* 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];
> > +
> 
> And this are absent from the VMSD, but after some thought they don't
> need to be as they are pure functions of the input pin state that is
> always refreshable from other state no? I would these together with a
> brief comment as to the above, and keep the migratable state (genuine
> device state) all together.

Yes, that was exactly the intention. I'll comment/revise as you suggest.

> Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Thanks for the review,
Andrew


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

* Re: [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device Andrew Baumann
@ 2016-01-29  4:50   ` Peter Crosthwaite
  0 siblings, 0 replies; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29  4:50 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

SoC in subject line.

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> This is the SoC for Raspberry Pi 2.
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
>
> Notes:
>     v4:
>     * s/ic/control/
>     * replace use of smp_cpus with enabled-cpus property
>     * propagate errors rather than exit(1)
>
>  hw/arm/Makefile.objs     |   2 +-
>  hw/arm/bcm2836.c         | 165 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/arm/bcm2836.h |  34 ++++++++++
>  3 files changed, 200 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..0fd6118
> --- /dev/null
> +++ b/hw/arm/bcm2836.c
> @@ -0,0 +1,165 @@
> +/*
> + * 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 "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;
> +
> +    for (n = 0; n < BCM2836_NCPUS; 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->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
> +    object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
> +    qdev_set_parent_bus(DEVICE(&s->control), 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->control), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
> +
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
> +        qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
> +        qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
> +
> +    for (n = 0; n < BCM2836_NCPUS; n++) {
> +        /* Mirror bcm2836, which has clusterid set to 0xf
> +         * TODO: this should be converted to a property of ARM_CPU
> +         */
> +        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_propagate(errp, err);
> +            return;
> +        }
> +
> +        /* start powered off if not enabled */
> +        object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
> +                                 "start-powered-off", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +
> +        /* Connect irq/fiq outputs from the interrupt controller. */
> +        qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
> +                qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
> +        qdev_connect_gpio_out_named(DEVICE(&s->control), "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->control), "cntpsirq", 0);
> +        s->cpus[n].gt_timer_outputs[GTIMER_VIRT]
> +            = qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", 0);

ARM CPU has

    qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
                       ARRAY_SIZE(cpu->gt_timer_outputs));

So you should be able to use qdev_connect_gpio_out rather than direct
assignment.

> +    }
> +}
> +
> +static Property bcm2836_props[] = {
> +    DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void bcm2836_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->props = bcm2836_props;
> +    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..cd0fd02
> --- /dev/null
> +++ b/include/hw/arm/bcm2836.h
> @@ -0,0 +1,34 @@
> +/*
> + * 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 >*/
> +
> +    uint32_t enabled_cpus;

blank line here.

Otherwise,

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +    ARMCPU cpus[BCM2836_NCPUS];
> +    BCM2836ControlState control;
> +    BCM2835PeripheralState peripherals;
> +} BCM2836State;
> +
> +#endif /* BCM2836_H */
> --
> 2.5.3
>

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

* Re: [Qemu-devel] [PATCH v4 7/8] arm/boot: move highbank secure board setup code to common routine
  2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 7/8] arm/boot: move highbank secure board setup code to common routine Andrew Baumann
@ 2016-01-29  7:11   ` Peter Crosthwaite
  0 siblings, 0 replies; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29  7:11 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> The new version is slightly different, to support Rasbperry Pi (in
> particular, Pi1's arm11 core which doesn't support v7 instructions
> such as MOVW).
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
>
> Notes:
>     This has not yet been tested on Highbank! Peter C -- please help :)
>

qemu-system-arm -kernel
/home/pcrost/poky/build/tmp/deploy/images/qemuarm/zImage -dtb
/home/pcrost/poky/build/tmp/deploy/images/qemuarm/zImage-highbank.dtb
-device ide-drive,drive=sata,bus=ide.0 -M highbank --no-reboot -drive
file=/home/pcrost/poky/build/tmp/deploy/images/qemuarm/core-image-minimal-qemuarm-20160114031411.rootfs.ext4,if=none,id=sata,format=raw
-no-reboot -nographic -m 128 -serial mon:stdio -serial null --append
"console=tty console=ttyAMA0,115200 ip=dhcp mem=128M highres=off
root=/dev/sda rw rootfstype=ext4 console=ttyS0"
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.2.1 (pcrost@pcrost-box) (gcc version
5.2.0 (GCC) ) #1 SMP Wed Jan 13 19:43:13 PST 2016
[    0.000000] CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT
nonaliasing instruction cache
[    0.000000] Machine model: Calxeda Highbank
[    0.000000] cma: Failed to reserve 64 MiB
[    0.000000] Memory policy: Data cache writeback
[    0.000000] DT missing boot CPU MPIDR[23:0], fall back to default
cpu_logical_map
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: Using PSCI v0.1 Function IDs from DT
[    0.000000] CPU: All CPU(s) started in SVC mode.
...
[    4.263064] random: dd urandom read with 84 bits of entropy available
[    7.103537] random: nonblocking pool is initialized
[    9.286935] uart-pl011 fff36000.serial: no DMA platform data

Poky (Yocto Project Reference Distro) 2.0 qemuarm /dev/ttyAMA0

qemuarm login: root
root@qemuarm:~# uname -a
Linux qemuarm 4.2.1 #1 SMP Wed Jan 13 19:43:13 PST 2016 armv7l GNU/Linux
root@qemuarm:~#

Tested-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

>     Honestly, I fear that the overhead of maintaining support for two very
>     different platforms (including Pi1) may outweigh the value of unifying
>     these blobs.
>

Having a look at the new code it is more robust than the original in
its own right with the separation of the blobs.

>  hw/arm/boot.c        | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/arm/highbank.c    | 37 ++----------------------------------
>  include/hw/arm/arm.h |  5 +++++
>  3 files changed, 60 insertions(+), 35 deletions(-)
>
> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
> index 75f69bf..bc1ea4d 100644
> --- a/hw/arm/boot.c
> +++ b/hw/arm/boot.c
> @@ -178,6 +178,59 @@ static void default_write_secondary(ARMCPU *cpu,
>                       smpboot, fixupcontext);
>  }
>
> +void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
> +                                            const struct arm_boot_info *info,
> +                                            hwaddr mvbar_addr)
> +{
> +    int n;
> +    uint32_t mvbar_blob[] = {
> +        /* mvbar_addr: secure monitor vectors
> +         * Default unimplemented and unused vectors to spin. Makes it
> +         * easier to debug (as opposed to the CPU running away).
> +         */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xE1B0F00E, /* movs pc, lr ;SMC exception return */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */
> +        0xEAFFFFFE, /* (spin) */

The code currently in arm_boot uses lower case for hex constants so we
should preserve convention.

> +    };
> +    uint32_t board_setup_blob[] = {
> +        /* board setup addr */
> +        0xE3A00E00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */
> +        0xEE0C0F30, /* mcr     p15, 0, r0, c12, c0, 1 ;set MVBAR */
> +        0xEE110F11, /* mrc     p15, 0, r0, c1 , c1, 0 ;read SCR */
> +        0xE3800031, /* orr     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                     ;call monitor to flush SCR */
> +        0xE1A0F001, /* mov     pc, r1                 ;return */
> +    };
> +
> +    /* check that mvbar_addr is correctly aligned and relocatable (using MOV) */
> +    assert((mvbar_addr & 0x1f) == 0 && (mvbar_addr >> 4) < 0x100);
> +
> +    /* check that these blobs don't overlap */
> +    assert((mvbar_addr + sizeof(mvbar_blob) <= info->board_setup_addr)
> +          || (info->board_setup_addr + sizeof(board_setup_blob) <= mvbar_addr));
> +
> +    for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) {
> +        mvbar_blob[n] = tswap32(mvbar_blob[n]);
> +    }
> +    rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob),
> +                       mvbar_addr);
> +
> +    for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
> +        board_setup_blob[n] = tswap32(board_setup_blob[n]);
> +    }
> +    rom_add_blob_fixed("board-setup", board_setup_blob,
> +                       sizeof(board_setup_blob), info->board_setup_addr);
> +}
> +
> +
> +

2 extra blanks not needed.

>  static void default_reset_secondary(ARMCPU *cpu,
>                                      const struct arm_boot_info *info)
>  {
> diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
> index cb9926e..e5105fb 100644
> --- a/hw/arm/highbank.c
> +++ b/hw/arm/highbank.c
> @@ -34,49 +34,16 @@
>  #define MPCORE_PERIPHBASE       0xfff10000
>
>  #define MVBAR_ADDR              0x200
> +#define BOARD_SETUP_ADDR        (MVBAR_ADDR + 8 * sizeof(uint32_t))
>
>  #define NIRQ_GIC                160
>
>  /* Board init.  */
>
> -/* MVBAR_ADDR is limited by precision of movw */
> -
> -QEMU_BUILD_BUG_ON(MVBAR_ADDR >= (1 << 16));
> -
> -#define ARMV7_IMM16(x) (extract32((x),  0, 12) | \
> -                        extract32((x), 12,  4) << 16)
> -
>  static void hb_write_board_setup(ARMCPU *cpu,
>                                   const struct arm_boot_info *info)
>  {
> -    int n;
> -    uint32_t board_setup_blob[] = {
> -        /* MVBAR_ADDR */
> -        /* Default unimplemented and unused vectors to spin. Makes it
> -         * easier to debug (as opposed to the CPU running away).
> -         */
> -        0xeafffffe, /* notused1: b notused */
> -        0xeafffffe, /* notused2: b notused */
> -        0xe1b0f00e, /* smc: movs pc, lr - exception return */
> -        0xeafffffe, /* prefetch_abort: b prefetch_abort */
> -        0xeafffffe, /* data_abort: b data_abort */
> -        0xeafffffe, /* notused3: b notused3 */
> -        0xeafffffe, /* irq: b irq */
> -        0xeafffffe, /* fiq: b fiq */
> -#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t))
> -        0xe3000000 + ARMV7_IMM16(MVBAR_ADDR), /* movw r0, MVBAR_ADDR */
> -        0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 - set MVBAR */
> -        0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 - get SCR */
> -        0xe3810001, /* orr r0, #1 - set NS */
> -        0xee010f11, /* mcr p15, 0, r0, c1 , c1, 0 - set SCR */
> -        0xe1600070, /* smc - go to monitor mode to flush NS change */
> -        0xe12fff1e, /* bx lr - return to caller */
> -    };
> -    for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
> -        board_setup_blob[n] = tswap32(board_setup_blob[n]);
> -    }
> -    rom_add_blob_fixed("board-setup", board_setup_blob,
> -                       sizeof(board_setup_blob), MVBAR_ADDR);
> +    arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
>  }
>
>  static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
> diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
> index c26b0e3..75bfe26 100644
> --- a/include/hw/arm/arm.h
> +++ b/include/hw/arm/arm.h
> @@ -126,4 +126,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
>     ticks.  */
>  extern int system_clock_scale;
>

system_clock_scale doesn't have much to do with boot but splits two
boot-related defs, so I would insert you new def after
arm_load_kernel.

otherwise:

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Regards,
Peter

> +/* Write a secure board setup routine with a dummy handler for SMCs */
> +void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
> +                                            const struct arm_boot_info *info,
> +                                            hwaddr mvbar_addr);
> +
>  #endif /* !ARM_MISC_H */
> --
> 2.5.3
>

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

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
       [not found] ` <1452902337-13844-9-git-send-email-Andrew.Baumann@microsoft.com>
@ 2016-01-29  7:31   ` Peter Crosthwaite
  2016-01-29 21:50     ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29  7:31 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
>
> Notes:
>     Pi1 requires more peripherals, and will be added in a later patch
>     series.
>
>     v4:
>     * drop header comment from versatile
>     * made smpboot and board setup blobs relocatable (within limits:
>       we can't use ARMv7 MOVW for Pi1, so it's messier than highbank)
>     * move board setup blob to common code
>     * modify SCR using read-or-write
>     * s/RaspiMachineState/RaspiState/
>     * style tweaks
>
>     v3:
>      * fix board setup to remain Pi1 compatible
>      * pass ram property
>
>  hw/arm/Makefile.objs |   2 +-
>  hw/arm/raspi.c       | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 157 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..2110725
> --- /dev/null
> +++ b/hw/arm/raspi.c
> @@ -0,0 +1,156 @@
> +/*
> + * 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.
> + */
> +
> +#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 RaspiState {

A quick google search, I see the camel case form for rpi is usually
"RasPi". Should we follow?

> +    union {

union not needed.

> +        BCM2836State pi2;
> +    } soc;
> +    MemoryRegion ram;
> +} RaspiState;
> +
> +static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
> +{
> +    static const uint32_t smpboot[] = {
> +        0xE1A0E00F, /*    mov     lr, pc */
> +        0xE3A0FE00 + (BOARDSETUP_ADDR >> 4), /* mov pc, 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) */

lower case hex for consistency with other blobbing boards (exynos,
zynq, arm_boot).

> +    };
> +

> +    /* check that we don't overrun board setup vectors */
> +    assert(SMPBOOT_ADDR + sizeof(smpboot) <= MVBAR_ADDR);
> +    /* check that board setup address is correctly relocated */
> +    assert((BOARDSETUP_ADDR & 0xf) == 0 && (BOARDSETUP_ADDR >> 4) < 0x100);

QEMU_BUILD_BUG_ON (both asserts should be convertible)

> +
> +    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)
> +{
> +    arm_write_secure_board_setup_dummy_smc(cpu, info, 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) {

Others on the qemu-arm list follow UEFI support better than I so Peter
or someone else should take a look at this section I think.

> +        /* 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 */

This comment doesn't add too much. I think it can be dropped
(everything in a binfo is to make arm_load_kernel DTRT).

> +        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)
> +{
> +    RaspiState *s = g_new0(RaspiState, 1);
> +
> +    /* Initialise the SOC */

Drop comment.

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

/* FIXME: Remove when we have custom CPU address space support */

> +    memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);
> +
> +    /* Setup the SOC */
> +    object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
> +                                   &error_abort);
> +    object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
> +                            &error_abort);
> +    object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
> +
> +    /* Prepare to boot */

Comment still doesn't add much so should drop.

Otherwise:

Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>

Thanks for your continued persistence and sorry about the recent
delays through review process.

Regards,
Peter

> +    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	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
  2016-01-29  7:31   ` [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine Peter Crosthwaite
@ 2016-01-29 21:50     ` Andrew Baumann
  2016-01-29 22:22       ` Peter Crosthwaite
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-29 21:50 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

Hi Peter,

Thanks for all the reviews. I should have a respun version on the list shortly. There's one minor change to this last patch:

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Thursday, 28 January 2016 23:31
> > On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann <Andrew.Baumann@microsoft.com> wrote:
 [...]
> > +typedef struct RaspiState {
> 
> A quick google search, I see the camel case form for rpi is usually
> "RasPi". Should we follow?

Ok.

> > +    union {
> 
> union not needed.

I know it's not needed now, but it will be as soon as we add pi1, which I hope to address in the next patch series. It will make that diff cleaner if we keep this here now, so I'm going to leave it as-is. I hope that's ok with you.

Thanks,
Andrew

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

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
  2016-01-29 21:50     ` Andrew Baumann
@ 2016-01-29 22:22       ` Peter Crosthwaite
  2016-01-29 22:28         ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29 22:22 UTC (permalink / raw)
  To: Andrew Baumann
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

On Fri, Jan 29, 2016 at 1:50 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> Hi Peter,
>
> Thanks for all the reviews. I should have a respun version on the list shortly. There's one minor change to this last patch:
>
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Thursday, 28 January 2016 23:31
>> > On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann <Andrew.Baumann@microsoft.com> wrote:
>  [...]
>> > +typedef struct RaspiState {
>>
>> A quick google search, I see the camel case form for rpi is usually
>> "RasPi". Should we follow?
>
> Ok.
>
>> > +    union {
>>
>> union not needed.
>
> I know it's not needed now, but it will be as soon as we add pi1, which I hope to address in the next patch series. It will make that diff cleaner if we keep this here now, so I'm going to leave it as-is. I hope that's ok with you.
>

It sounds like you are implementing an inheritance outside QOM. I'm
not sure about this, can we just drop the union and figure it out on
the next series?

Regards,
Peter

> Thanks,
> Andrew

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

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
  2016-01-29 22:22       ` Peter Crosthwaite
@ 2016-01-29 22:28         ` Andrew Baumann
  2016-01-29 22:40           ` Peter Crosthwaite
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Baumann @ 2016-01-29 22:28 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Friday, 29 January 2016 14:23
> 
> On Fri, Jan 29, 2016 at 1:50 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> > Hi Peter,
> >
> > Thanks for all the reviews. I should have a respun version on the list shortly.
> There's one minor change to this last patch:
> >
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Thursday, 28 January 2016 23:31
> >> > On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >  [...]
> >> > +typedef struct RaspiState {
> >>
> >> A quick google search, I see the camel case form for rpi is usually
> >> "RasPi". Should we follow?
> >
> > Ok.
> >
> >> > +    union {
> >>
> >> union not needed.
> >
> > I know it's not needed now, but it will be as soon as we add pi1, which I
> hope to address in the next patch series. It will make that diff cleaner if we
> keep this here now, so I'm going to leave it as-is. I hope that's ok with you.
> >
> 
> It sounds like you are implementing an inheritance outside QOM. I'm
> not sure about this, can we just drop the union and figure it out on
> the next series?

It's nothing nearly that clever/complicated. See https://github.com/0xabu/qemu/blob/raspi/hw/arm/raspi.c#L116

    switch (version) {
    case 1:
        object_initialize(&s->soc.pi1, sizeof(s->soc.pi1), TYPE_BCM2835);
        break;
    case 2:
        object_initialize(&s->soc.pi2, sizeof(s->soc.pi2), TYPE_BCM2836);
        break;
    }

And then later, we always refer simply to OBJECT(&s->soc). I suppose I could use a generic Object pointer instead, and allocate the soc-specific type elsewhere, but it seemed simpler with the union.

Andrew

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

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
  2016-01-29 22:28         ` Andrew Baumann
@ 2016-01-29 22:40           ` Peter Crosthwaite
  2016-01-29 22:43             ` Andrew Baumann
  0 siblings, 1 reply; 25+ messages in thread
From: Peter Crosthwaite @ 2016-01-29 22:40 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, Rob Herring

On Fri, Jan 29, 2016 at 2:28 PM, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> Sent: Friday, 29 January 2016 14:23
>>
>> On Fri, Jan 29, 2016 at 1:50 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> > Hi Peter,
>> >
>> > Thanks for all the reviews. I should have a respun version on the list shortly.
>> There's one minor change to this last patch:
>> >
>> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
>> >> Sent: Thursday, 28 January 2016 23:31
>> >> > On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
>> <Andrew.Baumann@microsoft.com> wrote:
>> >  [...]
>> >> > +typedef struct RaspiState {
>> >>
>> >> A quick google search, I see the camel case form for rpi is usually
>> >> "RasPi". Should we follow?
>> >
>> > Ok.
>> >
>> >> > +    union {
>> >>
>> >> union not needed.
>> >
>> > I know it's not needed now, but it will be as soon as we add pi1, which I
>> hope to address in the next patch series. It will make that diff cleaner if we
>> keep this here now, so I'm going to leave it as-is. I hope that's ok with you.
>> >
>>
>> It sounds like you are implementing an inheritance outside QOM. I'm
>> not sure about this, can we just drop the union and figure it out on
>> the next series?
>
> It's nothing nearly that clever/complicated. See https://github.com/0xabu/qemu/blob/raspi/hw/arm/raspi.c#L116
>
>     switch (version) {
>     case 1:
>         object_initialize(&s->soc.pi1, sizeof(s->soc.pi1), TYPE_BCM2835);
>         break;
>     case 2:
>         object_initialize(&s->soc.pi2, sizeof(s->soc.pi2), TYPE_BCM2836);
>         break;
>     }
>
> And then later, we always refer simply to OBJECT(&s->soc). I suppose I could use a generic Object pointer instead, and allocate the soc-specific type elsewhere, but it seemed simpler with the union.
>

But this is effectively an upcast to an abstract type, here:

+
+    /* Setup the SOC */
+    object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
+                                   &error_abort);
+    object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
+                            &error_abort);

Where that concrete type musts implement "ram" and "enabled-cpus". So
I am unsure of having a split implementation of "ram", "enabled-cpus"
etc from one SoC to the other as you are using a QOM property name as
an abstract interface definition.

Regards,
Peter

> Andrew

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

* Re: [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine
  2016-01-29 22:40           ` Peter Crosthwaite
@ 2016-01-29 22:43             ` Andrew Baumann
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Baumann @ 2016-01-29 22:43 UTC (permalink / raw)
  To: Peter Crosthwaite, Andreas Färber
  Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
	Peter Crosthwaite, qemu-devel@nongnu.org Developers, qemu-arm,
	Paolo Bonzini, Rob Herring

> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> Sent: Friday, 29 January 2016 14:41
> 
> On Fri, Jan 29, 2016 at 2:28 PM, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> Sent: Friday, 29 January 2016 14:23
> >>
> >> On Fri, Jan 29, 2016 at 1:50 PM, Andrew Baumann
> >> <Andrew.Baumann@microsoft.com> wrote:
> >> > Hi Peter,
> >> >
> >> > Thanks for all the reviews. I should have a respun version on the list
> shortly.
> >> There's one minor change to this last patch:
> >> >
> >> >> From: Peter Crosthwaite [mailto:crosthwaitepeter@gmail.com]
> >> >> Sent: Thursday, 28 January 2016 23:31
> >> >> > On Fri, Jan 15, 2016 at 3:58 PM, Andrew Baumann
> >> <Andrew.Baumann@microsoft.com> wrote:
> >> >  [...]
> >> >> > +typedef struct RaspiState {
> >> >>
> >> >> A quick google search, I see the camel case form for rpi is usually
> >> >> "RasPi". Should we follow?
> >> >
> >> > Ok.
> >> >
> >> >> > +    union {
> >> >>
> >> >> union not needed.
> >> >
> >> > I know it's not needed now, but it will be as soon as we add pi1, which I
> >> hope to address in the next patch series. It will make that diff cleaner if
> we
> >> keep this here now, so I'm going to leave it as-is. I hope that's ok with you.
> >> >
> >>
> >> It sounds like you are implementing an inheritance outside QOM. I'm
> >> not sure about this, can we just drop the union and figure it out on
> >> the next series?
> >
> > It's nothing nearly that clever/complicated. See
> https://github.com/0xabu/qemu/blob/raspi/hw/arm/raspi.c#L116
> >
> >     switch (version) {
> >     case 1:
> >         object_initialize(&s->soc.pi1, sizeof(s->soc.pi1), TYPE_BCM2835);
> >         break;
> >     case 2:
> >         object_initialize(&s->soc.pi2, sizeof(s->soc.pi2), TYPE_BCM2836);
> >         break;
> >     }
> >
> > And then later, we always refer simply to OBJECT(&s->soc). I suppose I
> could use a generic Object pointer instead, and allocate the soc-specific type
> elsewhere, but it seemed simpler with the union.
> >
> 
> But this is effectively an upcast to an abstract type, here:
> 
> +
> +    /* Setup the SOC */
> +    object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s-
> >ram),
> +                                   &error_abort);
> +    object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
> +                            &error_abort);
> 
> Where that concrete type musts implement "ram" and "enabled-cpus". So
> I am unsure of having a split implementation of "ram", "enabled-cpus"
> etc from one SoC to the other as you are using a QOM property name as
> an abstract interface definition.

Ok, fair enough. Indeed, "enabled-cpus" is actually a bug there for pi1. I'll drop the union for now, and rework it for pi1.

Andrew

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

end of thread, other threads:[~2016-01-29 22:44 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-15 23:58 [Qemu-devel] [PATCH v4 0/8] Raspberry Pi 2 support Andrew Baumann
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 1/8] bcm2835_mbox: add BCM2835 mailboxes Andrew Baumann
2016-01-26  5:54   ` Peter Crosthwaite
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 2/8] bcm2835_property: add bcm2835 property channel Andrew Baumann
2016-01-26  6:03   ` Peter Crosthwaite
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 3/8] bcm2835_ic: add bcm2835 interrupt controller Andrew Baumann
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 4/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals Andrew Baumann
2016-01-26  6:14   ` Peter Crosthwaite
2016-01-26  6:23     ` Andrew Baumann
2016-01-26  8:03       ` Peter Crosthwaite
2016-01-26 19:12         ` Andrew Baumann
2016-01-26 19:40           ` Peter Maydell
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 5/8] bcm2836_control: add bcm2836 ARM control logic Andrew Baumann
2016-01-29  4:37   ` Peter Crosthwaite
2016-01-29  4:42     ` Andrew Baumann
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 6/8] bcm2836: add bcm2836 soc device Andrew Baumann
2016-01-29  4:50   ` Peter Crosthwaite
2016-01-15 23:58 ` [Qemu-devel] [PATCH v4 7/8] arm/boot: move highbank secure board setup code to common routine Andrew Baumann
2016-01-29  7:11   ` Peter Crosthwaite
     [not found] ` <1452902337-13844-9-git-send-email-Andrew.Baumann@microsoft.com>
2016-01-29  7:31   ` [Qemu-devel] [PATCH v4 8/8] raspi: add raspberry pi 2 machine Peter Crosthwaite
2016-01-29 21:50     ` Andrew Baumann
2016-01-29 22:22       ` Peter Crosthwaite
2016-01-29 22:28         ` Andrew Baumann
2016-01-29 22:40           ` Peter Crosthwaite
2016-01-29 22:43             ` 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.