qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
@ 2020-05-21 19:21 Havard Skinnemoen
  2020-05-21 19:21 ` [PATCH 1/6] npcm7xx: Add config symbol Havard Skinnemoen
                   ` (7 more replies)
  0 siblings, 8 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

This patch series models enough of the Nuvoton NPCM730 and NPCM750 SoCs to boot
a minimal Linux kernel. This includes device models for:

  - Global Configuration Registers
  - Clock Control
  - Timers

These modules, along with the existing Cortex A9 CPU cores and built-in
peripherals, are integrated into a NPCM730 or NPCM750 SoC, which in turn form
the foundation for the quanta-gsj and npcm750-evb machines, respectively. The
two SoCs are very similar; the only difference is that NPCM730 is missing some
peripherals that NPCM750 has, and which are not considered essential for
datacenter use (e.g. graphics controllers). For more information, see

https://www.nuvoton.com/products/cloud-computing/ibmc/

Both quanta-gsj and npcm750-evb correspond to real boards supported by OpenBMC.
While this initial series uses a stripped-down kernel for testing, future
series will be tested using OpenBMC images built from public sources. I'm
currently putting the finishing touches on flash controller support, which is
necessary to boot a full OpenBMC image, and will be enabled by the next series.

The patches in this series were developed by Google and reviewed by Nuvoton. We
will be maintaining the machine and peripheral support together.

The data sheet for these SoCs is not generally available. Please let me know if
more comments are needed to understand the device behavior.

Thanks for reviewing,

Havard

Havard Skinnemoen (6):
  npcm7xx: Add config symbol
  hw/misc: Add NPCM7xx System Global Control Registers device model
  hw/misc: Add NPCM7xx Clock Controller device model
  hw/timer: Add NPCM7xx Timer device model
  hw/arm: Add NPCM730 and NPCM750 SoC models
  hw/arm: Add two NPCM7xx-based machines

 MAINTAINERS                      |  12 +
 default-configs/arm-softmmu.mak  |   1 +
 hw/arm/Kconfig                   |   8 +
 hw/arm/Makefile.objs             |   1 +
 hw/arm/npcm7xx.c                 | 328 +++++++++++++++++++++++
 hw/arm/npcm7xx_boards.c          | 108 ++++++++
 hw/misc/Makefile.objs            |   2 +
 hw/misc/npcm7xx_clk.c            | 210 +++++++++++++++
 hw/misc/npcm7xx_gcr.c            | 160 +++++++++++
 hw/misc/trace-events             |   8 +
 hw/timer/Makefile.objs           |   1 +
 hw/timer/npcm7xx_timer.c         | 437 +++++++++++++++++++++++++++++++
 hw/timer/trace-events            |   5 +
 include/hw/arm/npcm7xx.h         |  98 +++++++
 include/hw/misc/npcm7xx_clk.h    |  65 +++++
 include/hw/misc/npcm7xx_gcr.h    |  74 ++++++
 include/hw/timer/npcm7xx_timer.h |  95 +++++++
 17 files changed, 1613 insertions(+)
 create mode 100644 hw/arm/npcm7xx.c
 create mode 100644 hw/arm/npcm7xx_boards.c
 create mode 100644 hw/misc/npcm7xx_clk.c
 create mode 100644 hw/misc/npcm7xx_gcr.c
 create mode 100644 hw/timer/npcm7xx_timer.c
 create mode 100644 include/hw/arm/npcm7xx.h
 create mode 100644 include/hw/misc/npcm7xx_clk.h
 create mode 100644 include/hw/misc/npcm7xx_gcr.h
 create mode 100644 include/hw/timer/npcm7xx_timer.h

-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 1/6] npcm7xx: Add config symbol
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-05-21 19:21 ` [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model Havard Skinnemoen
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

Add a config symbol for the NPCM7xx BMC SoC family that subsequent
patches can use in Makefiles.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 default-configs/arm-softmmu.mak | 1 +
 hw/arm/Kconfig                  | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 8fc09a4a51..9a94ebd0be 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -27,6 +27,7 @@ CONFIG_GUMSTIX=y
 CONFIG_SPITZ=y
 CONFIG_TOSA=y
 CONFIG_Z2=y
+CONFIG_NPCM7XX=y
 CONFIG_COLLIE=y
 CONFIG_ASPEED_SOC=y
 CONFIG_NETDUINO2=y
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 5364172537..47d0a3ca43 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -354,6 +354,14 @@ config XLNX_VERSAL
     select VIRTIO_MMIO
     select UNIMP
 
+config NPCM7XX
+    bool
+    select A9MPCORE
+    select ARM_GIC
+    select PL310  # cache controller
+    select SERIAL
+    select UNIMP
+
 config FSL_IMX25
     bool
     select IMX
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
  2020-05-21 19:21 ` [PATCH 1/6] npcm7xx: Add config symbol Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  2020-05-21 19:21 ` [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller " Havard Skinnemoen
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

Implement a device model for the System Global Control Registers in the
NPCM730 and NPCM750 BMC SoCs.

This is primarily used to enable SMP boot (the boot ROM spins reading
the SCRPAD register); other registers are best effort for now.

The reset values of the MDLR and PWRON registers are determined by the
SoC variant (730 vs 750) and board straps respectively.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 MAINTAINERS                   |   8 ++
 hw/misc/Makefile.objs         |   1 +
 hw/misc/npcm7xx_gcr.c         | 160 ++++++++++++++++++++++++++++++++++
 hw/misc/trace-events          |   4 +
 include/hw/misc/npcm7xx_gcr.h |  74 ++++++++++++++++
 5 files changed, 247 insertions(+)
 create mode 100644 hw/misc/npcm7xx_gcr.c
 create mode 100644 include/hw/misc/npcm7xx_gcr.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 87a412c229..5b150184ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -715,6 +715,14 @@ S: Odd Fixes
 F: hw/arm/musicpal.c
 F: docs/system/arm/musicpal.rst
 
+Nuvoton NPCM7xx
+M: Havard Skinnemoen <hskinnemoen@google.com>
+M: Tyrone Ting <kfting@nuvoton.com>
+L: qemu-arm@nongnu.org
+S: Supported
+F: hw/misc/npcm7xx*
+F: include/hw/misc/npcm7xx*
+
 nSeries
 M: Andrzej Zaborowski <balrogg@gmail.com>
 M: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 68aae2eabb..4d83fa337b 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
 common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
+common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o
 common-obj-$(CONFIG_OMAP) += omap_clk.o
 common-obj-$(CONFIG_OMAP) += omap_gpmc.o
 common-obj-$(CONFIG_OMAP) += omap_l4.o
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
new file mode 100644
index 0000000000..cd8690a968
--- /dev/null
+++ b/hw/misc/npcm7xx_gcr.c
@@ -0,0 +1,160 @@
+/*
+ * Nuvoton NPCM7xx System Global Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/misc/npcm7xx_gcr.h"
+#include "hw/qdev-properties.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
+    [NPCM7XX_GCR_PDID]          = 0x04A92750,   /* Poleg A1 */
+    [NPCM7XX_GCR_MISCPE]        = 0x0000FFFF,
+    [NPCM7XX_GCR_SPSWC]         = 0x00000003,
+    [NPCM7XX_GCR_INTCR]         = 0x0000035E,
+    [NPCM7XX_GCR_HIFCR]         = 0x0000004E,
+    [NPCM7XX_GCR_RESSR]         = 0x80000000,
+    [NPCM7XX_GCR_DSCNT]         = 0x000000c0,
+    [NPCM7XX_GCR_DAVCLVLR]      = 0x5A00F3CF,
+    [NPCM7XX_GCR_INTCR3]        = 0x00001002,
+    [NPCM7XX_GCR_SCRPAD]        = 0x00000008,
+    [NPCM7XX_GCR_USB1PHYCTL]    = 0x034730E4,
+    [NPCM7XX_GCR_USB2PHYCTL]    = 0x034730E4,
+};
+
+static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint32_t reg = offset / sizeof(uint32_t);
+    NPCM7xxGCRState *s = opaque;
+
+    if (reg >= NPCM7XX_GCR_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
+                      __func__, (unsigned int)offset);
+        return 0;
+    }
+
+    trace_npcm7xx_gcr_read(offset, s->regs[reg]);
+
+    return s->regs[reg];
+}
+
+static void npcm7xx_gcr_write(void *opaque, hwaddr offset,
+                              uint64_t v, unsigned size)
+{
+    uint32_t reg = offset / sizeof(uint32_t);
+    NPCM7xxGCRState *s = opaque;
+    uint32_t value = v;
+
+    trace_npcm7xx_gcr_write(offset, value);
+
+    if (reg >= NPCM7XX_GCR_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
+                      __func__, (unsigned int)offset);
+        return;
+    }
+
+    switch (reg) {
+    case NPCM7XX_GCR_PDID:
+    case NPCM7XX_GCR_PWRON:
+    case NPCM7XX_GCR_INTSR:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is read-only\n",
+                      __func__, (unsigned int)offset);
+        return;
+
+    case NPCM7XX_GCR_RESSR:
+    case NPCM7XX_GCR_CP2BST:
+        /* Write 1 to clear */
+        value = s->regs[reg] & ~value;
+        break;
+
+    case NPCM7XX_GCR_RLOCKR1:
+    case NPCM7XX_GCR_MDLR:
+        /* Write 1 to set */
+        value |= s->regs[reg];
+        break;
+    };
+
+    s->regs[reg] = value;
+}
+
+static const struct MemoryRegionOps npcm7xx_gcr_ops = {
+    .read       = npcm7xx_gcr_read,
+    .write      = npcm7xx_gcr_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid      = {
+        .min_access_size        = 4,
+        .max_access_size        = 4,
+        .unaligned              = false,
+    },
+};
+
+static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
+{
+    NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
+
+    QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
+
+    switch (type) {
+    case RESET_TYPE_COLD:
+        memcpy(s->regs, cold_reset_values, sizeof(s->regs));
+        s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
+        s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
+        break;
+    }
+}
+
+static void npcm7xx_gcr_init(Object *obj)
+{
+    NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
+
+    memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
+                          TYPE_NPCM7XX_GCR, 4 * KiB);
+    sysbus_init_mmio(&s->parent, &s->iomem);
+}
+
+static Property npcm7xx_gcr_properties[] = {
+    DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0),
+    DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "NPCM7xx System Global Control Registers";
+    rc->phases.enter = npcm7xx_gcr_enter_reset;
+
+    device_class_set_props(dc, npcm7xx_gcr_properties);
+}
+
+static const TypeInfo npcm7xx_gcr_info = {
+    .name               = TYPE_NPCM7XX_GCR,
+    .parent             = TYPE_SYS_BUS_DEVICE,
+    .instance_size      = sizeof(NPCM7xxGCRState),
+    .instance_init      = npcm7xx_gcr_init,
+    .class_init         = npcm7xx_gcr_class_init,
+};
+
+static void npcm7xx_gcr_register_type(void)
+{
+    type_register_static(&npcm7xx_gcr_info);
+}
+type_init(npcm7xx_gcr_register_type);
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index a5862b2bed..d200438dbf 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -103,6 +103,10 @@ mos6522_set_sr_int(void) "set sr_int"
 mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
 
+# npcm7xx_gcr.c
+npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+
 # stm32f4xx_syscfg
 stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
 stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
diff --git a/include/hw/misc/npcm7xx_gcr.h b/include/hw/misc/npcm7xx_gcr.h
new file mode 100644
index 0000000000..e74a0e6305
--- /dev/null
+++ b/include/hw/misc/npcm7xx_gcr.h
@@ -0,0 +1,74 @@
+/*
+ * Nuvoton NPCM7xx System Global Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 NPCM7XX_GCR_H
+#define NPCM7XX_GCR_H
+
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+
+enum NPCM7xxGCRRegisters {
+    NPCM7XX_GCR_PDID,
+    NPCM7XX_GCR_PWRON,
+    NPCM7XX_GCR_MFSEL1          = 0x0C / sizeof(uint32_t),
+    NPCM7XX_GCR_MFSEL2,
+    NPCM7XX_GCR_MISCPE,
+    NPCM7XX_GCR_SPSWC           = 0x038 / sizeof(uint32_t),
+    NPCM7XX_GCR_INTCR,
+    NPCM7XX_GCR_INTSR,
+    NPCM7XX_GCR_HIFCR           = 0x050 / sizeof(uint32_t),
+    NPCM7XX_GCR_INTCR2          = 0x060 / sizeof(uint32_t),
+    NPCM7XX_GCR_MFSEL3,
+    NPCM7XX_GCR_SRCNT,
+    NPCM7XX_GCR_RESSR,
+    NPCM7XX_GCR_RLOCKR1,
+    NPCM7XX_GCR_FLOCKR1,
+    NPCM7XX_GCR_DSCNT,
+    NPCM7XX_GCR_MDLR,
+    NPCM7XX_GCR_SCRPAD3,
+    NPCM7XX_GCR_SCRPAD2,
+    NPCM7XX_GCR_DAVCLVLR        = 0x098 / sizeof(uint32_t),
+    NPCM7XX_GCR_INTCR3,
+    NPCM7XX_GCR_VSINTR          = 0x0AC / sizeof(uint32_t),
+    NPCM7XX_GCR_MFSEL4,
+    NPCM7XX_GCR_CPBPNTR         = 0x0C4 / sizeof(uint32_t),
+    NPCM7XX_GCR_CPCTL           = 0x0D0 / sizeof(uint32_t),
+    NPCM7XX_GCR_CP2BST,
+    NPCM7XX_GCR_B2CPNT,
+    NPCM7XX_GCR_CPPCTL,
+    NPCM7XX_GCR_I2CSEGSEL,
+    NPCM7XX_GCR_I2CSEGCTL,
+    NPCM7XX_GCR_VSRCR,
+    NPCM7XX_GCR_MLOCKR,
+    NPCM7XX_GCR_SCRPAD          = 0x013C / sizeof(uint32_t),
+    NPCM7XX_GCR_USB1PHYCTL,
+    NPCM7XX_GCR_USB2PHYCTL,
+    NPCM7XX_GCR_NR_REGS,
+};
+
+typedef struct NPCM7xxGCRState {
+    SysBusDevice parent;
+
+    MemoryRegion iomem;
+
+    uint32_t regs[NPCM7XX_GCR_NR_REGS];
+
+    uint32_t reset_pwron;
+    uint32_t reset_mdlr;
+} NPCM7xxGCRState;
+
+#define TYPE_NPCM7XX_GCR "npcm7xx-gcr"
+#define NPCM7XX_GCR(obj) OBJECT_CHECK(NPCM7xxGCRState, (obj), TYPE_NPCM7XX_GCR)
+
+#endif /* NPCM7XX_GCR_H */
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller device model
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
  2020-05-21 19:21 ` [PATCH 1/6] npcm7xx: Add config symbol Havard Skinnemoen
  2020-05-21 19:21 ` [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  2020-05-21 19:21 ` [PATCH 4/6] hw/timer: Add NPCM7xx Timer " Havard Skinnemoen
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

Enough functionality to boot the Linux kernel has been implemented. This
includes:

  - Correct power-on reset values so the various clock rates can be
    accurately calculated.
  - Clock enables stick around when written.

In addition, a best effort attempt to implement SECCNT and CNTR25M was
made even though I don't think the kernel needs them.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 hw/misc/Makefile.objs         |   1 +
 hw/misc/npcm7xx_clk.c         | 210 ++++++++++++++++++++++++++++++++++
 hw/misc/trace-events          |   4 +
 include/hw/misc/npcm7xx_clk.h |  65 +++++++++++
 4 files changed, 280 insertions(+)
 create mode 100644 hw/misc/npcm7xx_clk.c
 create mode 100644 include/hw/misc/npcm7xx_clk.h

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 4d83fa337b..1096a76457 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
 common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
