Skip to contentSkip to conversation

Next Generation Xilinx Zynq SoC

PATCH Superseded Peter Crosthwaite 2 participants 23 messages May 6, 2015 – May 8, 2015 Arm/Zynq architecture

v7 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v7 cover Next Generation Xilinx Zynq SoC

Hi Peter and all,

Xilinx's next gen SoC has been announced. This series adds a SoC and board.

Series start with addition of ARM cortex A53 support (P1 and P2). The Soc skeleton is then added with GIC, EMACs and UARTs added. The pre-existing models for GEM and UART are not SoC friendly (no visible state struct), so those are refactored for SoC.

Create a model of the EP108 board. Currently this doesn't have any EP108 specific features but is a usable board exposing the user visible features of the raw SoC.

See individual patches for detailed change logs.

changed since v6 (Edgar review):
Added GIC region size macro
Added GIC alises

changed since v4:
Addressed PMM and Alistair Reviews

changed since v3:
Included CPU thread kick fix
Addressed Alistair review

changed since v2:
Fix CPU child prop adder
Add DTS compat string

changed since v1:
Addressed Alistair review (individual changes on resp. patches) Changed board name to EP108
Changed naming scheme to "zynqmp" / "ZYNQMP" (Michal review)

Regards,
Peter

Peter Crosthwaite (15):
target-arm: cpu64: generalise name of A57 regs
target-arm: cpu64: Add support for cortex-a53
arm: Introduce Xilinx ZynqMP SoC
intc: arm_gic: Macroify the MemoryRegion size
arm: xlnx-zynqmp: Add GIC
arm: xlnx-zynqmp: Connect CPU Timers to GIC
net: cadence_gem: Clean up variable names
net: cadence_gem: Split state struct and type into header
arm: xlnx-zynqmp: Add GEM support
char: cadence_uart: Clean up variable names
char: cadence_uart: Split state struct and type into header
arm: xlnx-zynqmp: Add UART support
arm: Add xlnx-ep108 machine
arm: xlnx-ep108: Add external RAM
arm: xlnx-ep108: Add bootloading

 default-configs/aarch64-softmmu.mak |   2 +-
 hw/arm/Makefile.objs                |   1 +
 hw/arm/xlnx-ep108.c                 |  82 ++++++++++++++
 hw/arm/xlnx-zynqmp.c                | 211 ++++++++++++++++++++++++++++++++++++
 hw/char/cadence_uart.c              | 115 ++++++++------------
 hw/intc/arm_gic.c                   |   2 +-
 hw/net/cadence_gem.c                |  95 +++++-----------
 include/hw/arm/xlnx-zynqmp.h        |  57 ++++++++++
 include/hw/char/cadence_uart.h      |  53 +++++++++
 include/hw/intc/arm_gic.h           |   2 +
 include/hw/net/cadence_gem.h        |  73 +++++++++++++
 target-arm/cpu64.c                  |  61 ++++++++++-
 12 files changed, 611 insertions(+), 143 deletions(-)
 create mode 100644 hw/arm/xlnx-ep108.c
 create mode 100644 hw/arm/xlnx-zynqmp.c
 create mode 100644 include/hw/arm/xlnx-zynqmp.h
 create mode 100644 include/hw/char/cadence_uart.h
 create mode 100644 include/hw/net/cadence_gem.h
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#1 lore raw

PATCH v7 1/15 target-arm: cpu64: generalise name of A57 regs

Rename some A57 CP register variables in preparation for support for Cortex A53. Use "a57_a53" to describe the shareable features. Some of the CP15 registers (such as ACTLR) are specific to implementation, but we currently just RAZ them so continue with that as the policy for both A57 and A53 processors under a shared definition.

---
changed since v4 (PMM review):
Use a57_a53 instead of axx
Drop initfn refactorings

 target-arm/cpu64.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
target-arm/cpu64.c +5 -5
index 270bc2f..13e042e 100644
@@ -38,22 +38,22 @@ static inline void unset_feature(CPUARMState *env, int feature)
 }
 
 #ifndef CONFIG_USER_ONLY
-static uint64_t a57_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     /* Number of processors is in [25:24]; otherwise we RAZ */
     return (smp_cpus - 1) << 24;
 }
 #endif
 
-static const ARMCPRegInfo cortexa57_cp_reginfo[] = {
+static const ARMCPRegInfo cortex_a57_a53_cp_reginfo[] = {
 #ifndef CONFIG_USER_ONLY
     { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2,
-      .access = PL1_RW, .readfn = a57_l2ctlr_read,
+      .access = PL1_RW, .readfn = a57_a53_l2ctlr_read,
       .writefn = arm_cp_write_ignore },
     { .name = "L2CTLR",
       .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2,
-      .access = PL1_RW, .readfn = a57_l2ctlr_read,
+      .access = PL1_RW, .readfn = a57_a53_l2ctlr_read,
       .writefn = arm_cp_write_ignore },
 #endif
     { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64,
@@ -140,7 +140,7 @@ static void aarch64_a57_initfn(Object *obj)
     cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
     cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
     cpu->dcz_blocksize = 4; /* 64 bytes */
-    define_arm_cp_regs(cpu, cortexa57_cp_reginfo);
+    define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
 }
 
 #ifdef CONFIG_USER_ONLY
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
Reviewed-by on v7 1/15
#2 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 01/15] target-arm: cpu64: generalise name of A57 regs

Quoted 8 lines · Peter Crosthwaite

Rename some A57 CP register variables in preparation for support for Cortex A53. Use "a57_a53" to describe the shareable features. Some of the CP15 registers (such as ACTLR) are specific to implementation, but we currently just RAZ them so continue with that as the policy for both A57 and A53 processors under a shared definition.

thanks
-- PMM

#3 lore raw

PATCH v7 2/15 target-arm: cpu64: Add support for cortex-a53

In reply to Peter Crosthwaite

Add the ARM cortex A53 processor definition. Similar to A57, but with different L1 I cache policy, phys addr size and different cache geometries. The cache sizes is implementation configurable, but use these values (from Xilinx Zynq MPSoC) as a default until cache size configurability is added.

---
Changed since v4:
Fix a53/a57 typo in commit message (Ozaki)
Use standalone init fn rather than a57-shared one (PMM). Changed since v2:
Added dtb compatible string

 target-arm/cpu64.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
target-arm/cpu64.c +51 -0
index 13e042e..bf7dd68 100644
@@ -143,6 +143,56 @@ static void aarch64_a57_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
 }
 
+static void aarch64_a53_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    cpu->dtb_compatible = "arm,cortex-a53";
+    set_feature(&cpu->env, ARM_FEATURE_V8);
+    set_feature(&cpu->env, ARM_FEATURE_VFP4);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
+    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
+    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
+    set_feature(&cpu->env, ARM_FEATURE_V8_AES);
+    set_feature(&cpu->env, ARM_FEATURE_V8_SHA1);
+    set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
+    set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
+    set_feature(&cpu->env, ARM_FEATURE_CRC);
+    cpu->midr = 0x410fd034;
+    cpu->reset_fpsid = 0x41034070;
+    cpu->mvfr0 = 0x10110222;
+    cpu->mvfr1 = 0x12111111;
+    cpu->mvfr2 = 0x00000043;
+    cpu->ctr = 0x84448004; /* L1Ip = VIPT */
+    cpu->reset_sctlr = 0x00c50838;
+    cpu->id_pfr0 = 0x00000131;
+    cpu->id_pfr1 = 0x00011011;
+    cpu->id_dfr0 = 0x03010066;
+    cpu->id_afr0 = 0x00000000;
+    cpu->id_mmfr0 = 0x10101105;
+    cpu->id_mmfr1 = 0x40000000;
+    cpu->id_mmfr2 = 0x01260000;
+    cpu->id_mmfr3 = 0x02102211;
+    cpu->id_isar0 = 0x02101110;
+    cpu->id_isar1 = 0x13112111;
+    cpu->id_isar2 = 0x21232042;
+    cpu->id_isar3 = 0x01112131;
+    cpu->id_isar4 = 0x00011142;
+    cpu->id_isar5 = 0x00011121;
+    cpu->id_aa64pfr0 = 0x00002222;
+    cpu->id_aa64dfr0 = 0x10305106;
+    cpu->id_aa64isar0 = 0x00011120;
+    cpu->id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */
+    cpu->dbgdidr = 0x3516d000;
+    cpu->clidr = 0x0a200023;
+    cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
+    cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
+    cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
+    cpu->dcz_blocksize = 4; /* 64 bytes */
+    define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
+}
+
 #ifdef CONFIG_USER_ONLY
 static void aarch64_any_initfn(Object *obj)
 {
@@ -170,6 +220,7 @@ typedef struct ARMCPUInfo {
 
 static const ARMCPUInfo aarch64_cpus[] = {
     { .name = "cortex-a57",         .initfn = aarch64_a57_initfn },
+    { .name = "cortex-a53",         .initfn = aarch64_a53_initfn },
 #ifdef CONFIG_USER_ONLY
     { .name = "any",         .initfn = aarch64_any_initfn },
 #endif
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
Reviewed-by on v7 2/15
#4 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 02/15] target-arm: cpu64: Add support for cortex-a53

Quoted 9 lines · Peter Crosthwaite

Add the ARM cortex A53 processor definition. Similar to A57, but with different L1 I cache policy, phys addr size and different cache geometries. The cache sizes is implementation configurable, but use these values (from Xilinx Zynq MPSoC) as a default until cache size configurability is added.

---

It would be nice if you could get the CPU name right in the commit message: it's "Cortex-A53" (caps, hyphen).

thanks
-- PMM

#5 lore raw

PATCH v7 3/15 arm: Introduce Xilinx ZynqMP SoC

In reply to Peter Crosthwaite

With quad Cortex-A53 CPUs.

Use SMC PSCI, with the standard policy of secondaries starting in power-off.

---
changed since v4 (PMM review):
Squashed in PSCI stuffs.
Add (c) info to new header
Remove extraneous trailing __ from header guard define remove ERR_PROP_CHECK_RETURN
changed since v2:
Added [*] to cpu child property name.
changed since v1:
Add &error_abort to CPU child adder call.

 default-configs/aarch64-softmmu.mak |  2 +-
 hw/arm/Makefile.objs                |  1 +
 hw/arm/xlnx-zynqmp.c                | 76 +++++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h        | 38 +++++++++++++++++++
 4 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/xlnx-zynqmp.c
 create mode 100644 include/hw/arm/xlnx-zynqmp.h
default-configs/aarch64-softmmu.mak +1 -1
index 6d3b5c7..96dd994 100644
@@ -3,4 +3,4 @@
 # We support all the 32 bit boards so need all their config
 include arm-softmmu.mak
 
-# Currently no 64-bit specific config requirements
+CONFIG_XLNX_ZYNQMP=y
hw/arm/Makefile.objs +1 -0
index 2577f68..d7cd5f4 100644
@@ -10,3 +10,4 @@ obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
+obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o
hw/arm/xlnx-zynqmp.c new file +76 -0

76 lines not on this page · raw message

include/hw/arm/xlnx-zynqmp.h new file +38 -0
new file mode 100644
index 0000000..62f6b6f
@@ -0,0 +1,38 @@
+/*
+ * Xilinx Zynq MPSoC emulation
+ *
+ * Copyright (C) 2015 Xilinx Inc
+ * Written by Peter Crosthwaite <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef XLNX_ZYNQMP_H
+
+#include "qemu-common.h"
+#include "hw/arm/arm.h"
+
+#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
+#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
+                                       TYPE_XLNX_ZYNQMP)
+
+#define XLNX_ZYNQMP_NUM_CPUS 4
+
+typedef struct XlnxZynqMPState {
+    /*< private >*/
+    DeviceState parent_obj;
+
+    /*< public >*/
+    ARMCPU cpu[XLNX_ZYNQMP_NUM_CPUS];
+}  XlnxZynqMPState;
+
+#define XLNX_ZYNQMP_H
+#endif
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#6 lore raw

PATCH v7 4/15 intc: arm_gic: Macroify the MemoryRegion size

In reply to Peter Crosthwaite

GIC generally uses a 4k memory region for the various subregions, such as GICC, GICD, GICV and GICH. Macroify this number in the publicly visible header.

Some machine model code may need to know the individual subregion size to implement special addresses mappings (such as aliases and under-decoding logic).

---
 hw/intc/arm_gic.c         | 2 +-
 include/hw/intc/arm_gic.h | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)
hw/intc/arm_gic.c +1 -1
index a04c822..694b424 100644
@@ -791,7 +791,7 @@ void gic_init_irqs_and_distributor(GICState *s)
         sysbus_init_irq(sbd, &s->parent_irq[i]);
     }
     memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
-                          "gic_dist", 0x1000);
+                          "gic_dist", ARM_GIC_REGION_SIZE);
 }
 
 static void arm_gic_realize(DeviceState *dev, Error **errp)
include/hw/intc/arm_gic.h +2 -0
index 0971e37..659be27 100644
@@ -31,6 +31,8 @@
 #define ARM_GIC_GET_CLASS(obj) \
      OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
 
+#define ARM_GIC_REGION_SIZE   0x1000
+
 typedef struct ARMGICClass {
     /*< private >*/
     ARMGICCommonClass parent_class;
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#7 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 04/15] intc: arm_gic: Macroify the MemoryRegion size

Quoted 5 lines · Peter Crosthwaite

GIC generally uses a 4k memory region for the various subregions, such as GICC, GICD, GICV and GICH. Macroify this number in the publicly visible header.

+#define ARM_GIC_REGION_SIZE 0x1000

I don't think it makes sense to have a single constant for this. In GICv2, the GICD distributor region is 4K, but the GICC CPU region is 8K. We don't currently actually implement the register in the second page (GICC_DIR), but exporting a constant that's the wrong size doesn't seem right (especially if it means the board model will end up repeating the GICC pages at the wrong points!).

In GICv1, on the other hand, the GICC region was 4K, so we can't just have a single #define for GICC size either.

-- PMM

#8 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 04/15] intc: arm_gic: Macroify the MemoryRegion size

Quoted 15 lines · Peter Maydell
Quoted 5 lines · Peter Crosthwaite

GIC generally uses a 4k memory region for the various subregions, such as GICC, GICD, GICV and GICH. Macroify this number in the publicly visible header.

+#define ARM_GIC_REGION_SIZE 0x1000

I don't think it makes sense to have a single constant for this. In GICv2, the GICD distributor region is 4K, but the GICC CPU region is 8K. We don't currently actually implement the register in the second page (GICC_DIR), but exporting a constant that's the wrong size doesn't seem right (especially if it means the board model will end up repeating the GICC pages at the wrong points!).

Quoted 3 lines

In GICv1, on the other hand, the GICC region was 4K, so we can't just have a single #define for GICC size either.

Ok patch dropped.

Regards,
Peter

Quoted 2 lines

-- PMM

#9 lore raw

PATCH v7 5/15 arm: xlnx-zynqmp: Add GIC

In reply to Peter Crosthwaite

Add the GIC and connect IRQ outputs to the CPUs. The GIC regions are under-decoded through a 64k address region so implement aliases accordingly.

---
changed since v6:
Added aliases.
changed since v5:
Make commit msg body standalone
Add reset-cbar configuration

 hw/arm/xlnx-zynqmp.c         | 59 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h | 13 ++++++++++
 2 files changed, 72 insertions(+)
hw/arm/xlnx-zynqmp.c +59 -0
index ec0ebaa..931cd5a 100644
@@ -16,6 +16,23 @@
  */
 
 #include "hw/arm/xlnx-zynqmp.h"
+#include "exec/address-spaces.h"
+
+#define GIC_NUM_SPI_INTR 128
+
+#define GIC_BASE_ADDR       0xf9000000
+#define GIC_DIST_ADDR       0xf9010000
+#define GIC_CPU_ADDR        0xf9020000
+
+typedef struct XlnxZynqMPGICRegion {
+    int region_index;
+    uint32_t address;
+} XlnxZynqMPGICRegion;
+
+static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions [] = {
+    { .region_index = 0, .address = GIC_DIST_ADDR, },
+    { .region_index = 1, .address = GIC_CPU_ADDR,  },
+};
 
 static void xlnx_zynqmp_init(Object *obj)
 {
@@ -28,14 +45,46 @@ static void xlnx_zynqmp_init(Object *obj)
         object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
                                   &error_abort);
     }