+common-obj-$(CONFIG_NPCM7XX) += npcm7xx_clk.o
 common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o
 common-obj-$(CONFIG_OMAP) += omap_clk.o
 common-obj-$(CONFIG_OMAP) += omap_gpmc.o
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
new file mode 100644
index 0000000000..b4ff85e8c2
--- /dev/null
+++ b/hw/misc/npcm7xx_clk.c
@@ -0,0 +1,210 @@
+/*
+ * Nuvoton NPCM7xx Clock Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/misc/npcm7xx_clk.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/timer.h"
+#include "qemu/units.h"
+#include "trace.h"
+
+#define PLLCON_LOKI     BIT(31)
+#define PLLCON_LOKS     BIT(30)
+#define PLLCON_PWDEN    BIT(12)
+
+static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
+    [NPCM7XX_CLK_CLKEN1]        = 0xffffffff,
+    [NPCM7XX_CLK_CLKSEL]        = 0x004aaaaa,
+    [NPCM7XX_CLK_CLKDIV1]       = 0x5413f855,
+    [NPCM7XX_CLK_PLLCON0]       = 0x00222101 | PLLCON_LOKI,
+    [NPCM7XX_CLK_PLLCON1]       = 0x00202101 | PLLCON_LOKI,
+    [NPCM7XX_CLK_IPSRST1]       = 0x00001000,
+    [NPCM7XX_CLK_IPSRST2]       = 0x80000000,
+    [NPCM7XX_CLK_CLKEN2]        = 0xffffffff,
+    [NPCM7XX_CLK_CLKDIV2]       = 0xaa4f8f9f,
+    [NPCM7XX_CLK_CLKEN3]        = 0xffffffff,
+    [NPCM7XX_CLK_IPSRST3]       = 0x03000000,
+    [NPCM7XX_CLK_WD0RCR]        = 0xffffffff,
+    [NPCM7XX_CLK_WD1RCR]        = 0xffffffff,
+    [NPCM7XX_CLK_WD2RCR]        = 0xffffffff,
+    [NPCM7XX_CLK_SWRSTC1]       = 0x00000003,
+    [NPCM7XX_CLK_PLLCON2]       = 0x00c02105 | PLLCON_LOKI,
+    [NPCM7XX_CLK_CORSTC]        = 0x04000003,
+    [NPCM7XX_CLK_PLLCONG]       = 0x01228606 | PLLCON_LOKI,
+    [NPCM7XX_CLK_AHBCKFI]       = 0x000000c8,
+};
+
+static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint32_t reg = offset / sizeof(uint32_t);
+    NPCM7xxCLKState *s = opaque;
+    int64_t now_ns;
+    uint32_t value = 0;
+
+    if (reg >= NPCM7XX_CLK_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
+                      __func__, (unsigned int)offset);
+        return 0;
+    }
+
+    switch (reg) {
+    case NPCM7XX_CLK_SWRSTR:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is write-only\n",
+                      __func__, (unsigned int)offset);
+        break;
+
+    case NPCM7XX_CLK_SECCNT:
+        now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        value = (now_ns - s->ref_ns) / NANOSECONDS_PER_SECOND;
+        break;
+
+    case NPCM7XX_CLK_CNTR25M:
+        now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        /*
+         * This register counts 25 MHz cycles, updating every 640 ns. It rolls
+         * over to zero every second.
+         *
+         * The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
+         */
+        value = (((now_ns - s->ref_ns) / 640) << 4) % 25000000;
+        break;
+
+    default:
+        value = s->regs[reg];
+        break;
+    };
+
+    trace_npcm7xx_clk_read(offset, value);
+
+    return value;
+}
+
+static void npcm7xx_clk_write(void *opaque, hwaddr offset,
+                              uint64_t v, unsigned size)
+{
+    uint32_t reg = offset / sizeof(uint32_t);
+    NPCM7xxCLKState *s = opaque;
+    uint32_t value = v;
+
+    trace_npcm7xx_clk_write(offset, value);
+
+    if (reg >= NPCM7XX_CLK_NR_REGS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
+                      __func__, (unsigned int)offset);
+        return;
+    }
+
+    switch (reg) {
+    case NPCM7XX_CLK_SWRSTR:
+        qemu_log_mask(LOG_UNIMP, "%s: SW reset not implemented: 0x%02x\n",
+                      __func__, value);
+        value = 0;
+        break;
+
+    case NPCM7XX_CLK_PLLCON0:
+    case NPCM7XX_CLK_PLLCON1:
+    case NPCM7XX_CLK_PLLCON2:
+    case NPCM7XX_CLK_PLLCONG:
+        if (value & PLLCON_PWDEN) {
+            /* Power down -- clear lock and indicate loss of lock */
+            value &= ~PLLCON_LOKI;
+            value |= PLLCON_LOKS;
+        } else {
+            /* Normal mode -- assume always locked */
+            value |= PLLCON_LOKI;
+            /* Keep LOKS unchanged unless cleared by writing 1 */
+            if (value & PLLCON_LOKS) {
+                value &= ~PLLCON_LOKS;
+            } else {
+                value |= (value & PLLCON_LOKS);
+            }
+        }
+        break;
+
+    case NPCM7XX_CLK_CNTR25M:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is read-only\n",
+                      __func__, (unsigned int)offset);
+        return;
+    }
+
+    s->regs[reg] = value;
+}
+
+static const struct MemoryRegionOps npcm7xx_clk_ops = {
+    .read       = npcm7xx_clk_read,
+    .write      = npcm7xx_clk_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid      = {
+        .min_access_size        = 4,
+        .max_access_size        = 4,
+        .unaligned              = false,
+    },
+};
+
+static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
+{
+    NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+
+    QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
+
+    switch (type) {
+    case RESET_TYPE_COLD:
+        memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
+        s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        return;
+    }
+
+    /*
+     * A small number of registers need to be reset on a core domain reset,
+     * but no such reset type exists yet.
+     */
+    qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
+                  __func__, type);
+}
+
+static void npcm7xx_clk_init(Object *obj)
+{
+    NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+
+    memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
+                          TYPE_NPCM7XX_CLK, 4 * KiB);
+    sysbus_init_mmio(&s->parent, &s->iomem);
+}
+
+static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "NPCM7xx Clock Control Registers";
+    rc->phases.enter = npcm7xx_clk_enter_reset;
+}
+
+static const TypeInfo npcm7xx_clk_info = {
+    .name               = TYPE_NPCM7XX_CLK,
+    .parent             = TYPE_SYS_BUS_DEVICE,
+    .instance_size      = sizeof(NPCM7xxCLKState),
+    .instance_init      = npcm7xx_clk_init,
+    .class_init         = npcm7xx_clk_class_init,
+};
+
+static void npcm7xx_clk_register_type(void)
+{
+    type_register_static(&npcm7xx_clk_info);
+}
+type_init(npcm7xx_clk_register_type);
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index d200438dbf..ae97e8b091 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -103,6 +103,10 @@ mos6522_set_sr_int(void) "set sr_int"
 mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
 
+# npcm7xx_clk.c
+npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+
 # npcm7xx_gcr.c
 npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
 npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
new file mode 100644
index 0000000000..a678b50ede
--- /dev/null
+++ b/include/hw/misc/npcm7xx_clk.h
@@ -0,0 +1,65 @@
+/*
+ * Nuvoton NPCM7xx Clock Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 NPCM7XX_CLK_H
+#define NPCM7XX_CLK_H
+
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+
+enum NPCM7xxCLKRegisters {
+    NPCM7XX_CLK_CLKEN1,
+    NPCM7XX_CLK_CLKSEL,
+    NPCM7XX_CLK_CLKDIV1,
+    NPCM7XX_CLK_PLLCON0,
+    NPCM7XX_CLK_PLLCON1,
+    NPCM7XX_CLK_SWRSTR,
+    NPCM7XX_CLK_IPSRST1         = 0x20 / sizeof(uint32_t),
+    NPCM7XX_CLK_IPSRST2,
+    NPCM7XX_CLK_CLKEN2,
+    NPCM7XX_CLK_CLKDIV2,
+    NPCM7XX_CLK_CLKEN3,
+    NPCM7XX_CLK_IPSRST3,
+    NPCM7XX_CLK_WD0RCR,
+    NPCM7XX_CLK_WD1RCR,
+    NPCM7XX_CLK_WD2RCR,
+    NPCM7XX_CLK_SWRSTC1,
+    NPCM7XX_CLK_SWRSTC2,
+    NPCM7XX_CLK_SWRSTC3,
+    NPCM7XX_CLK_SWRSTC4,
+    NPCM7XX_CLK_PLLCON2,
+    NPCM7XX_CLK_CLKDIV3,
+    NPCM7XX_CLK_CORSTC,
+    NPCM7XX_CLK_PLLCONG,
+    NPCM7XX_CLK_AHBCKFI,
+    NPCM7XX_CLK_SECCNT,
+    NPCM7XX_CLK_CNTR25M,
+    NPCM7XX_CLK_NR_REGS,
+};
+
+typedef struct NPCM7xxCLKState {
+    SysBusDevice parent;
+
+    MemoryRegion iomem;
+
+    uint32_t regs[NPCM7XX_CLK_NR_REGS];
+
+    /* Time reference for SECCNT and CNTR25M, initialized by power on reset */
+    int64_t ref_ns;
+} NPCM7xxCLKState;
+
+#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
+#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
+
+#endif /* NPCM7XX_CLK_H */
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 4/6] hw/timer: Add NPCM7xx Timer device model
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
                   ` (2 preceding siblings ...)
  2020-05-21 19:21 ` [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller " Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-05-21 19:21 ` [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models Havard Skinnemoen
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

The NPCM730 and NPCM750 SoCs have three timer modules each holding five
timers and some shared registers (e.g. interrupt status).

Each timer runs at 25 MHz divided by a prescaler, and counts down from a
configurable initial value to zero. When zero is reached, the interrupt
flag for the timer is set, and the timer is disabled (one-shot mode) or
reloaded from its initial value (periodic mode).

This implementation is sufficient to boot a Linux kernel configured for
NPCM750. Note that the kernel does not seem to actually turn on the
interrupts.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 MAINTAINERS                      |   2 +
 hw/timer/Makefile.objs           |   1 +
 hw/timer/npcm7xx_timer.c         | 437 +++++++++++++++++++++++++++++++
 hw/timer/trace-events            |   5 +
 include/hw/timer/npcm7xx_timer.h |  95 +++++++
 5 files changed, 540 insertions(+)
 create mode 100644 hw/timer/npcm7xx_timer.c
 create mode 100644 include/hw/timer/npcm7xx_timer.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b150184ab..c9a59a2c10 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -721,7 +721,9 @@ M: Tyrone Ting <kfting@nuvoton.com>
 L: qemu-arm@nongnu.org
 S: Supported
 F: hw/misc/npcm7xx*
+F: hw/timer/npcm7xx*
 F: include/hw/misc/npcm7xx*
+F: include/hw/timer/npcm7xx*
 
 nSeries
 M: Andrzej Zaborowski <balrogg@gmail.com>
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index dece235fd7..6ea6d644ad 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -14,6 +14,7 @@ common-obj-$(CONFIG_IMX) += imx_epit.o
 common-obj-$(CONFIG_IMX) += imx_gpt.o
 common-obj-$(CONFIG_LM32) += lm32_timer.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
+common-obj-$(CONFIG_NPCM7XX) += npcm7xx_timer.o
 common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o
 
 common-obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
new file mode 100644
index 0000000000..7e3a2a170a
--- /dev/null
+++ b/hw/timer/npcm7xx_timer.c
@@ -0,0 +1,437 @@
+/*
+ * Nuvoton NPCM7xx Timer Controller
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/irq.h"
+#include "hw/timer/npcm7xx_timer.h"
+#include "qemu/bitops.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/timer.h"
+#include "qemu/units.h"
+#include "trace.h"
+
+/* Register field definitions. */
+#define NPCM7XX_TCSR_CEN                BIT(30)
+#define NPCM7XX_TCSR_IE                 BIT(29)
+#define NPCM7XX_TCSR_PERIODIC           BIT(27)
+#define NPCM7XX_TCSR_CRST               BIT(26)
+#define NPCM7XX_TCSR_CACT               BIT(25)
+#define NPCM7XX_TCSR_RSVD               0x21ffff00
+#define NPCM7XX_TCSR_PRESCALE_START     0
+#define NPCM7XX_TCSR_PRESCALE_LEN       8
+
+/* The reference clock frequency is always 25 MHz. */
+#define NPCM7XX_TIMER_REF_HZ            (25000000)
+
+/* Return the value by which to divide the reference clock rate. */
+static uint32_t npcm7xx_timer_prescaler(const NPCM7xxTimer *t)
+{
+    return extract32(t->tcsr, NPCM7XX_TCSR_PRESCALE_START,
+                     NPCM7XX_TCSR_PRESCALE_LEN) + 1;
+}
+
+/* Convert a timer cycle count to a time interval in nanoseconds. */
+static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
+{
+    int64_t ns = count;
+
+    ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
+    ns *= npcm7xx_timer_prescaler(t);
+
+    return ns;
+}
+
+/* Convert a time interval in nanoseconds to a timer cycle count. */
+static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
+{
+    int64_t count;
+
+    count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
+    count /= npcm7xx_timer_prescaler(t);
+
+    return count;
+}
+
+/*
+ * Raise the interrupt line if there's a pending interrupt and interrupts are
+ * enabled for this timer. If not, lower it.
+ */
+static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
+{
+    NPCM7xxTimerCtrlState *tc = t->ctrl;
+    /* Find the array index of this timer. */
+    int index = t - tc->timer;
+
+    g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL);
+
+    if ((t->tcsr & NPCM7XX_TCSR_IE) && (tc->tisr & BIT(index))) {
+        qemu_irq_raise(t->irq);
+        trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, 1);
+    } else {
+        qemu_irq_lower(t->irq);
+        trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, 0);
+    }
+}
+
+/* Start or resume the timer. */
+static void npcm7xx_timer_start(NPCM7xxTimer *t)
+{
+    int64_t now;
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    t->expires_ns = now + t->remaining_ns;
+    timer_mod(&t->qtimer, t->expires_ns);
+}
+
+/*
+ * Called when the counter reaches zero. Sets the interrupt flag, and either
+ * restarts or disables the timer.
+ */
+static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
+{
+    NPCM7xxTimerCtrlState *tc = t->ctrl;
+    int index = t - tc->timer;
+
+    g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL);
+
+    tc->tisr |= BIT(index);
+
+    if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
+        t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
+        if (t->tcsr & NPCM7XX_TCSR_CEN) {
+            npcm7xx_timer_start(t);
+        }
+    } else {
+        t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
+    }
+
+    npcm7xx_timer_check_interrupt(t);
+}
+
+/* Stop counting. Record the time remaining so we can continue later. */
+static void npcm7xx_timer_pause(NPCM7xxTimer *t)
+{
+    int64_t now;
+
+    timer_del(&t->qtimer);
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    t->remaining_ns = t->expires_ns - now;
+    if (t->remaining_ns <= 0) {
+        npcm7xx_timer_reached_zero(t);
+    }
+}
+
+/*
+ * Restart the timer from its initial value. If the timer was enabled and stays
+ * enabled, adjust the QEMU timer according to the new count. If the timer is
+ * transitioning from disabled to enabled, the caller is expected to start the
+ * timer later.
+ */
+static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
+{
+    t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
+
+    if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
+        npcm7xx_timer_start(t);
+    }
+}
+
+/* Register read and write handlers */
+
+static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
+{
+    uint32_t old_tcsr = t->tcsr;
+
+    if (new_tcsr & NPCM7XX_TCSR_RSVD) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits in 0x%08x ignored\n",
+                      __func__, new_tcsr);
+        new_tcsr &= ~NPCM7XX_TCSR_RSVD;
+    }
+    if (new_tcsr & NPCM7XX_TCSR_CACT) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only bits in 0x%08x ignored\n",
+                      __func__, new_tcsr);
+        new_tcsr &= ~NPCM7XX_TCSR_CACT;
+    }
+
+    t->tcsr = (t->tcsr & NPCM7XX_TCSR_CACT) | new_tcsr;
+
+    if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_IE) {
+        npcm7xx_timer_check_interrupt(t);
+    }
+    if (new_tcsr & NPCM7XX_TCSR_CRST) {
+        npcm7xx_timer_restart(t, old_tcsr);
+        t->tcsr &= ~NPCM7XX_TCSR_CRST;
+    }
+    if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
+        if (new_tcsr & NPCM7XX_TCSR_CEN) {
+            npcm7xx_timer_start(t);
+        } else {
+            npcm7xx_timer_pause(t);
+        }
+    }
+}
+
+static void npcm7xx_timer_write_ticr(NPCM7xxTimer *t, uint32_t new_ticr)
+{
+    t->ticr = new_ticr;
+
+    npcm7xx_timer_restart(t, t->tcsr);
+}
+
+static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
+{
+    if (t->tcsr & NPCM7XX_TCSR_CEN) {
+        int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+        return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
+    }
+
+    return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
+}
+
+static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
+{
+    NPCM7xxTimerCtrlState *s = opaque;
+    uint64_t value = 0;
+    hwaddr reg;
+
+    reg = offset / sizeof(uint32_t);
+    switch (reg) {
+    case NPCM7XX_TIMER_TCSR0:
+        value = s->timer[0].tcsr;
+        break;
+    case NPCM7XX_TIMER_TCSR1:
+        value = s->timer[1].tcsr;
+        break;
+    case NPCM7XX_TIMER_TCSR2:
+        value = s->timer[2].tcsr;
+        break;
+    case NPCM7XX_TIMER_TCSR3:
+        value = s->timer[3].tcsr;
+        break;
+    case NPCM7XX_TIMER_TCSR4:
+        value = s->timer[4].tcsr;
+        break;
+
+    case NPCM7XX_TIMER_TICR0:
+        value = s->timer[0].ticr;
+        break;
+    case NPCM7XX_TIMER_TICR1:
+        value = s->timer[1].ticr;
+        break;
+    case NPCM7XX_TIMER_TICR2:
+        value = s->timer[2].ticr;
+        break;
+    case NPCM7XX_TIMER_TICR3:
+        value = s->timer[3].ticr;
+        break;
+    case NPCM7XX_TIMER_TICR4:
+        value = s->timer[4].ticr;
+        break;
+
+    case NPCM7XX_TIMER_TDR0:
+        value = npcm7xx_timer_read_tdr(&s->timer[0]);
+        break;
+    case NPCM7XX_TIMER_TDR1:
+        value = npcm7xx_timer_read_tdr(&s->timer[1]);
+        break;
+    case NPCM7XX_TIMER_TDR2:
+        value = npcm7xx_timer_read_tdr(&s->timer[2]);
+        break;
+    case NPCM7XX_TIMER_TDR3:
+        value = npcm7xx_timer_read_tdr(&s->timer[3]);
+        break;
+    case NPCM7XX_TIMER_TDR4:
+        value = npcm7xx_timer_read_tdr(&s->timer[4]);
+        break;
+
+    case NPCM7XX_TIMER_TISR:
+        value = s->tisr;
+        break;
+
+    case NPCM7XX_TIMER_WTCR:
+        value = s->wtcr;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid offset 0x%04x\n",
+                      __func__, (unsigned int)offset);
+        break;
+    }
+
+    trace_npcm7xx_timer_read(DEVICE(s)->canonical_path, offset, value);
+
+    return value;
+}
+
+static void npcm7xx_timer_write(void *opaque, hwaddr offset,
+                                uint64_t v, unsigned size)
+{
+    uint32_t reg = offset / sizeof(uint32_t);
+    NPCM7xxTimerCtrlState *s = opaque;
+    uint32_t value = v;
+
+    trace_npcm7xx_timer_write(DEVICE(s)->canonical_path, offset, value);
+
+    switch (reg) {
+    case NPCM7XX_TIMER_TCSR0:
+        npcm7xx_timer_write_tcsr(&s->timer[0], value);
+        return;
+    case NPCM7XX_TIMER_TCSR1:
+        npcm7xx_timer_write_tcsr(&s->timer[1], value);
+        return;
+    case NPCM7XX_TIMER_TCSR2:
+        npcm7xx_timer_write_tcsr(&s->timer[2], value);
+        return;
+    case NPCM7XX_TIMER_TCSR3:
+        npcm7xx_timer_write_tcsr(&s->timer[3], value);
+        return;
+    case NPCM7XX_TIMER_TCSR4:
+        npcm7xx_timer_write_tcsr(&s->timer[4], value);
+        return;
+
+    case NPCM7XX_TIMER_TICR0:
+        npcm7xx_timer_write_ticr(&s->timer[0], value);
+        return;
+    case NPCM7XX_TIMER_TICR1:
+        npcm7xx_timer_write_ticr(&s->timer[1], value);
+        return;
+    case NPCM7XX_TIMER_TICR2:
+        npcm7xx_timer_write_ticr(&s->timer[2], value);
+        return;
+    case NPCM7XX_TIMER_TICR3:
+        npcm7xx_timer_write_ticr(&s->timer[3], value);
+        return;
+    case NPCM7XX_TIMER_TICR4:
+        npcm7xx_timer_write_ticr(&s->timer[4], value);
+        return;
+
+    case NPCM7XX_TIMER_TDR0:
+    case NPCM7XX_TIMER_TDR1:
+    case NPCM7XX_TIMER_TDR2:
+    case NPCM7XX_TIMER_TDR3:
+    case NPCM7XX_TIMER_TDR4:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is read-only\n",
+                      __func__, (unsigned int)offset);
+        return;
+
+    case NPCM7XX_TIMER_TISR:
+        s->tisr &= ~value;
+        return;
+
+    case NPCM7XX_TIMER_WTCR:
+        qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
+                      __func__, value);
+        return;
+    }
+
+    qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid offset 0x%04x\n",
+                  __func__, (unsigned int)offset);
+}
+
+static const struct MemoryRegionOps npcm7xx_timer_ops = {
+    .read       = npcm7xx_timer_read,
+    .write      = npcm7xx_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid      = {
+        .min_access_size        = 4,
+        .max_access_size        = 4,
+        .unaligned              = false,
+    },
+};
+
+/* Called when the QEMU timer expires. */
+static void npcm7xx_timer_expired(void *opaque)
+{
+    NPCM7xxTimer *t = opaque;
+
+    if (t->tcsr & NPCM7XX_TCSR_CEN) {
+        npcm7xx_timer_reached_zero(t);
+    }
+}
+
+static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
+{
+    NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
+    int i;
+
+    for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
+        NPCM7xxTimer *t = &s->timer[i];
+
+        timer_del(&t->qtimer);
+        t->expires_ns = 0;
+        t->remaining_ns = 0;
+        t->tcsr = 0x00000005;
+        t->ticr = 0x00000000;
+    }
+
+    s->tisr = 0x00000000;
+    s->wtcr = 0x00000400;
+}
+
+static void npcm7xx_timer_hold_reset(Object *obj)
+{
+    NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
+    int i;
+
+    for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
+        qemu_irq_lower(s->timer[i].irq);
+    }
+}
+
+static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
+{
+    NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
+    SysBusDevice *sbd = &s->parent;
+    int i;
+
+    for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
+        NPCM7xxTimer *t = &s->timer[i];
+        t->ctrl = s;
+        timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
+        sysbus_init_irq(sbd, &t->irq);
+    }
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
+                          TYPE_NPCM7XX_TIMER, 4 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "NPCM7xx Timer Controller";
+    dc->realize = npcm7xx_timer_realize;
+    rc->phases.enter = npcm7xx_timer_enter_reset;
+    rc->phases.hold = npcm7xx_timer_hold_reset;
+}
+
+static const TypeInfo npcm7xx_timer_info = {
+    .name               = TYPE_NPCM7XX_TIMER,
+    .parent             = TYPE_SYS_BUS_DEVICE,
+    .instance_size      = sizeof(NPCM7xxTimerCtrlState),
+    .class_init         = npcm7xx_timer_class_init,
+};
+
+static void npcm7xx_timer_register_type(void)
+{
+    type_register_static(&npcm7xx_timer_info);
+}
+type_init(npcm7xx_timer_register_type);
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 80ea197594..ee5a47c154 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -66,6 +66,11 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
 cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
 