+
+    object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
+    qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 {
     XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
+    MemoryRegion *system_memory = get_system_memory();
     uint8_t i;
     Error *err = NULL;
 
+    qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
+    qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
+    qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_CPUS);
+    object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
+    if (err) {
+        error_propagate((errp), (err));
+        return;
+    }
+    assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
+    for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) {
+        SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic);
+        const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i];
+        MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index);
+        uint32_t addr = r->address;
+        int j;
+
+        sysbus_mmio_map(gic, r->region_index, addr);
+
+        for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) {
+            MemoryRegion *alias = &s->gic_mr[i][j];
+
+            addr += ARM_GIC_REGION_SIZE;
+            memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr,
+                                     0, ARM_GIC_REGION_SIZE);
+            memory_region_add_subregion(system_memory, addr, alias);
+        }
+    }
+
     for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) {
         object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC,
                                 "psci-conduit", &error_abort);
@@ -45,11 +94,21 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
                                      "start-powered-off", &error_abort);
         }
 
+        object_property_set_int(OBJECT(&s->cpu[i]), GIC_BASE_ADDR,
+                                "reset-cbar", &err);
+        if (err) {
+            error_propagate((errp), (err));
+            return;
+        }
+
         object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
         if (err) {
             error_propagate((errp), (err));
             return;
         }
+
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
+                           qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
     }
 }
 
include/hw/arm/xlnx-zynqmp.h +13 -0
index 62f6b6f..9d40e9f 100644
@@ -19,6 +19,7 @@
 
 #include "qemu-common.h"
 #include "hw/arm/arm.h"
+#include "hw/intc/arm_gic.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@@ -26,12 +27,24 @@
 
 #define XLNX_ZYNQMP_NUM_CPUS 4
 
+#define XLNX_ZYNQMP_GIC_REGIONS 2
+
+/* ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
+ * and under-decodes the 64k region. This mirrors the 4k regions to every 4k
+ * aligned address in the 64k region. To implement each GIC region needs a
+ * number of memory region aliases.
+ */
+
+#define XLNX_ZYNQMP_GIC_ALIASES (0x10000 / ARM_GIC_REGION_SIZE - 1)
+
 typedef struct XlnxZynqMPState {
     /*< private >*/
     DeviceState parent_obj;
 
     /*< public >*/
     ARMCPU cpu[XLNX_ZYNQMP_NUM_CPUS];
+    GICState gic;
+    MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
 }  XlnxZynqMPState;
 
 #define XLNX_ZYNQMP_H
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#10 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 05/15] arm: xlnx-zynqmp: Add GIC

Quoted 8 lines · Peter Crosthwaite

Add the GIC and connect IRQ outputs to the CPUs. The GIC regions are under-decoded through a 64k address region so implement aliases accordingly.

hw/arm/xlnx-zynqmp.c +4 -0
+    assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
+    for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) {
+        SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic);
+        const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i];

hw/arm/xlnx-zynqmp.c static void xlnx_zynqmp_init(Object *obj) · line 81

Quoted 10 lines
hw/arm/xlnx-zynqmp.c +10 -0
+        MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index);
+        uint32_t addr = r->address;
+        int j;
+
+        sysbus_mmio_map(gic, r->region_index, addr);
+
+        for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) {
+            MemoryRegion *alias = &s->gic_mr[i][j];
+
+            addr += ARM_GIC_REGION_SIZE;

Since the frequency at which the GICC region repeats in the memory map is actually board dependent, you could just use a board specific constant here.

hw/arm/xlnx-zynqmp.c static void xlnx_zynqmp_init(Object *obj) · line 83

Quoted 2 lines
hw/arm/xlnx-zynqmp.c +2 -0
+            memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr,
+                                     0, ARM_GIC_REGION_SIZE);

...and here you could use memory_region_size(mr), I suppose, or just the board-specific value again.

-- PMM

#11 lore raw

Re: [Qemu-devel] [PATCH target-arm v7 05/15] arm: xlnx-zynqmp: Add GIC

Quoted 24 lines · Peter Maydell
Quoted 8 lines · Peter Crosthwaite

Add the GIC and connect IRQ outputs to the CPUs. The GIC regions are under-decoded through a 64k address region so implement aliases accordingly.

hw/arm/xlnx-zynqmp.c +4 -0
+    assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
+    for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) {
+        SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic);
+        const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i];

hw/arm/xlnx-zynqmp.c static void xlnx_zynqmp_init(Object *obj) · line 81

Quoted 10 lines
hw/arm/xlnx-zynqmp.c +10 -0
+        MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index);
+        uint32_t addr = r->address;
+        int j;
+
+        sysbus_mmio_map(gic, r->region_index, addr);
+
+        for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) {
+            MemoryRegion *alias = &s->gic_mr[i][j];
+
+            addr += ARM_GIC_REGION_SIZE;

Since the frequency at which the GICC region repeats in the memory map is actually board dependent, you could just use a board specific constant here.

Quoted 6 lines

hw/arm/xlnx-zynqmp.c static void xlnx_zynqmp_init(Object *obj) · line 83

Quoted 2 lines
hw/arm/xlnx-zynqmp.c +2 -0
+            memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr,
+                                     0, ARM_GIC_REGION_SIZE);

...and here you could use memory_region_size(mr), I suppose, or just the board-specific value again.

Used board-specific define in both instances (as well as the one in the header).

Regards,
Peter

Quoted 2 lines

-- PMM

#12 lore raw

PATCH v7 6/15 arm: xlnx-zynqmp: Connect CPU Timers to GIC

In reply to Peter Crosthwaite

Connect the GPIO outputs from the individual CPUs for the timers to the GIC.

---
changed since v4:
Use macro for GIC_INTERNAL

 hw/arm/xlnx-zynqmp.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
hw/arm/xlnx-zynqmp.c +17 -0
index 931cd5a..12a8c77 100644
@@ -16,10 +16,14 @@
  */
 
 #include "hw/arm/xlnx-zynqmp.h"
+#include "hw/intc/arm_gic_common.h"
 #include "exec/address-spaces.h"
 
 #define GIC_NUM_SPI_INTR 128
 
+#define ARM_PHYS_TIMER_PPI  30
+#define ARM_VIRT_TIMER_PPI  27
+
 #define GIC_BASE_ADDR       0xf9000000
 #define GIC_DIST_ADDR       0xf9010000
 #define GIC_CPU_ADDR        0xf9020000
@@ -34,6 +38,11 @@ static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions [] = {
     { .region_index = 1, .address = GIC_CPU_ADDR,  },
 };
 
+static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
+{
+    return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index;
+}
+
 static void xlnx_zynqmp_init(Object *obj)
 {
     XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
@@ -86,6 +95,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
     }
 
     for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) {
+        qemu_irq irq;
+
         object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC,
                                 "psci-conduit", &error_abort);
         if (i > 0) {
@@ -109,6 +120,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 
         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
                            qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
+        irq = qdev_get_gpio_in(DEVICE(&s->gic),
+                               arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI));
+        qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 0, irq);
+        irq = qdev_get_gpio_in(DEVICE(&s->gic),
+                               arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
+        qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 1, irq);
     }
 }
 
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#13 lore raw

PATCH v7 7/15 net: cadence_gem: Clean up variable names

In reply to Peter Crosthwaite

Cleanup some variable names in preparation for migrating the state struct and type cast macro to a public header. The acronym "GEM" on its own is not specific enough to be used in a more global namespace so preface with "cadence". Fix the capitalisation of "gem" in the state type while touching the typename. Also preface the GEM_MAXREG macro as this will need to migrate to public header.

---
changed since v5:
Make commit message body standalone

 hw/net/cadence_gem.c | 70 ++++++++++++++++++++++++++--------------------------
 1 file changed, 35 insertions(+), 35 deletions(-)
hw/net/cadence_gem.c +35 -35
index 55b6293..5994306 100644
@@ -141,7 +141,7 @@
 #define GEM_DESCONF6      (0x00000294/4)
 #define GEM_DESCONF7      (0x00000298/4)
 
-#define GEM_MAXREG        (0x00000640/4) /* Last valid GEM address */
+#define CADENCE_GEM_MAXREG        (0x00000640/4) /* Last valid GEM address */
 
 /*****************************************/
 #define GEM_NWCTRL_TXSTART     0x00000200 /* Transmit Enable */
@@ -350,9 +350,9 @@ static inline void rx_desc_set_sar(unsigned *desc, int sar_idx)
 }
 
 #define TYPE_CADENCE_GEM "cadence_gem"
-#define GEM(obj) OBJECT_CHECK(GemState, (obj), TYPE_CADENCE_GEM)
+#define CADENCE_GEM(obj) OBJECT_CHECK(CadenceGEMState, (obj), TYPE_CADENCE_GEM)
 