+# npcm7xx_timer.c
+npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
+npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
+npcm7xx_timer_irq(const char *id, int timer, int state) "%s timer %d state %d"
+
 # nrf51_timer.c
 nrf51_timer_read(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
 nrf51_timer_write(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size) "timer %u write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
new file mode 100644
index 0000000000..d8ed98933d
--- /dev/null
+++ b/include/hw/timer/npcm7xx_timer.h
@@ -0,0 +1,95 @@
+/*
+ * Nuvoton NPCM7xx Timer Controller
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 NPCM7XX_TIMER_H
+#define NPCM7XX_TIMER_H
+
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+
+/* Each Timer Module (TIM) instance holds five 25 MHz timers. */
+#define NPCM7XX_TIMERS_PER_CTRL (5)
+
+/**
+ * enum NPCM7xxTimerRegisters - 32-bit register indices.
+ */
+enum NPCM7xxTimerRegisters {
+    NPCM7XX_TIMER_TCSR0,
+    NPCM7XX_TIMER_TCSR1,
+    NPCM7XX_TIMER_TICR0,
+    NPCM7XX_TIMER_TICR1,
+    NPCM7XX_TIMER_TDR0,
+    NPCM7XX_TIMER_TDR1,
+    NPCM7XX_TIMER_TISR,
+    NPCM7XX_TIMER_WTCR,
+    NPCM7XX_TIMER_TCSR2,
+    NPCM7XX_TIMER_TCSR3,
+    NPCM7XX_TIMER_TICR2,
+    NPCM7XX_TIMER_TICR3,
+    NPCM7XX_TIMER_TDR2,
+    NPCM7XX_TIMER_TDR3,
+    NPCM7XX_TIMER_TCSR4         = 0x0040 / sizeof(uint32_t),
+    NPCM7XX_TIMER_TICR4         = 0x0048 / sizeof(uint32_t),
+    NPCM7XX_TIMER_TDR4          = 0x0050 / sizeof(uint32_t),
+    NPCM7XX_TIMER_NR_REGS,
+};
+
+typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState;
+
+/**
+ * struct NPCM7xxTimer - Individual timer state.
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
+ * @qtimer: QEMU timer that notifies us on expiration.
+ * @expires_ns: Absolute virtual expiration time.
+ * @remaining_ns: Remaining time until expiration if timer is paused.
+ * @tcsr: The Timer Control and Status Register.
+ * @ticr: The Timer Initial Count Register.
+ */
+typedef struct NPCM7xxTimer {
+    NPCM7xxTimerCtrlState *ctrl;
+
+    qemu_irq    irq;
+    QEMUTimer   qtimer;
+    int64_t     expires_ns;
+    int64_t     remaining_ns;
+
+    uint32_t    tcsr;
+    uint32_t    ticr;
+} NPCM7xxTimer;
+
+/**
+ * struct NPCM7xxTimerCtrlState - Timer Module device state.
+ * @parent: System bus device.
+ * @iomem: Memory region through which registers are accessed.
+ * @tisr: The Timer Interrupt Status Register.
+ * @wtcr: The Watchdog Timer Control Register.
+ * @timer: The five individual timers managed by this module.
+ */
+struct NPCM7xxTimerCtrlState {
+    SysBusDevice parent;
+
+    MemoryRegion iomem;
+
+    uint32_t    tisr;
+    uint32_t    wtcr;
+
+    NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
+};
+
+#define TYPE_NPCM7XX_TIMER "npcm7xx-timer"
+#define NPCM7XX_TIMER(obj)                                              \
+    OBJECT_CHECK(NPCM7xxTimerCtrlState, (obj), TYPE_NPCM7XX_TIMER)
+
+#endif /* NPCM7XX_TIMER_H */
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
                   ` (3 preceding siblings ...)
  2020-05-21 19:21 ` [PATCH 4/6] hw/timer: Add NPCM7xx Timer " Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  2020-05-21 19:21 ` [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines Havard Skinnemoen
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

The Nuvoton NPCM7xx SoC family are used to implement Baseboard
Management Controllers in servers. While the family includes four SoCs,
this patch implements limited support for two of them: NPCM730 (targeted
for Data Center applications) and NPCM750 (targeted for Enterprise
applications).

This patch includes little more than the bare minimum needed to boot a
Linux kernel built with NPCM7xx support in direct-kernel mode:

  - Two Cortex-A9 CPU cores with built-in periperhals.
  - Global Configuration Registers.
  - Clock Management.
  - 3 Timer Modules with 5 timers each.
  - 4 serial ports.

The chips themselves have a lot more features, some of which will be
added to the model at a later stage.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 MAINTAINERS              |   2 +
 hw/arm/Makefile.objs     |   1 +
 hw/arm/npcm7xx.c         | 328 +++++++++++++++++++++++++++++++++++++++
 include/hw/arm/npcm7xx.h |  79 ++++++++++
 4 files changed, 410 insertions(+)
 create mode 100644 hw/arm/npcm7xx.c
 create mode 100644 include/hw/arm/npcm7xx.h

diff --git a/MAINTAINERS b/MAINTAINERS
index c9a59a2c10..9c526af784 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -720,8 +720,10 @@ M: Havard Skinnemoen <hskinnemoen@google.com>
 M: Tyrone Ting <kfting@nuvoton.com>
 L: qemu-arm@nongnu.org
 S: Supported
+F: hw/arm/npcm7xx*
 F: hw/misc/npcm7xx*
 F: hw/timer/npcm7xx*
+F: include/hw/arm/npcm7xx*
 F: include/hw/misc/npcm7xx*
 F: include/hw/timer/npcm7xx*
 
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 534a6a119e..13d163a599 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -41,6 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
 obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
+obj-$(CONFIG_NPCM7XX) += npcm7xx.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
 obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
 obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
new file mode 100644
index 0000000000..3d88615634
--- /dev/null
+++ b/hw/arm/npcm7xx.c
@@ -0,0 +1,328 @@
+/*
+ * Nuvoton NPCM7xx SoC family.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+
+#include "exec/address-spaces.h"
+#include "hw/arm/npcm7xx.h"
+#include "hw/char/serial.h"
+#include "hw/loader.h"
+#include "hw/misc/unimp.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/units.h"
+#include "sysemu/sysemu.h"
+
+/* The first half of the address space is reserved for DDR4 DRAM. */
+#define NPCM7XX_DRAM_BA         (0x00000000)
+#define NPCM7XX_DRAM_SZ         (2 * GiB)
+
+/*
+ * This covers the whole MMIO space. We'll use this to catch any MMIO accesses
+ * that aren't handled by any device.
+ */
+#define NPCM7XX_MMIO_BA         (0x80000000)
+#define NPCM7XX_MMIO_SZ         (0x7FFD0000)
+
+/* Core system modules. */
+#define NPCM7XX_L2C_BA          (0xF03FC000)
+#define NPCM7XX_CPUP_BA         (0xF03FE000)
+#define NPCM7XX_GCR_BA          (0xF0800000)
+#define NPCM7XX_CLK_BA          (0xF0801000)
+
+/* Memory blocks at the end of the address space */
+#define NPCM7XX_RAM2_BA         (0xFFFD0000)
+#define NPCM7XX_RAM2_SZ         (128 * KiB)
+#define NPCM7XX_ROM_BA          (0xFFFF0000)
+#define NPCM7XX_ROM_SZ          (64 * KiB)
+
+/*
+ * Interrupt lines going into the GIC. This does not include internal Cortex-A9
+ * interrupts.
+ */
+enum NPCM7xxInterrupt {
+    NPCM7XX_UART0_IRQ           = 2,
+    NPCM7XX_UART1_IRQ,
+    NPCM7XX_UART2_IRQ,
+    NPCM7XX_UART3_IRQ,
+    NPCM7XX_TIMER0_IRQ          = 32,   /* Timer Module 0 */
+    NPCM7XX_TIMER1_IRQ,
+    NPCM7XX_TIMER2_IRQ,
+    NPCM7XX_TIMER3_IRQ,
+    NPCM7XX_TIMER4_IRQ,
+    NPCM7XX_TIMER5_IRQ,                 /* Timer Module 1 */
+    NPCM7XX_TIMER6_IRQ,
+    NPCM7XX_TIMER7_IRQ,
+    NPCM7XX_TIMER8_IRQ,
+    NPCM7XX_TIMER9_IRQ,
+    NPCM7XX_TIMER10_IRQ,                /* Timer Module 2 */
+    NPCM7XX_TIMER11_IRQ,
+    NPCM7XX_TIMER12_IRQ,
+    NPCM7XX_TIMER13_IRQ,
+    NPCM7XX_TIMER14_IRQ,
+};
+
+/* Register base address for each Timer Module */
+static const hwaddr npcm7xx_tim_addr[] = {
+    0xF0008000,
+    0xF0009000,
+    0xF000A000,
+};
+
+/* Register base address for each 16550 UART */
+static const hwaddr npcm7xx_uart_addr[] = {
+    0xF0001000,
+    0xF0002000,
+    0xF0003000,
+    0xF0004000,
+};
+
+void npcm7xx_write_secondary_boot(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+    /*
+     * The default smpboot stub halts the secondary CPU with a 'wfi'
+     * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel
+     * does not send an IPI to wake it up, so the second CPU fails to boot. So
+     * we need to provide our own smpboot stub that can not use 'wfi', it has
+     * to spin the secondary CPU until the first CPU writes to the SCRPAD reg.
+     */
+    uint32_t smpboot[] = {
+        0xe59f2018,     /* ldr r2, bootreg_addr */
+        0xe3a00000,     /* mov r0, #0 */
+        0xe5820000,     /* str r0, [r2] */
+        0xe320f002,     /* wfe */
+        0xe5921000,     /* ldr r1, [r2] */
+        0xe1110001,     /* tst r1, r1 */
+        0x0afffffb,     /* beq <wfe> */
+        0xe12fff11,     /* bx r1 */
+        NPCM7XX_SMP_BOOTREG_ADDR,
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(smpboot); i++) {
+        smpboot[i] = tswap32(smpboot[i]);
+    }
+
+    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+                       NPCM7XX_SMP_LOADER_START);
+}
+
+static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
+{
+    return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
+}
+
+static void npcm7xx_init(Object *obj)
+{
+    NPCM7xxState *s = NPCM7XX(obj);
+    int i;
+
+    for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
+        s->cpu[i] = ARM_CPU(
+            object_new_with_props(ARM_CPU_TYPE_NAME("cortex-a9"),
+                                  obj, "cpu[*]", &error_abort, NULL));
+    }
+
+    sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore,
+                          sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV);
+    sysbus_init_child_obj(obj, "gcr", OBJECT(&s->gcr), sizeof(s->gcr),
+                          TYPE_NPCM7XX_GCR);
+    sysbus_init_child_obj(obj, "clk", OBJECT(&s->clk), sizeof(s->clk),
+                          TYPE_NPCM7XX_CLK);
+
+    for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
+        sysbus_init_child_obj(obj, "tim[*]", OBJECT(&s->tim[i]),
+                              sizeof(s->tim[i]), TYPE_NPCM7XX_TIMER);
+    }
+}
+
+static void npcm7xx_realize(DeviceState *dev, Error **errp)
+{
+    NPCM7xxState *s = NPCM7XX(dev);
+    NPCM7xxClass *sc = NPCM7XX_GET_CLASS(s);
+    Error *err = NULL;
+    int i;
+
+    /* I/O space -- unimplemented unless overridden below. */
+    create_unimplemented_device("npcm7xx.io", NPCM7XX_MMIO_BA, NPCM7XX_MMIO_SZ);
+
+    /* CPUs */
+    if (s->num_cpus > NPCM7XX_MAX_NUM_CPUS) {
+        warn_report("%s: invalid number of CPUs %d, using maximum %d",
+                    object_get_typename(OBJECT(s)), s->num_cpus,
+                    NPCM7XX_MAX_NUM_CPUS);
+        s->num_cpus = NPCM7XX_MAX_NUM_CPUS;
+    }
+
+    for (i = 0; i < s->num_cpus; i++) {
+        object_property_set_int(OBJECT(s->cpu[i]),
+                                arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS),
+                                "mp-affinity", &error_abort);
+        object_property_set_int(OBJECT(s->cpu[i]), NPCM7XX_GIC_CPU_IF_ADDR,
+                                "reset-cbar", &error_abort);
+        object_property_set_bool(OBJECT(s->cpu[i]), true,
+                                 "reset-hivecs", &error_abort);
+
+        /* TODO: Not sure why this is needed. */
+        if (object_property_find(OBJECT(s->cpu[i]), "has_el3", NULL)) {
+            object_property_set_bool(OBJECT(s->cpu[i]), false, "has_el3",
+                                     &error_abort);
+        }
+
+        object_property_set_bool(OBJECT(s->cpu[i]), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+    }
+
+    /* A9MPCORE peripherals */
+    object_property_set_int(OBJECT(&s->a9mpcore), s->num_cpus, "num-cpu",
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->a9mpcore), 160, "num-irq", &error_abort);
+    object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized",
+                             &error_abort);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA);
+
+    for (i = 0; i < s->num_cpus; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
+                           qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + s->num_cpus,
+                           qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_FIQ));
+    }
+
+    /* L2 cache controller */
+    sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL);
+
+    /* System Global Control Registers (GCR) */
+    object_property_set_int(OBJECT(&s->gcr), sc->disabled_modules,
+                            "disabled-modules", &err);
+    object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA);
+
+    /* Clock Control Registers (CLK) */
+    object_property_set_bool(OBJECT(&s->clk), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA);
+
+    /* Timer Modules (TIM) */
+    QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
+    for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
+        Object *t = OBJECT(&s->tim[i]);
+        int first_irq;
+        int j;
+
+        object_property_set_bool(t, true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        sysbus_mmio_map(SYS_BUS_DEVICE(t), 0, npcm7xx_tim_addr[i]);
+
+        first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL;
+        for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) {
+            qemu_irq irq = npcm7xx_irq(s, first_irq + j);
+            sysbus_connect_irq(SYS_BUS_DEVICE(t), j, irq);
+        }
+    }
+
+    /* UART0..3 (16550 compatible) */
+    for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) {
+        serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2,
+                       npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200,
+                       serial_hd(i), DEVICE_LITTLE_ENDIAN);
+    }
+
+    /* RAM2 (SRAM) */
+    memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
+                           NPCM7XX_RAM2_SZ, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram);
+
+    /* Internal ROM */
+    memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
+
+    /* External DDR4 SDRAM */
+    memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, s->dram);
+}
+
+static Property npcm7xx_properties[] = {
+    DEFINE_PROP_INT32("num-cpus", NPCM7xxState, num_cpus, -1),
+    DEFINE_PROP_LINK("dram", NPCM7xxState, dram, TYPE_MEMORY_REGION,
+                     MemoryRegion *),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void npcm7xx_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = npcm7xx_realize;
+    dc->user_creatable = false;
+    device_class_set_props(dc, npcm7xx_properties);
+}
+
+static void npcm730_class_init(ObjectClass *oc, void *data)
+{
+    NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
+
+    /* NPCM730 is optimized for data center use, so no graphics, etc. */
+    nc->disabled_modules = 0x00300395;
+}
+
+static void npcm750_class_init(ObjectClass *oc, void *data)
+{
+    NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
+
+    /* NPCM750 has everything */
+    nc->disabled_modules = 0x00000000;
+}
+
+static const TypeInfo npcm7xx_soc_types[] = {
+    {
+        .name           = TYPE_NPCM7XX,
+        .parent         = TYPE_DEVICE,
+        .instance_size  = sizeof(NPCM7xxState),
+        .instance_init  = npcm7xx_init,
+        .class_size     = sizeof(NPCM7xxClass),
+        .class_init     = npcm7xx_class_init,
+        .abstract       = true,
+    }, {
+        .name           = TYPE_NPCM730,
+        .parent         = TYPE_NPCM7XX,
+        .class_init     = npcm730_class_init,
+    }, {
+        .name           = TYPE_NPCM750,
+        .parent         = TYPE_NPCM7XX,
+        .class_init     = npcm750_class_init,
+    },
+};
+
+DEFINE_TYPES(npcm7xx_soc_types);
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
new file mode 100644
index 0000000000..0a8798dd24
--- /dev/null
+++ b/include/hw/arm/npcm7xx.h
@@ -0,0 +1,79 @@
+/*
+ * Nuvoton NPCM7xx SoC family.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 NPCM7XX_H
+#define NPCM7XX_H
+
+#include "hw/boards.h"
+#include "hw/cpu/a9mpcore.h"
+#include "hw/misc/npcm7xx_clk.h"
+#include "hw/misc/npcm7xx_gcr.h"
+#include "hw/timer/npcm7xx_timer.h"
+#include "target/arm/cpu.h"
+
+#define NPCM7XX_MAX_NUM_CPUS    (2)
+
+/* Magic addresses for setting up direct kernel booting and SMP boot stubs. */
+#define NPCM7XX_LOADER_START            (0x00000000)  /* Start of SDRAM */
+#define NPCM7XX_SMP_LOADER_START        (0xFFFF0000)  /* Boot ROM */
+#define NPCM7XX_SMP_BOOTREG_ADDR        (0xF080013C)  /* GCR.SCRPAD */
+#define NPCM7XX_GIC_CPU_IF_ADDR         (0xF03FE100)  /* GIC within A9 */
+
+typedef struct NPCM7xxState {
+    DeviceState         parent;
+
+    ARMCPU              *cpu[NPCM7XX_MAX_NUM_CPUS];
+    A9MPPrivState       a9mpcore;
+    int32_t             num_cpus;
+
+    MemoryRegion        sram;
+    MemoryRegion        irom;
+    MemoryRegion        *dram;
+
+    NPCM7xxGCRState     gcr;
+    NPCM7xxCLKState     clk;
+    NPCM7xxTimerCtrlState tim[3];
+} NPCM7xxState;
+
+#define TYPE_NPCM7XX    "npcm7xx"
+#define NPCM7XX(obj)    OBJECT_CHECK(NPCM7xxState, (obj), TYPE_NPCM7XX)
+
+#define TYPE_NPCM730    "npcm730"
+#define TYPE_NPCM750    "npcm750"
+
+typedef struct NPCM7xxClass {
+    DeviceClass         parent;
+
+    /* Bitmask of modules that are permanently disabled on this chip. */
+    uint32_t            disabled_modules;
+} NPCM7xxClass;
+
+#define NPCM7XX_CLASS(klass)                                            \
+    OBJECT_CLASS_CHECK(NPCM7xxClass, (klass), TYPE_NPCM7XX)
+#define NPCM7XX_GET_CLASS(obj)                                          \
+    OBJECT_GET_CLASS(NPCM7xxClass, (obj), TYPE_NPCM7XX)
+
+/**
+ * npcm7xx_write_secondary_boot - Write stub for booting secondary CPU.
+ * @cpu: The CPU to be booted.
+ * @info: Boot info structure for the board.
+ *
+ * This will write a short code stub to the internal ROM that will keep the
+ * secondary CPU spinning until the primary CPU writes an address to the SCRPAD
+ * register in the GCR, after which the secondary CPU will jump there.
+ */
+extern void npcm7xx_write_secondary_boot(ARMCPU *cpu,
+                                         const struct arm_boot_info *info);
+
+#endif /* NPCM7XX_H */
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
                   ` (4 preceding siblings ...)
  2020-05-21 19:21 ` [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models Havard Skinnemoen
@ 2020-05-21 19:21 ` Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  2020-05-22  4:57 ` [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines no-reply
  2020-06-08 22:14 ` Havard Skinnemoen
  7 siblings, 2 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-05-21 19:21 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-arm, qemu-devel, Avi.Fishman, kfting, Havard Skinnemoen

This adds two new machines:

  - npcm750-evb: Nuvoton NPCM750 Evaluation Board.
  - quanta-gsj: A board with a NPCM730 chip.

They rely on the NPCM7xx SoC device to do the heavy lifting. They are
almost completely identical at the moment, apart from the SoC type,
which currently only changes the reset contents of one register
(GCR.MDLR), but they might grow apart a bit more as more functionality
is added.

Both machines can boot the Linux kernel into /bin/sh.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
---
 hw/arm/Makefile.objs     |   2 +-
 hw/arm/npcm7xx_boards.c  | 108 +++++++++++++++++++++++++++++++++++++++
 include/hw/arm/npcm7xx.h |  19 +++++++
 3 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/npcm7xx_boards.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 13d163a599..c333548ce1 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -41,7 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
 obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
-obj-$(CONFIG_NPCM7XX) += npcm7xx.o
+obj-$(CONFIG_NPCM7XX) += npcm7xx.o npcm7xx_boards.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
 obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
 obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
new file mode 100644
index 0000000000..b89819f6e2
--- /dev/null
+++ b/hw/arm/npcm7xx_boards.c
@@ -0,0 +1,108 @@
+/*
+ * Machine definitions for boards featuring an NPCM7xx SoC.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/arm/boot.h"
+#include "hw/arm/npcm7xx.h"
+#include "hw/core/cpu.h"
+#include "qapi/error.h"
+#include "qemu/units.h"
+
+static struct arm_boot_info npcm7xx_binfo = {
+    .loader_start       = NPCM7XX_LOADER_START,
+    .smp_loader_start   = NPCM7XX_SMP_LOADER_START,
+    .smp_bootreg_addr   = NPCM7XX_SMP_BOOTREG_ADDR,
+    .gic_cpu_if_addr    = NPCM7XX_GIC_CPU_IF_ADDR,
+    .write_secondary_boot = npcm7xx_write_secondary_boot,
+    .board_id           = -1,
+};
+
+static void npcm7xx_machine_init(MachineState *machine)
+{
+    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
+    NPCM7xxState *soc;
+
+    soc = NPCM7XX(object_new_with_props(nmc->soc_type, OBJECT(machine), "soc",
+                                        &error_abort, NULL));
+    object_property_set_int(OBJECT(soc), machine->smp.cpus, "num-cpus",
+                            &error_abort);
+    object_property_set_link(OBJECT(soc), OBJECT(machine->ram), "dram",
+                             &error_abort);
+    object_property_set_bool(OBJECT(soc), true, "realized", &error_abort);
+
+    npcm7xx_binfo.ram_size = machine->ram_size;
+    npcm7xx_binfo.nb_cpus = machine->smp.cpus;
+
+    arm_load_kernel(soc->cpu[0], machine, &npcm7xx_binfo);
+}
+
+static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->init            = npcm7xx_machine_init;
+    mc->max_cpus        = NPCM7XX_MAX_NUM_CPUS;
+    mc->default_cpus    = NPCM7XX_MAX_NUM_CPUS;
+    mc->no_floppy       = 1;
+    mc->no_cdrom        = 1;
+    mc->no_parallel     = 1;
+    mc->default_ram_id  = "ram";
+}
+
+/*
+ * Schematics:
+ * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
+ */
+static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
+{
+    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc            = "Nuvoton NPCM750 Evaluation Board (Cortex A9)";
+    nmc->soc_type       = TYPE_NPCM750;
+    mc->default_ram_size = 512 * MiB;
+};
+
+static void gsj_machine_class_init(ObjectClass *oc, void *data)
+{
+    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc            = "Quanta GSJ (Cortex A9)";
+    nmc->soc_type       = TYPE_NPCM730;
+    mc->default_ram_size = 512 * MiB;
+};
+
+static const TypeInfo npcm7xx_machine_types[] = {
+    {
+        .name           = TYPE_NPCM7XX_MACHINE,
+        .parent         = TYPE_MACHINE,
+        .instance_size  = sizeof(NPCM7xxMachine),
+        .class_size     = sizeof(NPCM7xxMachineClass),
+        .class_init     = npcm7xx_machine_class_init,
+        .abstract       = true,
+    }, {
+        .name           = MACHINE_TYPE_NAME("npcm750-evb"),
+        .parent         = TYPE_NPCM7XX_MACHINE,
+        .class_init     = npcm750_evb_machine_class_init,
+    }, {
+        .name           = MACHINE_TYPE_NAME("quanta-gsj"),
+        .parent         = TYPE_NPCM7XX_MACHINE,
+        .class_init     = gsj_machine_class_init,
+    },
+};
+
+DEFINE_TYPES(npcm7xx_machine_types)
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index 0a8798dd24..c1a108e89a 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -30,6 +30,25 @@
 #define NPCM7XX_SMP_BOOTREG_ADDR        (0xF080013C)  /* GCR.SCRPAD */
 #define NPCM7XX_GIC_CPU_IF_ADDR         (0xF03FE100)  /* GIC within A9 */
 
+typedef struct NPCM7xxMachine {
+    MachineState        parent;
+} NPCM7xxMachine;
+
+#define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx")
+#define NPCM7XX_MACHINE(obj)                                            \
+    OBJECT_CHECK(NPCM7xxMachine, (obj), TYPE_NPCM7XX_MACHINE)
+
+typedef struct NPCM7xxMachineClass {
+    MachineClass        parent;
+
+    const char          *soc_type;
+} NPCM7xxMachineClass;
+
+#define NPCM7XX_MACHINE_CLASS(klass)                                    \
+    OBJECT_CLASS_CHECK(NPCM7xxMachineClass, (klass), TYPE_NPCM7XX_MACHINE)
+#define NPCM7XX_MACHINE_GET_CLASS(obj)                                  \
+    OBJECT_GET_CLASS(NPCM7xxMachineClass, (obj), TYPE_NPCM7XX_MACHINE)
+
 typedef struct NPCM7xxState {
     DeviceState         parent;
 
-- 
2.27.0.rc0.183.gde8f92d652-goog



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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
                   ` (5 preceding siblings ...)
  2020-05-21 19:21 ` [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines Havard Skinnemoen
@ 2020-05-22  4:57 ` no-reply
  2020-06-08 22:14 ` Havard Skinnemoen
  7 siblings, 0 replies; 28+ messages in thread
From: no-reply @ 2020-05-22  4:57 UTC (permalink / raw)
  To: hskinnemoen
  Cc: peter.maydell, hskinnemoen, qemu-devel, kfting, qemu-arm, Avi.Fishman

Patchew URL: https://patchew.org/QEMU/20200521192133.127559-1-hskinnemoen@google.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===

Broken pipe
/tmp/qemu-test/src/tests/qtest/libqtest.c:166: kill_qemu() tried to terminate QEMU process but encountered exit status 1 (expected 0)
  TEST    iotest-qcow2: 089
ERROR - too few tests run (expected 68, got 21)
make: *** [check-qtest-aarch64] Error 1
make: *** Waiting for unfinished jobs....
  TEST    iotest-qcow2: 090
  TEST    iotest-qcow2: 097
---
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=935cc7f201a94a2e865cf081636a2cf4', '-u', '1001', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-evkby52n/src/docker-src.2020-05-22-00.39.52.17361:/var/tmp/qemu:z,ro', 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2.
filter=--filter=label=com.qemu.instance.uuid=935cc7f201a94a2e865cf081636a2cf4
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-evkby52n/src'
make: *** [docker-run-test-quick@centos7] Error 2

real    17m34.256s
user    0m9.006s


The full log is available at
http://patchew.org/logs/20200521192133.127559-1-hskinnemoen@google.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
                   ` (6 preceding siblings ...)
  2020-05-22  4:57 ` [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines no-reply
@ 2020-06-08 22:14 ` Havard Skinnemoen
  2020-06-09  1:39   ` Joel Stanley
  2020-06-09  7:31   ` Cédric Le Goater
  7 siblings, 2 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-06-08 22:14 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-arm, qemu-devel, IS20 Avi Fishman, CS20 KFTing

[-- Attachment #1: Type: text/plain, Size: 629 bytes --]

On Thu, May 21, 2020 at 12:21 PM Havard Skinnemoen <hskinnemoen@google.com>
wrote:

> This patch series models enough of the Nuvoton NPCM730 and NPCM750 SoCs to
> boot
> a minimal Linux kernel. This includes device models for:
>

Does anyone have comments on this series? I'm currently finishing up a
second patch series that adds flash support and a few other things so qemu
can boot a full OpenBMC flash image built for npcm7xx.

If you prefer, I can combine them both into one series and send it to the
list.

This series can be found here:
https://patchwork.kernel.org/project/qemu-devel/list/?series=291809

Thanks,

Havard

[-- Attachment #2: Type: text/html, Size: 1112 bytes --]

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

* Re: [PATCH 1/6] npcm7xx: Add config symbol
  2020-05-21 19:21 ` [PATCH 1/6] npcm7xx: Add config symbol Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  0 siblings, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:39, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> Add a config symbol for the NPCM7xx BMC SoC family that subsequent
> patches can use in Makefiles.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Acked-by: Joel Stanley <joel@jms.id.au>


> ---
>  default-configs/arm-softmmu.mak | 1 +
>  hw/arm/Kconfig                  | 8 ++++++++
>  2 files changed, 9 insertions(+)
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 8fc09a4a51..9a94ebd0be 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -27,6 +27,7 @@ CONFIG_GUMSTIX=y
>  CONFIG_SPITZ=y
>  CONFIG_TOSA=y
>  CONFIG_Z2=y
> +CONFIG_NPCM7XX=y
>  CONFIG_COLLIE=y
>  CONFIG_ASPEED_SOC=y
>  CONFIG_NETDUINO2=y
> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index 5364172537..47d0a3ca43 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -354,6 +354,14 @@ config XLNX_VERSAL
>      select VIRTIO_MMIO
>      select UNIMP
>
> +config NPCM7XX
> +    bool
> +    select A9MPCORE
> +    select ARM_GIC
> +    select PL310  # cache controller
> +    select SERIAL
> +    select UNIMP
> +
>  config FSL_IMX25
>      bool
>      select IMX
> --
> 2.27.0.rc0.183.gde8f92d652-goog
>
>


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

* Re: [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model
  2020-05-21 19:21 ` [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:40, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> Implement a device model for the System Global Control Registers in the
> NPCM730 and NPCM750 BMC SoCs.
>
> This is primarily used to enable SMP boot (the boot ROM spins reading
> the SCRPAD register); other registers are best effort for now.
>
> The reset values of the MDLR and PWRON registers are determined by the
> SoC variant (730 vs 750) and board straps respectively.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

This looks similar to the aspeed scu model :)

Reviewed-by: Joel Stanley <joel@jms.id.au>


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

* Re: [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller device model
  2020-05-21 19:21 ` [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller " Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:39, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> Enough functionality to boot the Linux kernel has been implemented. This
> includes:
>
>   - Correct power-on reset values so the various clock rates can be
>     accurately calculated.
>   - Clock enables stick around when written.
>
> In addition, a best effort attempt to implement SECCNT and CNTR25M was
> made even though I don't think the kernel needs them.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> +++ b/hw/misc/npcm7xx_clk.c

> +#define PLLCON_LOKI     BIT(31)
> +#define PLLCON_LOKS     BIT(30)
> +#define PLLCON_PWDEN    BIT(12)
> +
> +static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {

Can you add a comment to mention where these come from? If it's the
data sheet, note which version you're using.


> +    [NPCM7XX_CLK_CLKEN1]        = 0xffffffff,
> +    [NPCM7XX_CLK_CLKSEL]        = 0x004aaaaa,
> +    [NPCM7XX_CLK_CLKDIV1]       = 0x5413f855,
> +    [NPCM7XX_CLK_PLLCON0]       = 0x00222101 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_PLLCON1]       = 0x00202101 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_IPSRST1]       = 0x00001000,
> +    [NPCM7XX_CLK_IPSRST2]       = 0x80000000,
> +    [NPCM7XX_CLK_CLKEN2]        = 0xffffffff,
> +    [NPCM7XX_CLK_CLKDIV2]       = 0xaa4f8f9f,
> +    [NPCM7XX_CLK_CLKEN3]        = 0xffffffff,
> +    [NPCM7XX_CLK_IPSRST3]       = 0x03000000,
> +    [NPCM7XX_CLK_WD0RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_WD1RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_WD2RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_SWRSTC1]       = 0x00000003,
> +    [NPCM7XX_CLK_PLLCON2]       = 0x00c02105 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_CORSTC]        = 0x04000003,
> +    [NPCM7XX_CLK_PLLCONG]       = 0x01228606 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_AHBCKFI]       = 0x000000c8,
> +};


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

* Re: [PATCH 4/6] hw/timer: Add NPCM7xx Timer device model
  2020-05-21 19:21 ` [PATCH 4/6] hw/timer: Add NPCM7xx Timer " Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  0 siblings, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:38, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> The NPCM730 and NPCM750 SoCs have three timer modules each holding five
> timers and some shared registers (e.g. interrupt status).
>
> Each timer runs at 25 MHz divided by a prescaler, and counts down from a
> configurable initial value to zero. When zero is reached, the interrupt
> flag for the timer is set, and the timer is disabled (one-shot mode) or
> reloaded from its initial value (periodic mode).
>
> This implementation is sufficient to boot a Linux kernel configured for
> NPCM750. Note that the kernel does not seem to actually turn on the
> interrupts.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>


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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-05-21 19:21 ` [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen, Cédric Le Goater
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:39, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> The Nuvoton NPCM7xx SoC family are used to implement Baseboard
> Management Controllers in servers. While the family includes four SoCs,
> this patch implements limited support for two of them: NPCM730 (targeted
> for Data Center applications) and NPCM750 (targeted for Enterprise
> applications).
>
> This patch includes little more than the bare minimum needed to boot a
> Linux kernel built with NPCM7xx support in direct-kernel mode:
>
>   - Two Cortex-A9 CPU cores with built-in periperhals.
>   - Global Configuration Registers.
>   - Clock Management.
>   - 3 Timer Modules with 5 timers each.
>   - 4 serial ports.
>
> The chips themselves have a lot more features, some of which will be
> added to the model at a later stage.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

This looks okay from my perspective. You will want to get Cedric or
Peter to take a closer look though.

We have started adding about the systems that are supported by qemu,
including how to boot the machine, what is supported and the
limitations of the modelling. See docs/system/arm/aspeed.rst for an
example.

Reviewed-by: Joel Stanley <joel@jms.id.au>

Cheers,

Joel


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

* Re: [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines
  2020-05-21 19:21 ` [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines Havard Skinnemoen
@ 2020-06-09  1:36   ` Joel Stanley
  2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:36 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, qemu-arm, QEMU Developers, kfting, Avi Fishman

On Thu, 21 May 2020 at 20:39, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> This adds two new machines:
>
>   - npcm750-evb: Nuvoton NPCM750 Evaluation Board.
>   - quanta-gsj: A board with a NPCM730 chip.

You could note that these are the two boards supported by OpenBMC.

> They rely on the NPCM7xx SoC device to do the heavy lifting. They are
> almost completely identical at the moment, apart from the SoC type,
> which currently only changes the reset contents of one register
> (GCR.MDLR), but they might grow apart a bit more as more functionality
> is added.
>
> Both machines can boot the Linux kernel into /bin/sh.
>
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>


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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-06-08 22:14 ` Havard Skinnemoen
@ 2020-06-09  1:39   ` Joel Stanley
  2020-06-09 16:36     ` Havard Skinnemoen
  2020-06-09  7:31   ` Cédric Le Goater
  1 sibling, 1 reply; 28+ messages in thread
From: Joel Stanley @ 2020-06-09  1:39 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: Peter Maydell, QEMU Developers, CS20 KFTing, qemu-arm,
	Cédric Le Goater, IS20 Avi Fishman

On Mon, 8 Jun 2020 at 22:15, Havard Skinnemoen <hskinnemoen@google.com> wrote:
>
> On Thu, May 21, 2020 at 12:21 PM Havard Skinnemoen <hskinnemoen@google.com> wrote:
>>
>> This patch series models enough of the Nuvoton NPCM730 and NPCM750 SoCs to boot
>> a minimal Linux kernel. This includes device models for:
>
>
> Does anyone have comments on this series? I'm currently finishing up a second patch series that adds flash support and a few other things so qemu can boot a full OpenBMC flash image built for npcm7xx.

I had a look and they appear good to me. Note that I'm less in to the
gory details of Qemu than some of our other reviewers, so you should
seek  a more detailed review from someone else.

I look forward further support so I can test the OpenBMC kernel
against Nuvoton boards in the same way as the Aspeed ones.

Cheers,

Joel

>
> If you prefer, I can combine them both into one series and send it to the list.
>
> This series can be found here: https://patchwork.kernel.org/project/qemu-devel/list/?series=291809
>
> Thanks,
>
> Havard


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

* Re: [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model
  2020-05-21 19:21 ` [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
@ 2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-09  7:24 UTC (permalink / raw)
  To: Havard Skinnemoen, peter.maydell
  Cc: kfting, qemu-arm, qemu-devel, Avi.Fishman

On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
> Implement a device model for the System Global Control Registers in the
> NPCM730 and NPCM750 BMC SoCs.
> 
> This is primarily used to enable SMP boot (the boot ROM spins reading
> the SCRPAD register); other registers are best effort for now.
> 
> The reset values of the MDLR and PWRON registers are determined by the
> SoC variant (730 vs 750) and board straps respectively.
> 
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

It's nice to have header files on the top and I would have used a list of
#define for NPCM7xxGCRRegisters in npcm7xx_gcr.c. Anyhow :

Reviewed-by: Cédric Le Goater <clg@kaod.org>

C.


> ---
>  MAINTAINERS                   |   8 ++
>  hw/misc/Makefile.objs         |   1 +
>  hw/misc/npcm7xx_gcr.c         | 160 ++++++++++++++++++++++++++++++++++
>  hw/misc/trace-events          |   4 +
>  include/hw/misc/npcm7xx_gcr.h |  74 ++++++++++++++++
>  5 files changed, 247 insertions(+)
>  create mode 100644 hw/misc/npcm7xx_gcr.c
>  create mode 100644 include/hw/misc/npcm7xx_gcr.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 87a412c229..5b150184ab 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -715,6 +715,14 @@ S: Odd Fixes
>  F: hw/arm/musicpal.c
>  F: docs/system/arm/musicpal.rst
>  
> +Nuvoton NPCM7xx
> +M: Havard Skinnemoen <hskinnemoen@google.com>
> +M: Tyrone Ting <kfting@nuvoton.com>
> +L: qemu-arm@nongnu.org
> +S: Supported
> +F: hw/misc/npcm7xx*
> +F: include/hw/misc/npcm7xx*
> +
>  nSeries
>  M: Andrzej Zaborowski <balrogg@gmail.com>
>  M: Peter Maydell <peter.maydell@linaro.org>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 68aae2eabb..4d83fa337b 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o
>  common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
>  common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
>  common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
> +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o
>  common-obj-$(CONFIG_OMAP) += omap_clk.o
>  common-obj-$(CONFIG_OMAP) += omap_gpmc.o
>  common-obj-$(CONFIG_OMAP) += omap_l4.o
> diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
> new file mode 100644
> index 0000000000..cd8690a968
> --- /dev/null
> +++ b/hw/misc/npcm7xx_gcr.c
> @@ -0,0 +1,160 @@
> +/*
> + * Nuvoton NPCM7xx System Global Control Registers.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/misc/npcm7xx_gcr.h"
> +#include "hw/qdev-properties.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qemu/units.h"
> +
> +#include "trace.h"
> +
> +static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
> +    [NPCM7XX_GCR_PDID]          = 0x04A92750,   /* Poleg A1 */
> +    [NPCM7XX_GCR_MISCPE]        = 0x0000FFFF,
> +    [NPCM7XX_GCR_SPSWC]         = 0x00000003,
> +    [NPCM7XX_GCR_INTCR]         = 0x0000035E,
> +    [NPCM7XX_GCR_HIFCR]         = 0x0000004E,
> +    [NPCM7XX_GCR_RESSR]         = 0x80000000,
> +    [NPCM7XX_GCR_DSCNT]         = 0x000000c0,
> +    [NPCM7XX_GCR_DAVCLVLR]      = 0x5A00F3CF,
> +    [NPCM7XX_GCR_INTCR3]        = 0x00001002,
> +    [NPCM7XX_GCR_SCRPAD]        = 0x00000008,
> +    [NPCM7XX_GCR_USB1PHYCTL]    = 0x034730E4,
> +    [NPCM7XX_GCR_USB2PHYCTL]    = 0x034730E4,
> +};
> +
> +static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    uint32_t reg = offset / sizeof(uint32_t);
> +    NPCM7xxGCRState *s = opaque;
> +
> +    if (reg >= NPCM7XX_GCR_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
> +                      __func__, (unsigned int)offset);
> +        return 0;
> +    }
> +
> +    trace_npcm7xx_gcr_read(offset, s->regs[reg]);
> +
> +    return s->regs[reg];
> +}
> +
> +static void npcm7xx_gcr_write(void *opaque, hwaddr offset,
> +                              uint64_t v, unsigned size)
> +{
> +    uint32_t reg = offset / sizeof(uint32_t);
> +    NPCM7xxGCRState *s = opaque;
> +    uint32_t value = v;
> +
> +    trace_npcm7xx_gcr_write(offset, value);
> +
> +    if (reg >= NPCM7XX_GCR_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
> +                      __func__, (unsigned int)offset);
> +        return;
> +    }
> +
> +    switch (reg) {
> +    case NPCM7XX_GCR_PDID:
> +    case NPCM7XX_GCR_PWRON:
> +    case NPCM7XX_GCR_INTSR:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is read-only\n",
> +                      __func__, (unsigned int)offset);
> +        return;
> +
> +    case NPCM7XX_GCR_RESSR:
> +    case NPCM7XX_GCR_CP2BST:
> +        /* Write 1 to clear */
> +        value = s->regs[reg] & ~value;
> +        break;
> +
> +    case NPCM7XX_GCR_RLOCKR1:
> +    case NPCM7XX_GCR_MDLR:
> +        /* Write 1 to set */
> +        value |= s->regs[reg];
> +        break;
> +    };
> +
> +    s->regs[reg] = value;
> +}
> +
> +static const struct MemoryRegionOps npcm7xx_gcr_ops = {
> +    .read       = npcm7xx_gcr_read,
> +    .write      = npcm7xx_gcr_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,

DEVICE_LITTLE_ENDIAN

> +    .valid      = {
> +        .min_access_size        = 4,
> +        .max_access_size        = 4,
> +        .unaligned              = false,
> +    },
> +};
> +
> +static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
> +{
> +    NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
> +
> +    QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
> +
> +    switch (type) {
> +    case RESET_TYPE_COLD:
> +        memcpy(s->regs, cold_reset_values, sizeof(s->regs));
> +        s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
> +        s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
> +        break;
> +    }
> +}
> +
> +static void npcm7xx_gcr_init(Object *obj)
> +{
> +    NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
> +
> +    memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
> +                          TYPE_NPCM7XX_GCR, 4 * KiB);
> +    sysbus_init_mmio(&s->parent, &s->iomem);
> +}
> +
> +static Property npcm7xx_gcr_properties[] = {
> +    DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0),
> +    DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data)
> +{
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "NPCM7xx System Global Control Registers";
> +    rc->phases.enter = npcm7xx_gcr_enter_reset;
> +
> +    device_class_set_props(dc, npcm7xx_gcr_properties);
> +}
> +
> +static const TypeInfo npcm7xx_gcr_info = {
> +    .name               = TYPE_NPCM7XX_GCR,
> +    .parent             = TYPE_SYS_BUS_DEVICE,
> +    .instance_size      = sizeof(NPCM7xxGCRState),
> +    .instance_init      = npcm7xx_gcr_init,
> +    .class_init         = npcm7xx_gcr_class_init,
> +};
> +
> +static void npcm7xx_gcr_register_type(void)
> +{
> +    type_register_static(&npcm7xx_gcr_info);
> +}
> +type_init(npcm7xx_gcr_register_type);
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index a5862b2bed..d200438dbf 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -103,6 +103,10 @@ mos6522_set_sr_int(void) "set sr_int"
>  mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
>  mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
>  
> +# npcm7xx_gcr.c
> +npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
> +npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
> +
>  # stm32f4xx_syscfg
>  stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
>  stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
> diff --git a/include/hw/misc/npcm7xx_gcr.h b/include/hw/misc/npcm7xx_gcr.h
> new file mode 100644
> index 0000000000..e74a0e6305
> --- /dev/null
> +++ b/include/hw/misc/npcm7xx_gcr.h
> @@ -0,0 +1,74 @@
> +/*
> + * Nuvoton NPCM7xx System Global Control Registers.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 NPCM7XX_GCR_H
> +#define NPCM7XX_GCR_H
> +
> +#include "exec/memory.h"
> +#include "hw/sysbus.h"
> +
> +enum NPCM7xxGCRRegisters {
> +    NPCM7XX_GCR_PDID,
> +    NPCM7XX_GCR_PWRON,
> +    NPCM7XX_GCR_MFSEL1          = 0x0C / sizeof(uint32_t),
> +    NPCM7XX_GCR_MFSEL2,
> +    NPCM7XX_GCR_MISCPE,
> +    NPCM7XX_GCR_SPSWC           = 0x038 / sizeof(uint32_t),
> +    NPCM7XX_GCR_INTCR,
> +    NPCM7XX_GCR_INTSR,
> +    NPCM7XX_GCR_HIFCR           = 0x050 / sizeof(uint32_t),
> +    NPCM7XX_GCR_INTCR2          = 0x060 / sizeof(uint32_t),
> +    NPCM7XX_GCR_MFSEL3,
> +    NPCM7XX_GCR_SRCNT,
> +    NPCM7XX_GCR_RESSR,
> +    NPCM7XX_GCR_RLOCKR1,
> +    NPCM7XX_GCR_FLOCKR1,
> +    NPCM7XX_GCR_DSCNT,
> +    NPCM7XX_GCR_MDLR,
> +    NPCM7XX_GCR_SCRPAD3,
> +    NPCM7XX_GCR_SCRPAD2,
> +    NPCM7XX_GCR_DAVCLVLR        = 0x098 / sizeof(uint32_t),
> +    NPCM7XX_GCR_INTCR3,
> +    NPCM7XX_GCR_VSINTR          = 0x0AC / sizeof(uint32_t),
> +    NPCM7XX_GCR_MFSEL4,
> +    NPCM7XX_GCR_CPBPNTR         = 0x0C4 / sizeof(uint32_t),
> +    NPCM7XX_GCR_CPCTL           = 0x0D0 / sizeof(uint32_t),
> +    NPCM7XX_GCR_CP2BST,
> +    NPCM7XX_GCR_B2CPNT,
> +    NPCM7XX_GCR_CPPCTL,
> +    NPCM7XX_GCR_I2CSEGSEL,
> +    NPCM7XX_GCR_I2CSEGCTL,
> +    NPCM7XX_GCR_VSRCR,
> +    NPCM7XX_GCR_MLOCKR,
> +    NPCM7XX_GCR_SCRPAD          = 0x013C / sizeof(uint32_t),
> +    NPCM7XX_GCR_USB1PHYCTL,
> +    NPCM7XX_GCR_USB2PHYCTL,
> +    NPCM7XX_GCR_NR_REGS,
> +};
> +
> +typedef struct NPCM7xxGCRState {
> +    SysBusDevice parent;
> +
> +    MemoryRegion iomem;
> +
> +    uint32_t regs[NPCM7XX_GCR_NR_REGS];
> +
> +    uint32_t reset_pwron;
> +    uint32_t reset_mdlr;
> +} NPCM7xxGCRState;
> +
> +#define TYPE_NPCM7XX_GCR "npcm7xx-gcr"
> +#define NPCM7XX_GCR(obj) OBJECT_CHECK(NPCM7xxGCRState, (obj), TYPE_NPCM7XX_GCR)
> +
> +#endif /* NPCM7XX_GCR_H */
> 


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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-05-21 19:21 ` [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
@ 2020-06-09  7:24   ` Cédric Le Goater
  2020-06-09 23:06     ` Havard Skinnemoen
  1 sibling, 1 reply; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-09  7:24 UTC (permalink / raw)
  To: Havard Skinnemoen, peter.maydell
  Cc: kfting, qemu-arm, qemu-devel, Avi.Fishman

On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
> The Nuvoton NPCM7xx SoC family are used to implement Baseboard
> Management Controllers in servers. While the family includes four SoCs,
> this patch implements limited support for two of them: NPCM730 (targeted
> for Data Center applications) and NPCM750 (targeted for Enterprise
> applications).
> 
> This patch includes little more than the bare minimum needed to boot a
> Linux kernel built with NPCM7xx support in direct-kernel mode:
> 
>   - Two Cortex-A9 CPU cores with built-in periperhals.
>   - Global Configuration Registers.
>   - Clock Management.
>   - 3 Timer Modules with 5 timers each.
>   - 4 serial ports.
> 
> The chips themselves have a lot more features, some of which will be
> added to the model at a later stage.
> 
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
> ---
>  MAINTAINERS              |   2 +
>  hw/arm/Makefile.objs     |   1 +
>  hw/arm/npcm7xx.c         | 328 +++++++++++++++++++++++++++++++++++++++
>  include/hw/arm/npcm7xx.h |  79 ++++++++++
>  4 files changed, 410 insertions(+)
>  create mode 100644 hw/arm/npcm7xx.c
>  create mode 100644 include/hw/arm/npcm7xx.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c9a59a2c10..9c526af784 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -720,8 +720,10 @@ M: Havard Skinnemoen <hskinnemoen@google.com>
>  M: Tyrone Ting <kfting@nuvoton.com>
>  L: qemu-arm@nongnu.org
>  S: Supported
> +F: hw/arm/npcm7xx*
>  F: hw/misc/npcm7xx*
>  F: hw/timer/npcm7xx*
> +F: include/hw/arm/npcm7xx*
>  F: include/hw/misc/npcm7xx*
>  F: include/hw/timer/npcm7xx*
>  
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 534a6a119e..13d163a599 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -41,6 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>  obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o
>  obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
>  obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
> +obj-$(CONFIG_NPCM7XX) += npcm7xx.o
>  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
>  obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
>  obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
> diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
> new file mode 100644
> index 0000000000..3d88615634
> --- /dev/null
> +++ b/hw/arm/npcm7xx.c
> @@ -0,0 +1,328 @@
> +/*
> + * Nuvoton NPCM7xx SoC family.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "exec/address-spaces.h"
> +#include "hw/arm/npcm7xx.h"
> +#include "hw/char/serial.h"
> +#include "hw/loader.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
> +#include "qemu/units.h"
> +#include "sysemu/sysemu.h"
> +
> +/* The first half of the address space is reserved for DDR4 DRAM. */
> +#define NPCM7XX_DRAM_BA         (0x00000000)
> +#define NPCM7XX_DRAM_SZ         (2 * GiB)
> +
> +/*
> + * This covers the whole MMIO space. We'll use this to catch any MMIO accesses
> + * that aren't handled by any device.
> + */
> +#define NPCM7XX_MMIO_BA         (0x80000000)
> +#define NPCM7XX_MMIO_SZ         (0x7FFD0000)
> +
> +/* Core system modules. */
> +#define NPCM7XX_L2C_BA          (0xF03FC000)
> +#define NPCM7XX_CPUP_BA         (0xF03FE000)
> +#define NPCM7XX_GCR_BA          (0xF0800000)
> +#define NPCM7XX_CLK_BA          (0xF0801000)
> +
> +/* Memory blocks at the end of the address space */
> +#define NPCM7XX_RAM2_BA         (0xFFFD0000)
> +#define NPCM7XX_RAM2_SZ         (128 * KiB)
> +#define NPCM7XX_ROM_BA          (0xFFFF0000)
> +#define NPCM7XX_ROM_SZ          (64 * KiB)
> +
> +/*
> + * Interrupt lines going into the GIC. This does not include internal Cortex-A9
> + * interrupts.
> + */
> +enum NPCM7xxInterrupt {
> +    NPCM7XX_UART0_IRQ           = 2,
> +    NPCM7XX_UART1_IRQ,
> +    NPCM7XX_UART2_IRQ,
> +    NPCM7XX_UART3_IRQ,
> +    NPCM7XX_TIMER0_IRQ          = 32,   /* Timer Module 0 */
> +    NPCM7XX_TIMER1_IRQ,
> +    NPCM7XX_TIMER2_IRQ,
> +    NPCM7XX_TIMER3_IRQ,
> +    NPCM7XX_TIMER4_IRQ,
> +    NPCM7XX_TIMER5_IRQ,                 /* Timer Module 1 */
> +    NPCM7XX_TIMER6_IRQ,
> +    NPCM7XX_TIMER7_IRQ,
> +    NPCM7XX_TIMER8_IRQ,
> +    NPCM7XX_TIMER9_IRQ,
> +    NPCM7XX_TIMER10_IRQ,                /* Timer Module 2 */
> +    NPCM7XX_TIMER11_IRQ,
> +    NPCM7XX_TIMER12_IRQ,
> +    NPCM7XX_TIMER13_IRQ,
> +    NPCM7XX_TIMER14_IRQ,
> +};
> +
> +/* Register base address for each Timer Module */
> +static const hwaddr npcm7xx_tim_addr[] = {
> +    0xF0008000,
> +    0xF0009000,
> +    0xF000A000,
> +};
> +
> +/* Register base address for each 16550 UART */
> +static const hwaddr npcm7xx_uart_addr[] = {
> +    0xF0001000,
> +    0xF0002000,
> +    0xF0003000,
> +    0xF0004000,
> +};
> +
> +void npcm7xx_write_secondary_boot(ARMCPU *cpu, const struct arm_boot_info *info)
> +{
> +    /*
> +     * The default smpboot stub halts the secondary CPU with a 'wfi'
> +     * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel
> +     * does not send an IPI to wake it up, so the second CPU fails to boot. So
> +     * we need to provide our own smpboot stub that can not use 'wfi', it has
> +     * to spin the secondary CPU until the first CPU writes to the SCRPAD reg.
> +     */
> +    uint32_t smpboot[] = {

static const uint32 ?

> +        0xe59f2018,     /* ldr r2, bootreg_addr */
> +        0xe3a00000,     /* mov r0, #0 */
> +        0xe5820000,     /* str r0, [r2] */
> +        0xe320f002,     /* wfe */
> +        0xe5921000,     /* ldr r1, [r2] */
> +        0xe1110001,     /* tst r1, r1 */
> +        0x0afffffb,     /* beq <wfe> */
> +        0xe12fff11,     /* bx r1 */
> +        NPCM7XX_SMP_BOOTREG_ADDR,
> +    };
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(smpboot); i++) {
> +        smpboot[i] = tswap32(smpboot[i]);

ah ! why do we need to swap the instructions ?

> +    }
> +
> +    rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
> +                       NPCM7XX_SMP_LOADER_START);
> +}
> +
> +static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
> +{
> +    return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
> +}
> +
> +static void npcm7xx_init(Object *obj)
> +{
> +    NPCM7xxState *s = NPCM7XX(obj);
> +    int i;
> +
> +    for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
> +        s->cpu[i] = ARM_CPU(
> +            object_new_with_props(ARM_CPU_TYPE_NAME("cortex-a9"),
> +                                  obj, "cpu[*]", &error_abort, NULL));

why allocate  ? Can't you use : 

              ARMCPU cpu[NPCM7XX_MAX_NUM_CPUS];

and call object_initialize_child() ? 

> +    }
> +
> +    sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore,
> +                          sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV);
> +    sysbus_init_child_obj(obj, "gcr", OBJECT(&s->gcr), sizeof(s->gcr),
> +                          TYPE_NPCM7XX_GCR);
> +    sysbus_init_child_obj(obj, "clk", OBJECT(&s->clk), sizeof(s->clk),
> +                          TYPE_NPCM7XX_CLK);
> +
> +    for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
> +        sysbus_init_child_obj(obj, "tim[*]", OBJECT(&s->tim[i]),
> +                              sizeof(s->tim[i]), TYPE_NPCM7XX_TIMER);
> +    }
> +}
> +
> +static void npcm7xx_realize(DeviceState *dev, Error **errp)
> +{
> +    NPCM7xxState *s = NPCM7XX(dev);
> +    NPCM7xxClass *sc = NPCM7XX_GET_CLASS(s);
> +    Error *err = NULL;
> +    int i;
> +
> +    /* I/O space -- unimplemented unless overridden below. */
> +    create_unimplemented_device("npcm7xx.io", NPCM7XX_MMIO_BA, NPCM7XX_MMIO_SZ);
> +
> +    /* CPUs */
> +    if (s->num_cpus > NPCM7XX_MAX_NUM_CPUS) {
> +        warn_report("%s: invalid number of CPUs %d, using maximum %d",
> +                    object_get_typename(OBJECT(s)), s->num_cpus,
> +                    NPCM7XX_MAX_NUM_CPUS);
> +        s->num_cpus = NPCM7XX_MAX_NUM_CPUS;
> +    }
> +
> +    for (i = 0; i < s->num_cpus; i++) {
> +        object_property_set_int(OBJECT(s->cpu[i]),
> +                                arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS),
> +                                "mp-affinity", &error_abort);
> +        object_property_set_int(OBJECT(s->cpu[i]), NPCM7XX_GIC_CPU_IF_ADDR,
> +                                "reset-cbar", &error_abort);
> +        object_property_set_bool(OBJECT(s->cpu[i]), true,
> +                                 "reset-hivecs", &error_abort);
> +
> +        /* TODO: Not sure why this is needed. */

It's disabling the security extensions.

> +        if (object_property_find(OBJECT(s->cpu[i]), "has_el3", NULL)) {
> +            object_property_set_bool(OBJECT(s->cpu[i]), false, "has_el3",
> +                                     &error_abort);
> +        }
> +
> +        object_property_set_bool(OBJECT(s->cpu[i]), true, "realized", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +    }

With this pattern, which initializes all possible CPU objects and only 
realizes the requested ones, some CPU objects are left unrealized in 
the QOM tree. It's is better to unparent them.

If the board has a fixed number of CPUs and you don't plan to activate 
only a few of them for debug/test, I would make the "num_cpus" a class
property. See the Aspeed boards.

> +
> +    /* A9MPCORE peripherals */
> +    object_property_set_int(OBJECT(&s->a9mpcore), s->num_cpus, "num-cpu",
> +                            &error_abort);
> +    object_property_set_int(OBJECT(&s->a9mpcore), 160, "num-irq", &error_abort);

160 needs a define.

> +    object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized",
> +                             &error_abort);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, NPCM7XX_CPUP_BA);
> +
> +    for (i = 0; i < s->num_cpus; i++) {
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
> +                           qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ));
> +        sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + s->num_cpus,
> +                           qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_FIQ));
> +    }
> +
> +    /* L2 cache controller */
> +    sysbus_create_simple("l2x0", NPCM7XX_L2C_BA, NULL);
> +
> +    /* System Global Control Registers (GCR) */
> +    object_property_set_int(OBJECT(&s->gcr), sc->disabled_modules,
> +                            "disabled-modules", &err);
> +    object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gcr), 0, NPCM7XX_GCR_BA);
> +
> +    /* Clock Control Registers (CLK) */
> +    object_property_set_bool(OBJECT(&s->clk), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->clk), 0, NPCM7XX_CLK_BA);
> +
> +    /* Timer Modules (TIM) */
> +    QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
> +    for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
> +        Object *t = OBJECT(&s->tim[i]);
> +        int first_irq;
> +        int j;
> +
> +        object_property_set_bool(t, true, "realized", &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            return;
> +        }
> +        sysbus_mmio_map(SYS_BUS_DEVICE(t), 0, npcm7xx_tim_addr[i]);
> +
> +        first_irq = NPCM7XX_TIMER0_IRQ + i * NPCM7XX_TIMERS_PER_CTRL;
> +        for (j = 0; j < NPCM7XX_TIMERS_PER_CTRL; j++) {
> +            qemu_irq irq = npcm7xx_irq(s, first_irq + j);
> +            sysbus_connect_irq(SYS_BUS_DEVICE(t), j, irq);
> +        }
> +    }
> +
> +    /* UART0..3 (16550 compatible) */
> +    for (i = 0; i < ARRAY_SIZE(npcm7xx_uart_addr); i++) {
> +        serial_mm_init(get_system_memory(), npcm7xx_uart_addr[i], 2,
> +                       npcm7xx_irq(s, NPCM7XX_UART0_IRQ + i), 115200,
> +                       serial_hd(i), DEVICE_LITTLE_ENDIAN);
> +    }
> +
> +    /* RAM2 (SRAM) */
> +    memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
> +                           NPCM7XX_RAM2_SZ, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    memory_region_add_subregion(get_system_memory(), NPCM7XX_RAM2_BA, &s->sram);
> +
> +    /* Internal ROM */
> +    memory_region_init_rom(&s->irom, OBJECT(dev), "irom", NPCM7XX_ROM_SZ, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
> +
> +    /* External DDR4 SDRAM */
> +    memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, s->dram);
> +}
> +
> +static Property npcm7xx_properties[] = {
> +    DEFINE_PROP_INT32("num-cpus", NPCM7xxState, num_cpus, -1),
> +    DEFINE_PROP_LINK("dram", NPCM7xxState, dram, TYPE_MEMORY_REGION,
> +                     MemoryRegion *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void npcm7xx_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->realize = npcm7xx_realize;
> +    dc->user_creatable = false;
> +    device_class_set_props(dc, npcm7xx_properties);
> +}
> +
> +static void npcm730_class_init(ObjectClass *oc, void *data)
> +{
> +    NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
> +
> +    /* NPCM730 is optimized for data center use, so no graphics, etc. */
> +    nc->disabled_modules = 0x00300395;
> +}
> +
> +static void npcm750_class_init(ObjectClass *oc, void *data)
> +{
> +    NPCM7xxClass *nc = NPCM7XX_CLASS(oc);
> +
> +    /* NPCM750 has everything */
> +    nc->disabled_modules = 0x00000000;
> +}
> +
> +static const TypeInfo npcm7xx_soc_types[] = {
> +    {
> +        .name           = TYPE_NPCM7XX,
> +        .parent         = TYPE_DEVICE,
> +        .instance_size  = sizeof(NPCM7xxState),
> +        .instance_init  = npcm7xx_init,
> +        .class_size     = sizeof(NPCM7xxClass),
> +        .class_init     = npcm7xx_class_init,
> +        .abstract       = true,
> +    }, {
> +        .name           = TYPE_NPCM730,
> +        .parent         = TYPE_NPCM7XX,
> +        .class_init     = npcm730_class_init,
> +    }, {
> +        .name           = TYPE_NPCM750,
> +        .parent         = TYPE_NPCM7XX,
> +        .class_init     = npcm750_class_init,
> +    },
> +};
> +
> +DEFINE_TYPES(npcm7xx_soc_types);
> diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
> new file mode 100644
> index 0000000000..0a8798dd24
> --- /dev/null
> +++ b/include/hw/arm/npcm7xx.h
> @@ -0,0 +1,79 @@
> +/*
> + * Nuvoton NPCM7xx SoC family.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 NPCM7XX_H
> +#define NPCM7XX_H
> +
> +#include "hw/boards.h"
> +#include "hw/cpu/a9mpcore.h"
> +#include "hw/misc/npcm7xx_clk.h"
> +#include "hw/misc/npcm7xx_gcr.h"
> +#include "hw/timer/npcm7xx_timer.h"
> +#include "target/arm/cpu.h"
> +
> +#define NPCM7XX_MAX_NUM_CPUS    (2)
> +
> +/* Magic addresses for setting up direct kernel booting and SMP boot stubs. */
> +#define NPCM7XX_LOADER_START            (0x00000000)  /* Start of SDRAM */
> +#define NPCM7XX_SMP_LOADER_START        (0xFFFF0000)  /* Boot ROM */
> +#define NPCM7XX_SMP_BOOTREG_ADDR        (0xF080013C)  /* GCR.SCRPAD */
> +#define NPCM7XX_GIC_CPU_IF_ADDR         (0xF03FE100)  /* GIC within A9 */
> +
> +typedef struct NPCM7xxState {
> +    DeviceState         parent;
> +
> +    ARMCPU              *cpu[NPCM7XX_MAX_NUM_CPUS];
> +    A9MPPrivState       a9mpcore;
> +    int32_t             num_cpus;
> +
> +    MemoryRegion        sram;
> +    MemoryRegion        irom;
> +    MemoryRegion        *dram;
> +
> +    NPCM7xxGCRState     gcr;
> +    NPCM7xxCLKState     clk;
> +    NPCM7xxTimerCtrlState tim[3];
> +} NPCM7xxState;
> +
> +#define TYPE_NPCM7XX    "npcm7xx"
> +#define NPCM7XX(obj)    OBJECT_CHECK(NPCM7xxState, (obj), TYPE_NPCM7XX)
> +
> +#define TYPE_NPCM730    "npcm730"
> +#define TYPE_NPCM750    "npcm750"
> +
> +typedef struct NPCM7xxClass {
> +    DeviceClass         parent;
> +
> +    /* Bitmask of modules that are permanently disabled on this chip. */
> +    uint32_t            disabled_modules;
> +} NPCM7xxClass;
> +
> +#define NPCM7XX_CLASS(klass)                                            \
> +    OBJECT_CLASS_CHECK(NPCM7xxClass, (klass), TYPE_NPCM7XX)
> +#define NPCM7XX_GET_CLASS(obj)                                          \
> +    OBJECT_GET_CLASS(NPCM7xxClass, (obj), TYPE_NPCM7XX)
> +
> +/**
> + * npcm7xx_write_secondary_boot - Write stub for booting secondary CPU.
> + * @cpu: The CPU to be booted.
> + * @info: Boot info structure for the board.
> + *
> + * This will write a short code stub to the internal ROM that will keep the
> + * secondary CPU spinning until the primary CPU writes an address to the SCRPAD
> + * register in the GCR, after which the secondary CPU will jump there.
> + */
> +extern void npcm7xx_write_secondary_boot(ARMCPU *cpu,
> +                                         const struct arm_boot_info *info);
> +
> +#endif /* NPCM7XX_H */
> 



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

* Re: [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines
  2020-05-21 19:21 ` [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
@ 2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-09  7:24 UTC (permalink / raw)
  To: Havard Skinnemoen, peter.maydell
  Cc: kfting, qemu-arm, qemu-devel, Avi.Fishman

On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
> This adds two new machines:
> 
>   - npcm750-evb: Nuvoton NPCM750 Evaluation Board.
>   - quanta-gsj: A board with a NPCM730 chip.
> 
> They rely on the NPCM7xx SoC device to do the heavy lifting. They are
> almost completely identical at the moment, apart from the SoC type,
> which currently only changes the reset contents of one register
> (GCR.MDLR), but they might grow apart a bit more as more functionality
> is added.
> 
> Both machines can boot the Linux kernel into /bin/sh.
> 
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Reviewed-by: Cédric Le Goater <clg@kaod.org>

> ---
>  hw/arm/Makefile.objs     |   2 +-
>  hw/arm/npcm7xx_boards.c  | 108 +++++++++++++++++++++++++++++++++++++++
>  include/hw/arm/npcm7xx.h |  19 +++++++
>  3 files changed, 128 insertions(+), 1 deletion(-)
>  create mode 100644 hw/arm/npcm7xx_boards.c
> 
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 13d163a599..c333548ce1 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -41,7 +41,7 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>  obj-$(CONFIG_STM32F405_SOC) += stm32f405_soc.o
>  obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
>  obj-$(CONFIG_XLNX_VERSAL) += xlnx-versal.o xlnx-versal-virt.o
> -obj-$(CONFIG_NPCM7XX) += npcm7xx.o
> +obj-$(CONFIG_NPCM7XX) += npcm7xx.o npcm7xx_boards.o
>  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
>  obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
>  obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
> diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
> new file mode 100644
> index 0000000000..b89819f6e2
> --- /dev/null
> +++ b/hw/arm/npcm7xx_boards.c
> @@ -0,0 +1,108 @@
> +/*
> + * Machine definitions for boards featuring an NPCM7xx SoC.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/arm/boot.h"
> +#include "hw/arm/npcm7xx.h"
> +#include "hw/core/cpu.h"
> +#include "qapi/error.h"
> +#include "qemu/units.h"
> +
> +static struct arm_boot_info npcm7xx_binfo = {
> +    .loader_start       = NPCM7XX_LOADER_START,
> +    .smp_loader_start   = NPCM7XX_SMP_LOADER_START,
> +    .smp_bootreg_addr   = NPCM7XX_SMP_BOOTREG_ADDR,
> +    .gic_cpu_if_addr    = NPCM7XX_GIC_CPU_IF_ADDR,
> +    .write_secondary_boot = npcm7xx_write_secondary_boot,
> +    .board_id           = -1,
> +};
> +
> +static void npcm7xx_machine_init(MachineState *machine)
> +{
> +    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
> +    NPCM7xxState *soc;
> +
> +    soc = NPCM7XX(object_new_with_props(nmc->soc_type, OBJECT(machine), "soc",
> +                                        &error_abort, NULL));
> +    object_property_set_int(OBJECT(soc), machine->smp.cpus, "num-cpus",
> +                            &error_abort);
> +    object_property_set_link(OBJECT(soc), OBJECT(machine->ram), "dram",
> +                             &error_abort);
> +    object_property_set_bool(OBJECT(soc), true, "realized", &error_abort);
> +
> +    npcm7xx_binfo.ram_size = machine->ram_size;
> +    npcm7xx_binfo.nb_cpus = machine->smp.cpus;
> +
> +    arm_load_kernel(soc->cpu[0], machine, &npcm7xx_binfo);
> +}
> +
> +static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->init            = npcm7xx_machine_init;
> +    mc->max_cpus        = NPCM7XX_MAX_NUM_CPUS;
> +    mc->default_cpus    = NPCM7XX_MAX_NUM_CPUS;
> +    mc->no_floppy       = 1;
> +    mc->no_cdrom        = 1;
> +    mc->no_parallel     = 1;
> +    mc->default_ram_id  = "ram";
> +}
> +
> +/*
> + * Schematics:
> + * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
> + */
> +static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
> +{
> +    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc            = "Nuvoton NPCM750 Evaluation Board (Cortex A9)";
> +    nmc->soc_type       = TYPE_NPCM750;
> +    mc->default_ram_size = 512 * MiB;
> +};
> +
> +static void gsj_machine_class_init(ObjectClass *oc, void *data)
> +{
> +    NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc            = "Quanta GSJ (Cortex A9)";
> +    nmc->soc_type       = TYPE_NPCM730;
> +    mc->default_ram_size = 512 * MiB;
> +};
> +
> +static const TypeInfo npcm7xx_machine_types[] = {
> +    {
> +        .name           = TYPE_NPCM7XX_MACHINE,
> +        .parent         = TYPE_MACHINE,
> +        .instance_size  = sizeof(NPCM7xxMachine),
> +        .class_size     = sizeof(NPCM7xxMachineClass),
> +        .class_init     = npcm7xx_machine_class_init,
> +        .abstract       = true,
> +    }, {
> +        .name           = MACHINE_TYPE_NAME("npcm750-evb"),
> +        .parent         = TYPE_NPCM7XX_MACHINE,
> +        .class_init     = npcm750_evb_machine_class_init,
> +    }, {
> +        .name           = MACHINE_TYPE_NAME("quanta-gsj"),
> +        .parent         = TYPE_NPCM7XX_MACHINE,
> +        .class_init     = gsj_machine_class_init,
> +    },
> +};
> +
> +DEFINE_TYPES(npcm7xx_machine_types)
> diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
> index 0a8798dd24..c1a108e89a 100644
> --- a/include/hw/arm/npcm7xx.h
> +++ b/include/hw/arm/npcm7xx.h
> @@ -30,6 +30,25 @@
>  #define NPCM7XX_SMP_BOOTREG_ADDR        (0xF080013C)  /* GCR.SCRPAD */
>  #define NPCM7XX_GIC_CPU_IF_ADDR         (0xF03FE100)  /* GIC within A9 */
>  
> +typedef struct NPCM7xxMachine {
> +    MachineState        parent;
> +} NPCM7xxMachine;
> +
> +#define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx")
> +#define NPCM7XX_MACHINE(obj)                                            \
> +    OBJECT_CHECK(NPCM7xxMachine, (obj), TYPE_NPCM7XX_MACHINE)
> +
> +typedef struct NPCM7xxMachineClass {
> +    MachineClass        parent;
> +
> +    const char          *soc_type;
> +} NPCM7xxMachineClass;
> +
> +#define NPCM7XX_MACHINE_CLASS(klass)                                    \
> +    OBJECT_CLASS_CHECK(NPCM7xxMachineClass, (klass), TYPE_NPCM7XX_MACHINE)
> +#define NPCM7XX_MACHINE_GET_CLASS(obj)                                  \
> +    OBJECT_GET_CLASS(NPCM7xxMachineClass, (obj), TYPE_NPCM7XX_MACHINE)
> +
>  typedef struct NPCM7xxState {
>      DeviceState         parent;
>  
> 



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

* Re: [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller device model
  2020-05-21 19:21 ` [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller " Havard Skinnemoen
  2020-06-09  1:36   ` Joel Stanley
@ 2020-06-09  7:24   ` Cédric Le Goater
  1 sibling, 0 replies; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-09  7:24 UTC (permalink / raw)
  To: Havard Skinnemoen, peter.maydell
  Cc: kfting, qemu-arm, qemu-devel, Avi.Fishman

On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
> Enough functionality to boot the Linux kernel has been implemented. This
> includes:
> 
>   - Correct power-on reset values so the various clock rates can be
>     accurately calculated.
>   - Clock enables stick around when written.
> 
> In addition, a best effort attempt to implement SECCNT and CNTR25M was
> made even though I don't think the kernel needs them.
> 
> Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
> Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>

Reviewed-by: Cédric Le Goater <clg@kaod.org>



> ---
>  hw/misc/Makefile.objs         |   1 +
>  hw/misc/npcm7xx_clk.c         | 210 ++++++++++++++++++++++++++++++++++
>  hw/misc/trace-events          |   4 +
>  include/hw/misc/npcm7xx_clk.h |  65 +++++++++++
>  4 files changed, 280 insertions(+)
>  create mode 100644 hw/misc/npcm7xx_clk.c
>  create mode 100644 include/hw/misc/npcm7xx_clk.h
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 4d83fa337b..1096a76457 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -51,6 +51,7 @@ common-obj-$(CONFIG_IMX) += imx_rngc.o
>  common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
>  common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
>  common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
> +common-obj-$(CONFIG_NPCM7XX) += npcm7xx_clk.o
>  common-obj-$(CONFIG_NPCM7XX) += npcm7xx_gcr.o
>  common-obj-$(CONFIG_OMAP) += omap_clk.o
>  common-obj-$(CONFIG_OMAP) += omap_gpmc.o
> diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
> new file mode 100644
> index 0000000000..b4ff85e8c2
> --- /dev/null
> +++ b/hw/misc/npcm7xx_clk.c
> @@ -0,0 +1,210 @@
> +/*
> + * Nuvoton NPCM7xx Clock Control Registers.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/misc/npcm7xx_clk.h"
> +#include "qemu/error-report.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qemu/timer.h"
> +#include "qemu/units.h"
> +#include "trace.h"
> +
> +#define PLLCON_LOKI     BIT(31)
> +#define PLLCON_LOKS     BIT(30)
> +#define PLLCON_PWDEN    BIT(12)
> +
> +static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
> +    [NPCM7XX_CLK_CLKEN1]        = 0xffffffff,
> +    [NPCM7XX_CLK_CLKSEL]        = 0x004aaaaa,
> +    [NPCM7XX_CLK_CLKDIV1]       = 0x5413f855,
> +    [NPCM7XX_CLK_PLLCON0]       = 0x00222101 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_PLLCON1]       = 0x00202101 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_IPSRST1]       = 0x00001000,
> +    [NPCM7XX_CLK_IPSRST2]       = 0x80000000,
> +    [NPCM7XX_CLK_CLKEN2]        = 0xffffffff,
> +    [NPCM7XX_CLK_CLKDIV2]       = 0xaa4f8f9f,
> +    [NPCM7XX_CLK_CLKEN3]        = 0xffffffff,
> +    [NPCM7XX_CLK_IPSRST3]       = 0x03000000,
> +    [NPCM7XX_CLK_WD0RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_WD1RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_WD2RCR]        = 0xffffffff,
> +    [NPCM7XX_CLK_SWRSTC1]       = 0x00000003,
> +    [NPCM7XX_CLK_PLLCON2]       = 0x00c02105 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_CORSTC]        = 0x04000003,
> +    [NPCM7XX_CLK_PLLCONG]       = 0x01228606 | PLLCON_LOKI,
> +    [NPCM7XX_CLK_AHBCKFI]       = 0x000000c8,
> +};
> +
> +static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    uint32_t reg = offset / sizeof(uint32_t);
> +    NPCM7xxCLKState *s = opaque;
> +    int64_t now_ns;
> +    uint32_t value = 0;
> +
> +    if (reg >= NPCM7XX_CLK_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
> +                      __func__, (unsigned int)offset);
> +        return 0;
> +    }
> +
> +    switch (reg) {
> +    case NPCM7XX_CLK_SWRSTR:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is write-only\n",
> +                      __func__, (unsigned int)offset);
> +        break;
> +
> +    case NPCM7XX_CLK_SECCNT:
> +        now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        value = (now_ns - s->ref_ns) / NANOSECONDS_PER_SECOND;
> +        break;
> +
> +    case NPCM7XX_CLK_CNTR25M:
> +        now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        /*
> +         * This register counts 25 MHz cycles, updating every 640 ns. It rolls
> +         * over to zero every second.
> +         *
> +         * The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
> +         */
> +        value = (((now_ns - s->ref_ns) / 640) << 4) % 25000000;
> +        break;
> +
> +    default:
> +        value = s->regs[reg];
> +        break;
> +    };
> +
> +    trace_npcm7xx_clk_read(offset, value);
> +
> +    return value;
> +}
> +
> +static void npcm7xx_clk_write(void *opaque, hwaddr offset,
> +                              uint64_t v, unsigned size)
> +{
> +    uint32_t reg = offset / sizeof(uint32_t);
> +    NPCM7xxCLKState *s = opaque;
> +    uint32_t value = v;
> +
> +    trace_npcm7xx_clk_write(offset, value);
> +
> +    if (reg >= NPCM7XX_CLK_NR_REGS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n",
> +                      __func__, (unsigned int)offset);
> +        return;
> +    }
> +
> +    switch (reg) {
> +    case NPCM7XX_CLK_SWRSTR:
> +        qemu_log_mask(LOG_UNIMP, "%s: SW reset not implemented: 0x%02x\n",
> +                      __func__, value);
> +        value = 0;
> +        break;
> +
> +    case NPCM7XX_CLK_PLLCON0:
> +    case NPCM7XX_CLK_PLLCON1:
> +    case NPCM7XX_CLK_PLLCON2:
> +    case NPCM7XX_CLK_PLLCONG:
> +        if (value & PLLCON_PWDEN) {
> +            /* Power down -- clear lock and indicate loss of lock */
> +            value &= ~PLLCON_LOKI;
> +            value |= PLLCON_LOKS;
> +        } else {
> +            /* Normal mode -- assume always locked */
> +            value |= PLLCON_LOKI;
> +            /* Keep LOKS unchanged unless cleared by writing 1 */
> +            if (value & PLLCON_LOKS) {
> +                value &= ~PLLCON_LOKS;
> +            } else {
> +                value |= (value & PLLCON_LOKS);
> +            }
> +        }
> +        break;
> +
> +    case NPCM7XX_CLK_CNTR25M:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: register @ 0x%04x is read-only\n",
> +                      __func__, (unsigned int)offset);
> +        return;
> +    }
> +
> +    s->regs[reg] = value;
> +}
> +
> +static const struct MemoryRegionOps npcm7xx_clk_ops = {
> +    .read       = npcm7xx_clk_read,
> +    .write      = npcm7xx_clk_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid      = {
> +        .min_access_size        = 4,
> +        .max_access_size        = 4,
> +        .unaligned              = false,
> +    },
> +};
> +
> +static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
> +{
> +    NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
> +
> +    QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
> +
> +    switch (type) {
> +    case RESET_TYPE_COLD:
> +        memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
> +        s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        return;
> +    }
> +
> +    /*
> +     * A small number of registers need to be reset on a core domain reset,
> +     * but no such reset type exists yet.
> +     */
> +    qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
> +                  __func__, type);
> +}
> +
> +static void npcm7xx_clk_init(Object *obj)
> +{
> +    NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
> +
> +    memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
> +                          TYPE_NPCM7XX_CLK, 4 * KiB);
> +    sysbus_init_mmio(&s->parent, &s->iomem);
> +}
> +
> +static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
> +{
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "NPCM7xx Clock Control Registers";
> +    rc->phases.enter = npcm7xx_clk_enter_reset;
> +}
> +
> +static const TypeInfo npcm7xx_clk_info = {
> +    .name               = TYPE_NPCM7XX_CLK,
> +    .parent             = TYPE_SYS_BUS_DEVICE,
> +    .instance_size      = sizeof(NPCM7xxCLKState),
> +    .instance_init      = npcm7xx_clk_init,
> +    .class_init         = npcm7xx_clk_class_init,
> +};
> +
> +static void npcm7xx_clk_register_type(void)
> +{
> +    type_register_static(&npcm7xx_clk_info);
> +}
> +type_init(npcm7xx_clk_register_type);
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index d200438dbf..ae97e8b091 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -103,6 +103,10 @@ mos6522_set_sr_int(void) "set sr_int"
>  mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
>  mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
>  
> +# npcm7xx_clk.c
> +npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
> +npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
> +
>  # npcm7xx_gcr.c
>  npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
>  npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
> diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
> new file mode 100644
> index 0000000000..a678b50ede
> --- /dev/null
> +++ b/include/hw/misc/npcm7xx_clk.h
> @@ -0,0 +1,65 @@
> +/*
> + * Nuvoton NPCM7xx Clock Control Registers.
> + *
> + * Copyright 2020 Google LLC
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 NPCM7XX_CLK_H
> +#define NPCM7XX_CLK_H
> +
> +#include "exec/memory.h"
> +#include "hw/sysbus.h"
> +
> +enum NPCM7xxCLKRegisters {
> +    NPCM7XX_CLK_CLKEN1,
> +    NPCM7XX_CLK_CLKSEL,
> +    NPCM7XX_CLK_CLKDIV1,
> +    NPCM7XX_CLK_PLLCON0,
> +    NPCM7XX_CLK_PLLCON1,
> +    NPCM7XX_CLK_SWRSTR,
> +    NPCM7XX_CLK_IPSRST1         = 0x20 / sizeof(uint32_t),
> +    NPCM7XX_CLK_IPSRST2,
> +    NPCM7XX_CLK_CLKEN2,
> +    NPCM7XX_CLK_CLKDIV2,
> +    NPCM7XX_CLK_CLKEN3,
> +    NPCM7XX_CLK_IPSRST3,
> +    NPCM7XX_CLK_WD0RCR,
> +    NPCM7XX_CLK_WD1RCR,
> +    NPCM7XX_CLK_WD2RCR,
> +    NPCM7XX_CLK_SWRSTC1,
> +    NPCM7XX_CLK_SWRSTC2,
> +    NPCM7XX_CLK_SWRSTC3,
> +    NPCM7XX_CLK_SWRSTC4,
> +    NPCM7XX_CLK_PLLCON2,
> +    NPCM7XX_CLK_CLKDIV3,
> +    NPCM7XX_CLK_CORSTC,
> +    NPCM7XX_CLK_PLLCONG,
> +    NPCM7XX_CLK_AHBCKFI,
> +    NPCM7XX_CLK_SECCNT,
> +    NPCM7XX_CLK_CNTR25M,
> +    NPCM7XX_CLK_NR_REGS,
> +};
> +
> +typedef struct NPCM7xxCLKState {
> +    SysBusDevice parent;
> +
> +    MemoryRegion iomem;
> +
> +    uint32_t regs[NPCM7XX_CLK_NR_REGS];
> +
> +    /* Time reference for SECCNT and CNTR25M, initialized by power on reset */
> +    int64_t ref_ns;
> +} NPCM7xxCLKState;
> +
> +#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
> +#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
> +
> +#endif /* NPCM7XX_CLK_H */
> 



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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-06-08 22:14 ` Havard Skinnemoen
  2020-06-09  1:39   ` Joel Stanley
@ 2020-06-09  7:31   ` Cédric Le Goater
  2020-06-09  9:38     ` Peter Maydell
  1 sibling, 1 reply; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-09  7:31 UTC (permalink / raw)
  To: Havard Skinnemoen, peter.maydell
  Cc: CS20 KFTing, qemu-arm, qemu-devel, IS20 Avi Fishman

On 6/9/20 12:14 AM, Havard Skinnemoen wrote:
> On Thu, May 21, 2020 at 12:21 PM Havard Skinnemoen <hskinnemoen@google.com <mailto:hskinnemoen@google.com>> wrote:
> 
>     This patch series models enough of the Nuvoton NPCM730 and NPCM750 SoCs to boot
>     a minimal Linux kernel. This includes device models for:
> 
> 
> Does anyone have comments on this series? I'm currently finishing up a second patch series that adds flash support and a few other things so qemu can boot a full OpenBMC flash image built for npcm7xx.
> 
> If you prefer, I can combine them both into one series and send it to the list.

The first series was nicely presented I think, but you can extend it in v2.
Documentation needs an update in :

  docs/system/target-arm.rst

Thanks,

C.



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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-06-09  7:31   ` Cédric Le Goater
@ 2020-06-09  9:38     ` Peter Maydell
  2020-06-09 16:30       ` Havard Skinnemoen
  0 siblings, 1 reply; 28+ messages in thread
From: Peter Maydell @ 2020-06-09  9:38 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: CS20 KFTing, qemu-arm, Havard Skinnemoen, IS20 Avi Fishman,
	QEMU Developers

On Tue, 9 Jun 2020 at 08:31, Cédric Le Goater <clg@kaod.org> wrote:
> The first series was nicely presented I think, but you can extend it in v2.
> Documentation needs an update in :
>
>   docs/system/target-arm.rst

To expand on that: the new boards should have at least some basic
documentation in a new docs/system/arm/something.rst (we have
one .rst file usually for each "family" of boards which are
similar enough to make sense to document as a group), which is
added to the toctree in target-arm.rst (note that it is supposed
to be kept in alpha-order-of-document-title-text). aspeed.rst should
give an idea of what ought to be documented: a basic summary of
what the machine is, what is supported, what is not implemented,
any machine options that the board has, that sort of thing.

thanks
-- PMM


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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-06-09  9:38     ` Peter Maydell
@ 2020-06-09 16:30       ` Havard Skinnemoen
  0 siblings, 0 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-06-09 16:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Cédric Le Goater, qemu-arm, QEMU Developers,
	IS20 Avi Fishman, CS20 KFTing

[-- Attachment #1: Type: text/plain, Size: 1055 bytes --]

On Tue, Jun 9, 2020 at 2:38 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> On Tue, 9 Jun 2020 at 08:31, Cédric Le Goater <clg@kaod.org> wrote:
> > The first series was nicely presented I think, but you can extend it in
> v2.
> > Documentation needs an update in :
> >
> >   docs/system/target-arm.rst
>
> To expand on that: the new boards should have at least some basic
> documentation in a new docs/system/arm/something.rst (we have
> one .rst file usually for each "family" of boards which are
> similar enough to make sense to document as a group), which is
> added to the toctree in target-arm.rst (note that it is supposed
> to be kept in alpha-order-of-document-title-text). aspeed.rst should
> give an idea of what ought to be documented: a basic summary of
> what the machine is, what is supported, what is not implemented,
> any machine options that the board has, that sort of thing.
>

Thanks for the feedback. I will include documentation in v2 of this
patchset, and also address your other comments.

Havard

[-- Attachment #2: Type: text/html, Size: 1476 bytes --]

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

* Re: [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines
  2020-06-09  1:39   ` Joel Stanley
@ 2020-06-09 16:36     ` Havard Skinnemoen
  0 siblings, 0 replies; 28+ messages in thread
From: Havard Skinnemoen @ 2020-06-09 16:36 UTC (permalink / raw)
  To: Joel Stanley
  Cc: Peter Maydell, qemu-arm, QEMU Developers, IS20 Avi Fishman,
	CS20 KFTing, Cédric Le Goater

[-- Attachment #1: Type: text/plain, Size: 491 bytes --]

On Mon, Jun 8, 2020 at 6:39 PM Joel Stanley <joel@jms.id.au> wrote:

> I had a look and they appear good to me. Note that I'm less in to the
> gory details of Qemu than some of our other reviewers, so you should
> seek  a more detailed review from someone else.
>
> I look forward further support so I can test the OpenBMC kernel
> against Nuvoton boards in the same way as the Aspeed ones.
>

Great to hear that, and thanks for your review. I hope to post an updated
patchset soon.

Havard

[-- Attachment #2: Type: text/html, Size: 841 bytes --]

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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-06-09  7:24   ` Cédric Le Goater
@ 2020-06-09 23:06     ` Havard Skinnemoen
  2020-06-11  6:12       ` Cédric Le Goater
  0 siblings, 1 reply; 28+ messages in thread
From: Havard Skinnemoen @ 2020-06-09 23:06 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: peter.maydell, qemu-arm, qemu-devel, IS20 Avi Fishman, CS20 KFTing

[-- Attachment #1: Type: text/plain, Size: 4431 bytes --]

On Tue, Jun 9, 2020 at 12:24 AM Cédric Le Goater <clg@kaod.org> wrote:

> On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
> > +void npcm7xx_write_secondary_boot(ARMCPU *cpu, const struct
> arm_boot_info *info)
> > +{
> > +    /*
> > +     * The default smpboot stub halts the secondary CPU with a 'wfi'
> > +     * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux
> kernel
> > +     * does not send an IPI to wake it up, so the second CPU fails to
> boot. So
> > +     * we need to provide our own smpboot stub that can not use 'wfi',
> it has
> > +     * to spin the secondary CPU until the first CPU writes to the
> SCRPAD reg.
> > +     */
> > +    uint32_t smpboot[] = {
>
> static const uint32 ?
>

I think that would be unsafe due to the byte swapping, but I'll do it if we
can get rid of that somehow.


>
> > +        0xe59f2018,     /* ldr r2, bootreg_addr */
> > +        0xe3a00000,     /* mov r0, #0 */
> > +        0xe5820000,     /* str r0, [r2] */
> > +        0xe320f002,     /* wfe */
> > +        0xe5921000,     /* ldr r1, [r2] */
> > +        0xe1110001,     /* tst r1, r1 */
> > +        0x0afffffb,     /* beq <wfe> */
> > +        0xe12fff11,     /* bx r1 */
> > +        NPCM7XX_SMP_BOOTREG_ADDR,
> > +    };
> > +    int i;
> > +
> > +    for (i = 0; i < ARRAY_SIZE(smpboot); i++) {
> > +        smpboot[i] = tswap32(smpboot[i]);
>
> ah ! why do we need to swap the instructions ?
>

I probably stole this from
https://elixir.bootlin.com/qemu/latest/source/hw/arm/exynos4210.c#L134
although there are several other examples of this pattern.

IIUC, it's necessary for the target to see the instruction words specified
above when its endianness is different from the host. But perhaps I can
specify it as a byte array instead. Would that work?

If that works, I should be able to drop the byte swapping and make the
smpboot array constant. I don't think I'll be able to test it thoroughly
though, as I don't have access to a big endian host.

> +static void npcm7xx_init(Object *obj)
> > +{
> > +    NPCM7xxState *s = NPCM7XX(obj);
> > +    int i;
> > +
> > +    for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
> > +        s->cpu[i] = ARM_CPU(
> > +            object_new_with_props(ARM_CPU_TYPE_NAME("cortex-a9"),
> > +                                  obj, "cpu[*]", &error_abort, NULL));
>
> why allocate  ? Can't you use :
>
>               ARMCPU cpu[NPCM7XX_MAX_NUM_CPUS];
>
> and call object_initialize_child() ?
>

OK, I will try that.

> +    for (i = 0; i < s->num_cpus; i++) {
> > +        object_property_set_int(OBJECT(s->cpu[i]),
> > +                                arm_cpu_mp_affinity(i,
> NPCM7XX_MAX_NUM_CPUS),
> > +                                "mp-affinity", &error_abort);
> > +        object_property_set_int(OBJECT(s->cpu[i]),
> NPCM7XX_GIC_CPU_IF_ADDR,
> > +                                "reset-cbar", &error_abort);
> > +        object_property_set_bool(OBJECT(s->cpu[i]), true,
> > +                                 "reset-hivecs", &error_abort);
> > +
> > +        /* TODO: Not sure why this is needed. */
>
> It's disabling the security extensions.
>

Thanks, I'll update the comment.


>
> > +        if (object_property_find(OBJECT(s->cpu[i]), "has_el3", NULL)) {
> > +            object_property_set_bool(OBJECT(s->cpu[i]), false,
> "has_el3",
> > +                                     &error_abort);
> > +        }
> > +
> > +        object_property_set_bool(OBJECT(s->cpu[i]), true, "realized",
> &err);
> > +        if (err) {
> > +            error_propagate(errp, err);
> > +            return;
> > +        }
> > +    }
>
> With this pattern, which initializes all possible CPU objects and only
> realizes the requested ones, some CPU objects are left unrealized in
> the QOM tree. It's is better to unparent them.
>
> If the board has a fixed number of CPUs and you don't plan to activate
> only a few of them for debug/test, I would make the "num_cpus" a class
> property. See the Aspeed boards.
>

Will do, thanks.


> > +
> > +    /* A9MPCORE peripherals */
> > +    object_property_set_int(OBJECT(&s->a9mpcore), s->num_cpus,
> "num-cpu",
> > +                            &error_abort);
> > +    object_property_set_int(OBJECT(&s->a9mpcore), 160, "num-irq",
> &error_abort);
>
> 160 needs a define.
>

Will do, thanks.

[-- Attachment #2: Type: text/html, Size: 6519 bytes --]

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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-06-09 23:06     ` Havard Skinnemoen
@ 2020-06-11  6:12       ` Cédric Le Goater
  2020-06-11  9:38         ` Peter Maydell
  0 siblings, 1 reply; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-11  6:12 UTC (permalink / raw)
  To: Havard Skinnemoen
  Cc: peter.maydell, qemu-arm, qemu-devel, CS20 KFTing, IS20 Avi Fishman

On 6/10/20 1:06 AM, Havard Skinnemoen wrote:
> On Tue, Jun 9, 2020 at 12:24 AM Cédric Le Goater <clg@kaod.org <mailto:clg@kaod.org>> wrote:
> 
>     On 5/21/20 9:21 PM, Havard Skinnemoen wrote:
>     > +void npcm7xx_write_secondary_boot(ARMCPU *cpu, const struct arm_boot_info *info)
>     > +{
>     > +    /*
>     > +     * The default smpboot stub halts the secondary CPU with a 'wfi'
>     > +     * instruction, but the arch/arm/mach-npcm/platsmp.c in the Linux kernel
>     > +     * does not send an IPI to wake it up, so the second CPU fails to boot. So
>     > +     * we need to provide our own smpboot stub that can not use 'wfi', it has
>     > +     * to spin the secondary CPU until the first CPU writes to the SCRPAD reg.
>     > +     */
>     > +    uint32_t smpboot[] = {
> 
>     static const uint32 ?
> 
> 
> I think that would be unsafe due to the byte swapping, but I'll do it if we can get rid of that somehow.
>  
> 
> 
>     > +        0xe59f2018,     /* ldr r2, bootreg_addr */
>     > +        0xe3a00000,     /* mov r0, #0 */
>     > +        0xe5820000,     /* str r0, [r2] */
>     > +        0xe320f002,     /* wfe */
>     > +        0xe5921000,     /* ldr r1, [r2] */
>     > +        0xe1110001,     /* tst r1, r1 */
>     > +        0x0afffffb,     /* beq <wfe> */
>     > +        0xe12fff11,     /* bx r1 */
>     > +        NPCM7XX_SMP_BOOTREG_ADDR,
>     > +    };
>     > +    int i;
>     > +
>     > +    for (i = 0; i < ARRAY_SIZE(smpboot); i++) {
>     > +        smpboot[i] = tswap32(smpboot[i]);
> 
>     ah ! why do we need to swap the instructions ?
> 
> 
> I probably stole this from https://elixir.bootlin.com/qemu/latest/source/hw/arm/exynos4210.c#L134 although there are several other examples of this pattern.

Some don't some do. This is a bit confusing. 

Peter, should we fix the boards not doing the tswap in the secondary 
bootloader ? 

I still have access to a PP64 BE host to test.

Thanks, 

C.


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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-06-11  6:12       ` Cédric Le Goater
@ 2020-06-11  9:38         ` Peter Maydell
  2020-06-17 15:24           ` Cédric Le Goater
  0 siblings, 1 reply; 28+ messages in thread
From: Peter Maydell @ 2020-06-11  9:38 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: CS20 KFTing, qemu-arm, Havard Skinnemoen, IS20 Avi Fishman,
	QEMU Developers

On Thu, 11 Jun 2020 at 07:12, Cédric Le Goater <clg@kaod.org> wrote:
> Some don't some do. This is a bit confusing.

Probably the usual thing of people not noticing that they
need to do something for big-endian hosts and nobody testing
the minor platforms there.

> Peter, should we fix the boards not doing the tswap in the secondary
> bootloader ?

Yes, we should -- it's an actual bug as well as just not being
very consistent.

> I still have access to a PP64 BE host to test.

In an ideal world the bugs would cause "make check" and/or
"make check-acceptance" to fail on BE hosts :-)

thanks
-- PMM


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

* Re: [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models
  2020-06-11  9:38         ` Peter Maydell
@ 2020-06-17 15:24           ` Cédric Le Goater
  0 siblings, 0 replies; 28+ messages in thread
From: Cédric Le Goater @ 2020-06-17 15:24 UTC (permalink / raw)
  To: Peter Maydell
  Cc: CS20 KFTing, qemu-arm, Havard Skinnemoen, IS20 Avi Fishman,
	QEMU Developers

On 6/11/20 11:38 AM, Peter Maydell wrote:
> On Thu, 11 Jun 2020 at 07:12, Cédric Le Goater <clg@kaod.org> wrote:
>> Some don't some do. This is a bit confusing.
> 
> Probably the usual thing of people not noticing that they
> need to do something for big-endian hosts and nobody testing
> the minor platforms there.
> 
>> Peter, should we fix the boards not doing the tswap in the secondary
>> bootloader ?
> 
> Yes, we should -- it's an actual bug as well as just not being
> very consistent.
> 
>> I still have access to a PP64 BE host to test.
> 
> In an ideal world the bugs would cause "make check" and/or
> "make check-acceptance" to fail on BE hosts :-)

I gave it a try manually with an Aspeed machine and the kernel fails to boot.

Download an OpenBMC witherspoon flash image : 

  wget https://openpower.xyz/job/openbmc-build/lastSuccessfulBuild/distro=ubuntu,label=builder,target=witherspoon/artifact/deploy/images/witherspoon/obmc-phosphor-image-witherspoon.ubi.mtd

and run :

  qemu-system-arm -M witherspoon-bmc -nic user -drive file=obmc-phosphor-image-witherspoon.ubi.mtd,format=raw,if=mtd -nographic 

The kernel hangs right after activating the translation :

#ifdef CONFIG_MMU
 ARM_BE8(	orr	r0, r0, #1 << 25 )	@ big-endian page tables
		mrcne   p15, 0, r6, c2, c0, 2   @ read ttb control reg
		orrne	r0, r0, #1		@ MMU enabled
		movne	r1, #0xfffffffd		@ domain 0 = client
		bic     r6, r6, #1 << 31        @ 32-bit translation system
		bic     r6, r6, #(7 << 0) | (1 << 4)	@ use only ttbr0
		mcrne	p15, 0, r3, c2, c0, 0	@ load page table pointer
		mcrne	p15, 0, r1, c3, c0, 0	@ load domain access control
		mcrne   p15, 0, r6, c2, c0, 2   @ load ttb control
#endif
		mcr	p15, 0, r0, c7, c5, 4	@ ISB
 *there* -->	mcr	p15, 0, r0, c1, c0, 0	@ load control register
		mrc	p15, 0, r0, c1, c0, 0	@ and read it back
		mov	r0, #0
		mcr	p15, 0, r0, c7, c5, 4	@ ISB
		mov	pc, r12


C.


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

end of thread, other threads:[~2020-06-17 15:25 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-21 19:21 [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines Havard Skinnemoen
2020-05-21 19:21 ` [PATCH 1/6] npcm7xx: Add config symbol Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-05-21 19:21 ` [PATCH 2/6] hw/misc: Add NPCM7xx System Global Control Registers device model Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-06-09  7:24   ` Cédric Le Goater
2020-05-21 19:21 ` [PATCH 3/6] hw/misc: Add NPCM7xx Clock Controller " Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-06-09  7:24   ` Cédric Le Goater
2020-05-21 19:21 ` [PATCH 4/6] hw/timer: Add NPCM7xx Timer " Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-05-21 19:21 ` [PATCH 5/6] hw/arm: Add NPCM730 and NPCM750 SoC models Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-06-09  7:24   ` Cédric Le Goater
2020-06-09 23:06     ` Havard Skinnemoen
2020-06-11  6:12       ` Cédric Le Goater
2020-06-11  9:38         ` Peter Maydell
2020-06-17 15:24           ` Cédric Le Goater
2020-05-21 19:21 ` [PATCH 6/6] hw/arm: Add two NPCM7xx-based machines Havard Skinnemoen
2020-06-09  1:36   ` Joel Stanley
2020-06-09  7:24   ` Cédric Le Goater
2020-05-22  4:57 ` [PATCH 0/6] Add Nuvoton NPCM730/NPCM750 SoCs and two BMC machines no-reply
2020-06-08 22:14 ` Havard Skinnemoen
2020-06-09  1:39   ` Joel Stanley
2020-06-09 16:36     ` Havard Skinnemoen
2020-06-09  7:31   ` Cédric Le Goater
2020-06-09  9:38     ` Peter Maydell
2020-06-09 16:30       ` Havard Skinnemoen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).