-typedef struct GemState {
+typedef struct CadenceGEMState {
     SysBusDevice parent_obj;
 
     MemoryRegion iomem;
@@ -361,15 +361,15 @@ typedef struct GemState {
     qemu_irq irq;
 
     /* GEM registers backing store */
-    uint32_t regs[GEM_MAXREG];
+    uint32_t regs[CADENCE_GEM_MAXREG];
     /* Mask of register bits which are write only */
-    uint32_t regs_wo[GEM_MAXREG];
+    uint32_t regs_wo[CADENCE_GEM_MAXREG];
     /* Mask of register bits which are read only */
-    uint32_t regs_ro[GEM_MAXREG];
+    uint32_t regs_ro[CADENCE_GEM_MAXREG];
     /* Mask of register bits which are clear on read */
-    uint32_t regs_rtc[GEM_MAXREG];
+    uint32_t regs_rtc[CADENCE_GEM_MAXREG];
     /* Mask of register bits which are write 1 to clear */
-    uint32_t regs_w1c[GEM_MAXREG];
+    uint32_t regs_w1c[CADENCE_GEM_MAXREG];
 
     /* PHY registers backing store */
     uint16_t phy_regs[32];
@@ -385,7 +385,7 @@ typedef struct GemState {
     unsigned rx_desc[2];
 
     bool sar_active[4];
-} GemState;
+} CadenceGEMState;
 
 /* The broadcast MAC address: 0xFFFFFFFFFFFF */
 static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -395,7 +395,7 @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  * One time initialization.
  * Set masks to identify which register bits have magical clear properties
  */
-static void gem_init_register_masks(GemState *s)
+static void gem_init_register_masks(CadenceGEMState *s)
 {
     /* Mask of register bits which are read only */
     memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
@@ -430,7 +430,7 @@ static void gem_init_register_masks(GemState *s)
  * phy_update_link:
  * Make the emulated PHY link state match the QEMU "interface" state.
  */
-static void phy_update_link(GemState *s)
+static void phy_update_link(CadenceGEMState *s)
 {
     DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down);
 
@@ -450,7 +450,7 @@ static void phy_update_link(GemState *s)
 
 static int gem_can_receive(NetClientState *nc)
 {
-    GemState *s;
+    CadenceGEMState *s;
 
     s = qemu_get_nic_opaque(nc);
 
@@ -483,7 +483,7 @@ static int gem_can_receive(NetClientState *nc)
  * gem_update_int_status:
  * Raise or lower interrupt based on current status.
  */
-static void gem_update_int_status(GemState *s)
+static void gem_update_int_status(CadenceGEMState *s)
 {
     if (s->regs[GEM_ISR]) {
         DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
@@ -495,7 +495,7 @@ static void gem_update_int_status(GemState *s)
  * gem_receive_updatestats:
  * Increment receive statistics.
  */
-static void gem_receive_updatestats(GemState *s, const uint8_t *packet,
+static void gem_receive_updatestats(CadenceGEMState *s, const uint8_t *packet,
                                     unsigned bytes)
 {
     uint64_t octets;
@@ -586,7 +586,7 @@ static unsigned calc_mac_hash(const uint8_t *mac)
  * GEM_RM_PROMISCUOUS_ACCEPT, GEM_RX_BROADCAST_ACCEPT,
  * GEM_RX_MULTICAST_HASH_ACCEPT or GEM_RX_UNICAST_HASH_ACCEPT
  */
-static int gem_mac_address_filter(GemState *s, const uint8_t *packet)
+static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
 {
     uint8_t *gem_spaddr;
     int i;
@@ -636,7 +636,7 @@ static int gem_mac_address_filter(GemState *s, const uint8_t *packet)
     return GEM_RX_REJECT;
 }
 
-static void gem_get_rx_desc(GemState *s)
+static void gem_get_rx_desc(CadenceGEMState *s)
 {
     DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
     /* read current descriptor */
@@ -660,7 +660,7 @@ static void gem_get_rx_desc(GemState *s)
  */
 static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
 {
-    GemState *s;
+    CadenceGEMState *s;
     unsigned   rxbufsize, bytes_to_copy;
     unsigned   rxbuf_offset;
     uint8_t    rxbuf[2048];
@@ -810,7 +810,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
  * gem_transmit_updatestats:
  * Increment transmit statistics.
  */
-static void gem_transmit_updatestats(GemState *s, const uint8_t *packet,
+static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet,
                                      unsigned bytes)
 {
     uint64_t octets;
@@ -856,7 +856,7 @@ static void gem_transmit_updatestats(GemState *s, const uint8_t *packet,
  * gem_transmit:
  * Fish packets out of the descriptor ring and feed them to QEMU
  */
-static void gem_transmit(GemState *s)
+static void gem_transmit(CadenceGEMState *s)
 {
     unsigned    desc[2];
     hwaddr packet_desc_addr;
@@ -976,7 +976,7 @@ static void gem_transmit(GemState *s)
     }
 }
 
-static void gem_phy_reset(GemState *s)
+static void gem_phy_reset(CadenceGEMState *s)
 {
     memset(&s->phy_regs[0], 0, sizeof(s->phy_regs));
     s->phy_regs[PHY_REG_CONTROL] = 0x1140;
@@ -1004,7 +1004,7 @@ static void gem_phy_reset(GemState *s)
 static void gem_reset(DeviceState *d)
 {
     int i;
-    GemState *s = GEM(d);
+    CadenceGEMState *s = CADENCE_GEM(d);
 
     DB_PRINT("\n");
 
@@ -1032,13 +1032,13 @@ static void gem_reset(DeviceState *d)
     gem_update_int_status(s);
 }
 
-static uint16_t gem_phy_read(GemState *s, unsigned reg_num)
+static uint16_t gem_phy_read(CadenceGEMState *s, unsigned reg_num)
 {
     DB_PRINT("reg: %d value: 0x%04x\n", reg_num, s->phy_regs[reg_num]);
     return s->phy_regs[reg_num];
 }
 
-static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val)
+static void gem_phy_write(CadenceGEMState *s, unsigned reg_num, uint16_t val)
 {
     DB_PRINT("reg: %d value: 0x%04x\n", reg_num, val);
 
@@ -1072,10 +1072,10 @@ static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val)
  */
 static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
 {
-    GemState *s;
+    CadenceGEMState *s;
     uint32_t retval;
 
-    s = (GemState *)opaque;
+    s = (CadenceGEMState *)opaque;
 
     offset >>= 2;
     retval = s->regs[offset];
@@ -1120,7 +1120,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
 static void gem_write(void *opaque, hwaddr offset, uint64_t val,
         unsigned size)
 {
-    GemState *s = (GemState *)opaque;
+    CadenceGEMState *s = (CadenceGEMState *)opaque;
     uint32_t readonly;
 
     DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
@@ -1226,7 +1226,7 @@ static NetClientInfo net_gem_info = {
 static int gem_init(SysBusDevice *sbd)
 {
     DeviceState *dev = DEVICE(sbd);
-    GemState *s = GEM(dev);
+    CadenceGEMState *s = CADENCE_GEM(dev);
 
     DB_PRINT("\n");
 
@@ -1248,18 +1248,18 @@ static const VMStateDescription vmstate_cadence_gem = {
     .version_id = 2,
     .minimum_version_id = 2,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG),
-        VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32),
-        VMSTATE_UINT8(phy_loop, GemState),
-        VMSTATE_UINT32(rx_desc_addr, GemState),
-        VMSTATE_UINT32(tx_desc_addr, GemState),
-        VMSTATE_BOOL_ARRAY(sar_active, GemState, 4),
+        VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG),
+        VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32),
+        VMSTATE_UINT8(phy_loop, CadenceGEMState),
+        VMSTATE_UINT32(rx_desc_addr, CadenceGEMState),
+        VMSTATE_UINT32(tx_desc_addr, CadenceGEMState),
+        VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4),
         VMSTATE_END_OF_LIST(),
     }
 };
 
 static Property gem_properties[] = {
-    DEFINE_NIC_PROPERTIES(GemState, conf),
+    DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -1277,7 +1277,7 @@ static void gem_class_init(ObjectClass *klass, void *data)
 static const TypeInfo gem_info = {
     .name  = TYPE_CADENCE_GEM,
     .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(GemState),
+    .instance_size  = sizeof(CadenceGEMState),
     .class_init = gem_class_init,
 };
 
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#14 lore raw

PATCH v7 8/15 net: cadence_gem: Split state struct and type into header

In reply to Peter Crosthwaite

Create a new header for Cadence GEM to allow using the device with modern SoC programming conventions. The state struct needs to be visible to embed the device in SoC containers.

---
changed since v4:
Added (c) information
Make commit msg body self contained changed since v1:
Fix /* Public */ comment spacing (Alistair review)

 hw/net/cadence_gem.c         | 43 +-------------------------
 include/hw/net/cadence_gem.h | 73 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 42 deletions(-)
 create mode 100644 include/hw/net/cadence_gem.h
hw/net/cadence_gem.c +1 -42
index 5994306..dafe914 100644
@@ -24,8 +24,7 @@
 
 #include <zlib.h> /* For crc32 */
 
-#include "hw/sysbus.h"
-#include "net/net.h"
+#include "hw/net/cadence_gem.h"
 #include "net/checksum.h"
 
 #ifdef CADENCE_GEM_ERR_DEBUG
@@ -141,8 +140,6 @@
 #define GEM_DESCONF6      (0x00000294/4)
 #define GEM_DESCONF7      (0x00000298/4)
 
-#define CADENCE_GEM_MAXREG        (0x00000640/4) /* Last valid GEM address */
-
 /*****************************************/
 #define GEM_NWCTRL_TXSTART     0x00000200 /* Transmit Enable */
 #define GEM_NWCTRL_TXENA       0x00000008 /* Transmit Enable */
@@ -349,44 +346,6 @@ static inline void rx_desc_set_sar(unsigned *desc, int sar_idx)
     desc[1] |= R_DESC_1_RX_SAR_MATCH;
 }
 
-#define TYPE_CADENCE_GEM "cadence_gem"
-#define CADENCE_GEM(obj) OBJECT_CHECK(CadenceGEMState, (obj), TYPE_CADENCE_GEM)
-
-typedef struct CadenceGEMState {
-    SysBusDevice parent_obj;
-
-    MemoryRegion iomem;
-    NICState *nic;
-    NICConf conf;
-    qemu_irq irq;
-
-    /* GEM registers backing store */
-    uint32_t regs[CADENCE_GEM_MAXREG];
-    /* Mask of register bits which are write only */
-    uint32_t regs_wo[CADENCE_GEM_MAXREG];
-    /* Mask of register bits which are read only */
-    uint32_t regs_ro[CADENCE_GEM_MAXREG];
-    /* Mask of register bits which are clear on read */
-    uint32_t regs_rtc[CADENCE_GEM_MAXREG];
-    /* Mask of register bits which are write 1 to clear */
-    uint32_t regs_w1c[CADENCE_GEM_MAXREG];
-
-    /* PHY registers backing store */
-    uint16_t phy_regs[32];
-
-    uint8_t phy_loop; /* Are we in phy loopback? */
-
-    /* The current DMA descriptor pointers */
-    uint32_t rx_desc_addr;
-    uint32_t tx_desc_addr;
-
-    uint8_t can_rx_state; /* Debug only */
-
-    unsigned rx_desc[2];
-
-    bool sar_active[4];
-} CadenceGEMState;
-
 /* The broadcast MAC address: 0xFFFFFFFFFFFF */
 static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
include/hw/net/cadence_gem.h new file +73 -0

73 lines not on this page · raw message

Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#15 lore raw

PATCH v7 9/15 arm: xlnx-zynqmp: Add GEM support

In reply to Peter Crosthwaite

There are 4x Cadence GEMs in ZynqMP. Add them.

---
changed since v4:
Remove use of ERR_PROP_CHECK_RETURN

 hw/arm/xlnx-zynqmp.c         | 35 +++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h |  3 +++
 2 files changed, 38 insertions(+)
hw/arm/xlnx-zynqmp.c +35 -0
index 12a8c77..4d54432 100644
@@ -28,6 +28,14 @@
 #define GIC_DIST_ADDR       0xf9010000
 #define GIC_CPU_ADDR        0xf9020000
 
+static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
+    0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
+};
+
+static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = {
+    57, 59, 61, 63,
+};
+
 typedef struct XlnxZynqMPGICRegion {
     int region_index;
     uint32_t address;
@@ -57,6 +65,11 @@ static void xlnx_zynqmp_init(Object *obj)
 
     object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
     qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
+
+    for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
+        object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM);
+        qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default());
+    }
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -64,6 +77,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
     XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
     MemoryRegion *system_memory = get_system_memory();
     uint8_t i;
+    qemu_irq gic_spi[GIC_NUM_SPI_INTR];
     Error *err = NULL;
 
     qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
@@ -127,6 +141,27 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
                                arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
         qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 1, irq);
     }
+
+    for (i = 0; i < GIC_NUM_SPI_INTR; i++) {
+        gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i);
+    }
+
+    for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (nd->used) {
+            qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
+            qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
+        }
+        object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
+        if (err) {
+            error_propagate((errp), (err));
+            return;
+        }
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
+                           gic_spi[gem_intr[i]]);
+    }
 }
 
 static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
include/hw/arm/xlnx-zynqmp.h +3 -0
index 9d40e9f..9b5d8f6 100644
@@ -20,12 +20,14 @@
 #include "qemu-common.h"
 #include "hw/arm/arm.h"
 #include "hw/intc/arm_gic.h"
+#include "hw/net/cadence_gem.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
                                        TYPE_XLNX_ZYNQMP)
 
 #define XLNX_ZYNQMP_NUM_CPUS 4
+#define XLNX_ZYNQMP_NUM_GEMS 4
 
 #define XLNX_ZYNQMP_GIC_REGIONS 2
 
@@ -45,6 +47,7 @@ typedef struct XlnxZynqMPState {
     ARMCPU cpu[XLNX_ZYNQMP_NUM_CPUS];
     GICState gic;
     MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
+    CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
 }  XlnxZynqMPState;
 
 #define XLNX_ZYNQMP_H
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#16 lore raw

PATCH v7 10/15 char: cadence_uart: Clean up variable names

In reply to Peter Crosthwaite

Clean up some variable names in preparation for migrating the state struct and type cast macro to a public header. The acronym "UART" on it's own is not specific enough to be used in a more global namespace so preface with "cadence". Fix the capitalisation of "uart" in the state type while touching the typename. Preface macros used by the state struct itself with CADENCE_UART so they don't conflict in namespace either.

---
Changed since v4:
Make commit message body self contained.

 hw/char/cadence_uart.c | 102 ++++++++++++++++++++++++++-----------------------
 1 file changed, 54 insertions(+), 48 deletions(-)
hw/char/cadence_uart.c +54 -48
index d145378..4a4d3eb 100644
@@ -85,8 +85,8 @@
 #define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
 #define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
 
-#define RX_FIFO_SIZE           16
-#define TX_FIFO_SIZE           16
+#define CADENCE_UART_RX_FIFO_SIZE           16
+#define CADENCE_UART_TX_FIFO_SIZE           16
 #define UART_INPUT_CLK         50000000
 
 #define R_CR       (0x00/4)
@@ -108,10 +108,11 @@
 #define R_PWID     (0x40/4)
 #define R_TTRIG    (0x44/4)
 
-#define R_MAX (R_TTRIG + 1)
+#define CADENCE_UART_R_MAX (0x48/4)
 
 #define TYPE_CADENCE_UART "cadence_uart"
-#define CADENCE_UART(obj) OBJECT_CHECK(UartState, (obj), TYPE_CADENCE_UART)
+#define CADENCE_UART(obj) OBJECT_CHECK(CadenceUARTState, (obj), \
+                                       TYPE_CADENCE_UART)
 
 typedef struct {
     /*< private >*/
@@ -119,9 +120,9 @@ typedef struct {
     /*< public >*/
 
     MemoryRegion iomem;
-    uint32_t r[R_MAX];
-    uint8_t rx_fifo[RX_FIFO_SIZE];
-    uint8_t tx_fifo[TX_FIFO_SIZE];
+    uint32_t r[CADENCE_UART_R_MAX];
+    uint8_t rx_fifo[CADENCE_UART_RX_FIFO_SIZE];
+    uint8_t tx_fifo[CADENCE_UART_TX_FIFO_SIZE];
     uint32_t rx_wpos;
     uint32_t rx_count;
     uint32_t tx_count;
@@ -129,17 +130,19 @@ typedef struct {
     CharDriverState *chr;
     qemu_irq irq;
     QEMUTimer *fifo_trigger_handle;
-} UartState;
+} CadenceUARTState;
 
-static void uart_update_status(UartState *s)
+static void uart_update_status(CadenceUARTState *s)
 {
     s->r[R_SR] = 0;
 
-    s->r[R_SR] |= s->rx_count == RX_FIFO_SIZE ? UART_SR_INTR_RFUL : 0;
+    s->r[R_SR] |= s->rx_count == CADENCE_UART_RX_FIFO_SIZE ? UART_SR_INTR_RFUL
+                                                           : 0;
     s->r[R_SR] |= !s->rx_count ? UART_SR_INTR_REMPTY : 0;
     s->r[R_SR] |= s->rx_count >= s->r[R_RTRIG] ? UART_SR_INTR_RTRIG : 0;
 
-    s->r[R_SR] |= s->tx_count == TX_FIFO_SIZE ? UART_SR_INTR_TFUL : 0;
+    s->r[R_SR] |= s->tx_count == CADENCE_UART_TX_FIFO_SIZE ? UART_SR_INTR_TFUL
+                                                           : 0;
     s->r[R_SR] |= !s->tx_count ? UART_SR_INTR_TEMPTY : 0;
     s->r[R_SR] |= s->tx_count >= s->r[R_TTRIG] ? UART_SR_TTRIG : 0;
 
@@ -150,14 +153,14 @@ static void uart_update_status(UartState *s)
 
 static void fifo_trigger_update(void *opaque)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
 
     s->r[R_CISR] |= UART_INTR_TIMEOUT;
 
     uart_update_status(s);
 }
 
-static void uart_rx_reset(UartState *s)
+static void uart_rx_reset(CadenceUARTState *s)
 {
     s->rx_wpos = 0;
     s->rx_count = 0;
@@ -166,12 +169,12 @@ static void uart_rx_reset(UartState *s)
     }
 }
 
-static void uart_tx_reset(UartState *s)
+static void uart_tx_reset(CadenceUARTState *s)
 {
     s->tx_count = 0;
 }
 
-static void uart_send_breaks(UartState *s)
+static void uart_send_breaks(CadenceUARTState *s)
 {
     int break_enabled = 1;
 
@@ -181,7 +184,7 @@ static void uart_send_breaks(UartState *s)
     }
 }
 
-static void uart_parameters_setup(UartState *s)
+static void uart_parameters_setup(CadenceUARTState *s)
 {
     QEMUSerialSetParams ssp;
     unsigned int baud_rate, packet_size;
@@ -236,20 +239,20 @@ static void uart_parameters_setup(UartState *s)
 
 static int uart_can_receive(void *opaque)
 {
-    UartState *s = (UartState *)opaque;
-    int ret = MAX(RX_FIFO_SIZE, TX_FIFO_SIZE);
+    CadenceUARTState *s = opaque;
+    int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
     uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
 
     if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
-        ret = MIN(ret, RX_FIFO_SIZE - s->rx_count);
+        ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count);
     }
     if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
-        ret = MIN(ret, TX_FIFO_SIZE - s->tx_count);
+        ret = MIN(ret, CADENCE_UART_TX_FIFO_SIZE - s->tx_count);
     }
     return ret;
 }
 
-static void uart_ctrl_update(UartState *s)
+static void uart_ctrl_update(CadenceUARTState *s)
 {
     if (s->r[R_CR] & UART_CR_TXRST) {
         uart_tx_reset(s);
@@ -268,7 +271,7 @@ static void uart_ctrl_update(UartState *s)
 
 static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
     uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     int i;
 
@@ -276,12 +279,12 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
         return;
     }
 
-    if (s->rx_count == RX_FIFO_SIZE) {
+    if (s->rx_count == CADENCE_UART_RX_FIFO_SIZE) {
         s->r[R_CISR] |= UART_INTR_ROVR;
     } else {
         for (i = 0; i < size; i++) {
             s->rx_fifo[s->rx_wpos] = buf[i];
-            s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE;
+            s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE;
             s->rx_count++;
         }
         timer_mod(s->fifo_trigger_handle, new_rx_time +
@@ -293,7 +296,7 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
 static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
                                   void *opaque)
 {
-    UartState *s = opaque;
+    CadenceUARTState *s = opaque;
     int ret;
 
     /* instant drain the fifo when there's no back-end */
@@ -320,14 +323,15 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
     return FALSE;
 }
 
-static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
+static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf,
+                               int size)
 {
     if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
         return;
     }
 
-    if (size > TX_FIFO_SIZE - s->tx_count) {
-        size = TX_FIFO_SIZE - s->tx_count;
+    if (size > CADENCE_UART_TX_FIFO_SIZE - s->tx_count) {
+        size = CADENCE_UART_TX_FIFO_SIZE - s->tx_count;
         /*
          * This can only be a guest error via a bad tx fifo register push,
          * as can_receive() should stop remote loop and echo modes ever getting
@@ -345,7 +349,7 @@ static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
 
 static void uart_receive(void *opaque, const uint8_t *buf, int size)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
     uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
 
     if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
@@ -358,7 +362,7 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size)
 
 static void uart_event(void *opaque, int event)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
     uint8_t buf = '\0';
 
     if (event == CHR_EVENT_BREAK) {
@@ -368,15 +372,15 @@ static void uart_event(void *opaque, int event)
     uart_update_status(s);
 }
 
-static void uart_read_rx_fifo(UartState *s, uint32_t *c)
+static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
 {
     if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
         return;
     }
 
     if (s->rx_count) {
-        uint32_t rx_rpos =
-                (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE;
+        uint32_t rx_rpos = (CADENCE_UART_RX_FIFO_SIZE + s->rx_wpos -
+                            s->rx_count) % CADENCE_UART_RX_FIFO_SIZE;
         *c = s->rx_fifo[rx_rpos];
         s->rx_count--;
 
@@ -393,7 +397,7 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c)
 static void uart_write(void *opaque, hwaddr offset,
                           uint64_t value, unsigned size)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
 
     DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
     offset >>= 2;
@@ -437,11 +441,11 @@ static void uart_write(void *opaque, hwaddr offset,
 static uint64_t uart_read(void *opaque, hwaddr offset,
         unsigned size)
 {
-    UartState *s = (UartState *)opaque;
+    CadenceUARTState *s = opaque;
     uint32_t c = 0;
 
     offset >>= 2;
-    if (offset >= R_MAX) {
+    if (offset >= CADENCE_UART_R_MAX) {
         c = 0;
     } else if (offset == R_TX_RX) {
         uart_read_rx_fifo(s, &c);
@@ -461,7 +465,7 @@ static const MemoryRegionOps uart_ops = {
 
 static void cadence_uart_reset(DeviceState *dev)
 {
-    UartState *s = CADENCE_UART(dev);
+    CadenceUARTState *s = CADENCE_UART(dev);
 
     s->r[R_CR] = 0x00000128;
     s->r[R_IMR] = 0;
@@ -478,7 +482,7 @@ static void cadence_uart_reset(DeviceState *dev)
 
 static void cadence_uart_realize(DeviceState *dev, Error **errp)
 {
-    UartState *s = CADENCE_UART(dev);
+    CadenceUARTState *s = CADENCE_UART(dev);
 
     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                           fifo_trigger_update, s);
@@ -495,7 +499,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
 static void cadence_uart_init(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-    UartState *s = CADENCE_UART(obj);
+    CadenceUARTState *s = CADENCE_UART(obj);
 
     memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
@@ -506,7 +510,7 @@ static void cadence_uart_init(Object *obj)
 
 static int cadence_uart_post_load(void *opaque, int version_id)
 {
-    UartState *s = opaque;
+    CadenceUARTState *s = opaque;
 
     uart_parameters_setup(s);
     uart_update_status(s);
@@ -519,13 +523,15 @@ static const VMStateDescription vmstate_cadence_uart = {
     .minimum_version_id = 2,
     .post_load = cadence_uart_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(r, UartState, R_MAX),
-        VMSTATE_UINT8_ARRAY(rx_fifo, UartState, RX_FIFO_SIZE),
-        VMSTATE_UINT8_ARRAY(tx_fifo, UartState, RX_FIFO_SIZE),
-        VMSTATE_UINT32(rx_count, UartState),
-        VMSTATE_UINT32(tx_count, UartState),
-        VMSTATE_UINT32(rx_wpos, UartState),
-        VMSTATE_TIMER_PTR(fifo_trigger_handle, UartState),
+        VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX),
+        VMSTATE_UINT8_ARRAY(rx_fifo, CadenceUARTState,
+                            CADENCE_UART_RX_FIFO_SIZE),
+        VMSTATE_UINT8_ARRAY(tx_fifo, CadenceUARTState,
+                            CADENCE_UART_TX_FIFO_SIZE),
+        VMSTATE_UINT32(rx_count, CadenceUARTState),
+        VMSTATE_UINT32(tx_count, CadenceUARTState),
+        VMSTATE_UINT32(rx_wpos, CadenceUARTState),
+        VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -544,7 +550,7 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data)
 static const TypeInfo cadence_uart_info = {
     .name          = TYPE_CADENCE_UART,
     .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(UartState),
+    .instance_size = sizeof(CadenceUARTState),
     .instance_init = cadence_uart_init,
     .class_init    = cadence_uart_class_init,
 };
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#17 lore raw

PATCH v7 11/15 char: cadence_uart: Split state struct and type into header

In reply to Peter Crosthwaite

Create a new header for Cadence UART to allow using the device with modern SoC programming conventions. The state struct needs to be visible to embed the device in SoC containers.

---
changed since v4 (PMM review):
remove include guard _
Add (c) info to header
Make commit msg body standalone
changed since v1:
Fix /* Public */ comment spacing (Alistair review)

 hw/char/cadence_uart.c         | 29 +----------------------
 include/hw/char/cadence_uart.h | 53 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 28 deletions(-)
 create mode 100644 include/hw/char/cadence_uart.h
hw/char/cadence_uart.c +1 -28
index 4a4d3eb..9d379e5 100644
@@ -16,9 +16,7 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "hw/sysbus.h"
-#include "sysemu/char.h"
-#include "qemu/timer.h"
+#include "hw/char/cadence_uart.h"
 
 #ifdef CADENCE_UART_ERR_DEBUG
 #define DB_PRINT(...) do { \
@@ -85,8 +83,6 @@
 #define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
 #define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
 
-#define CADENCE_UART_RX_FIFO_SIZE           16
-#define CADENCE_UART_TX_FIFO_SIZE           16
 #define UART_INPUT_CLK         50000000
 
 #define R_CR       (0x00/4)
@@ -108,29 +104,6 @@
 #define R_PWID     (0x40/4)
 #define R_TTRIG    (0x44/4)
 
-#define CADENCE_UART_R_MAX (0x48/4)
-
-#define TYPE_CADENCE_UART "cadence_uart"
-#define CADENCE_UART(obj) OBJECT_CHECK(CadenceUARTState, (obj), \
-                                       TYPE_CADENCE_UART)
-
-typedef struct {
-    /*< private >*/
-    SysBusDevice parent_obj;
-    /*< public >*/
-
-    MemoryRegion iomem;
-    uint32_t r[CADENCE_UART_R_MAX];
-    uint8_t rx_fifo[CADENCE_UART_RX_FIFO_SIZE];
-    uint8_t tx_fifo[CADENCE_UART_TX_FIFO_SIZE];
-    uint32_t rx_wpos;
-    uint32_t rx_count;
-    uint32_t tx_count;
-    uint64_t char_tx_time;
-    CharDriverState *chr;
-    qemu_irq irq;
-    QEMUTimer *fifo_trigger_handle;
-} CadenceUARTState;
 
 static void uart_update_status(CadenceUARTState *s)
 {
include/hw/char/cadence_uart.h new file +53 -0

53 lines not on this page · raw message

Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#18 lore raw

PATCH v7 12/15 arm: xlnx-zynqmp: Add UART support

In reply to Peter Crosthwaite

There are 2x Cadence UARTs in Zynq MP. Add them.

---
Changed since v4:
Remove ERR_PROP_CHECK_RETURN usage.
Changed since v1:
Fixed "UARTSs" typo

 hw/arm/xlnx-zynqmp.c         | 24 ++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h |  3 +++
 2 files changed, 27 insertions(+)
hw/arm/xlnx-zynqmp.c +24 -0
index 4d54432..90f39cc 100644
@@ -36,6 +36,14 @@ static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = {
     57, 59, 61, 63,
 };
 
+static const uint64_t uart_addr[XLNX_ZYNQMP_NUM_UARTS] = {
+    0xFF000000, 0xFF010000,
+};
+
+static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = {
+    21, 22,
+};
+
 typedef struct XlnxZynqMPGICRegion {
     int region_index;
     uint32_t address;
@@ -70,6 +78,11 @@ static void xlnx_zynqmp_init(Object *obj)
         object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM);
         qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default());
     }
+
+    for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
+        object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART);
+        qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
+    }
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -162,6 +175,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
         sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
                            gic_spi[gem_intr[i]]);
     }
+
+    for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
+        object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
+        if (err) {
+            error_propagate((errp), (err));
+            return;
+        }
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+                           gic_spi[uart_intr[i]]);
+    }
 }
 
 static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
include/hw/arm/xlnx-zynqmp.h +3 -0
index 9b5d8f6..fc92ed5 100644
@@ -21,6 +21,7 @@
 #include "hw/arm/arm.h"
 #include "hw/intc/arm_gic.h"
 #include "hw/net/cadence_gem.h"
+#include "hw/char/cadence_uart.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@@ -28,6 +29,7 @@
 
 #define XLNX_ZYNQMP_NUM_CPUS 4
 #define XLNX_ZYNQMP_NUM_GEMS 4
+#define XLNX_ZYNQMP_NUM_UARTS 2
 
 #define XLNX_ZYNQMP_GIC_REGIONS 2
 
@@ -48,6 +50,7 @@ typedef struct XlnxZynqMPState {
     GICState gic;
     MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
     CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
+    CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
 }  XlnxZynqMPState;
 
 #define XLNX_ZYNQMP_H
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#19 lore raw

PATCH v7 13/15 arm: Add xlnx-ep108 machine

In reply to Peter Crosthwaite

Add a machine model for the Xilinx ZynqMP SoC EP108 board.

---
Chaned since v1:
Change board name to ep108

 hw/arm/Makefile.objs |  2 +-
 hw/arm/xlnx-ep108.c  | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/xlnx-ep108.c
hw/arm/Makefile.objs +1 -1
index d7cd5f4..a75a182 100644
@@ -10,4 +10,4 @@ obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o
+obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
hw/arm/xlnx-ep108.c new file +53 -0

53 lines not on this page · raw message

Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#20 lore raw

PATCH v7 14/15 arm: xlnx-ep108: Add external RAM

In reply to Peter Crosthwaite

Zynq MPSoC supports external DDR RAM. Add a RAM at 0 to the model.

---
changed since v4:
Use memory_region_allocate_system_memory
Change too-small warning to be qemu_log
changed since v1:
Add ram size clamps and warnings

 hw/arm/xlnx-ep108.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
hw/arm/xlnx-ep108.c +20 -0
index 81704bb..46f145b 100644
@@ -18,11 +18,16 @@
 #include "hw/arm/xlnx-zynqmp.h"
 #include "hw/boards.h"
 #include "qemu/error-report.h"
+#include "exec/address-spaces.h"
 
 typedef struct XlnxEP108 {
     XlnxZynqMPState soc;
+    MemoryRegion ddr_ram;
 } XlnxEP108;
 
+/* Max 2GB RAM */
+#define EP108_MAX_RAM_SIZE 0x80000000ull
+
 static void xlnx_ep108_init(MachineState *machine)
 {
     XlnxEP108 *s = g_new0(XlnxEP108, 1);
@@ -37,6 +42,21 @@ static void xlnx_ep108_init(MachineState *machine)
         error_report("%s", error_get_pretty(err));
         exit(1);
     }
+
+    if (machine->ram_size > EP108_MAX_RAM_SIZE) {
+        error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
+                     "reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE);
+        machine->ram_size = EP108_MAX_RAM_SIZE;
+    }
+
+    if (machine->ram_size <= 0x08000000) {
+        qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108",
+                 machine->ram_size);
+    }
+
+    memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
+                                         machine->ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram);
 }
 
 static QEMUMachine xlnx_ep108_machine = {
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#21 lore raw

PATCH v7 15/15 arm: xlnx-ep108: Add bootloading

In reply to Peter Crosthwaite

Add bootloader support using standard ARM bootloader.

---
changed since v4:
Add loader_start field
Make commit message body standalone.

 hw/arm/xlnx-ep108.c | 9 +++++++++
 1 file changed, 9 insertions(+)
hw/arm/xlnx-ep108.c +9 -0
index 46f145b..b924f5e 100644
@@ -28,6 +28,8 @@ typedef struct XlnxEP108 {
 /* Max 2GB RAM */
 #define EP108_MAX_RAM_SIZE 0x80000000ull
 
+static struct arm_boot_info xlnx_ep108_binfo;
+
 static void xlnx_ep108_init(MachineState *machine)
 {
     XlnxEP108 *s = g_new0(XlnxEP108, 1);
@@ -57,6 +59,13 @@ static void xlnx_ep108_init(MachineState *machine)
     memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
                                          machine->ram_size);
     memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram);
+
+    xlnx_ep108_binfo.ram_size = machine->ram_size;
+    xlnx_ep108_binfo.kernel_filename = machine->kernel_filename;
+    xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
+    xlnx_ep108_binfo.initrd_filename = machine->initrd_filename;
+    xlnx_ep108_binfo.loader_start = 0;
+    arm_load_kernel(&s->soc.cpu[0], &xlnx_ep108_binfo);
 }
 
 static QEMUMachine xlnx_ep108_machine = {
Signature · 1 line
2.4.0.3.ge0ccc3b.dirty
#22 lore raw
In reply to Peter Crosthwaite
Quoted 14 lines · Peter Crosthwaite

Hi Peter and all,

Xilinx's next gen SoC has been announced. This series adds a SoC and board.

Series start with addition of ARM cortex A53 support (P1 and P2). The Soc skeleton is then added with GIC, EMACs and UARTs added. The pre-existing models for GEM and UART are not SoC friendly (no visible state struct), so those are refactored for SoC.

Create a model of the EP108 board. Currently this doesn't have any EP108 specific features but is a usable board exposing the user visible features of the raw SoC.

Quoted 5 lines

See individual patches for detailed change logs.

changed since v6 (Edgar review):
Added GIC region size macro
Added GIC alises

I've made some comments about these new GIC bits. Other than that I don't have any problem with the rest of the series (though I haven't actually reviewed all the patches, I'm happy not to :-))

thanks
-- PMM