QEMU-Arm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Bin Meng <bin.meng@processmission.com>
To: QEMU <qemu-devel@nongnu.org>
Cc: qemu-arm@nongnu.org
Subject: [PATCH v2 08/32] hw/misc: Add Phytium E2000 DDR controller
Date: Tue,  8 Sep 2026 18:41:17 +0800	[thread overview]
Message-ID: <20260908104159.1621764-9-bin.meng@processmission.com> (raw)
In-Reply-To: <20260908104159.1621764-1-bin.meng@processmission.com>

Model the E2000 DDR initialization and training compatibility window.
Keep ordinary aligned registers as persistent storage and implement
the indirect selector/value interface used by the vendor PBF.

Return the expected initialization, PHY training, update, and BIST
results, including the training-error range. This models the firmware
contract without attempting a timing-accurate DDR PHY.

Signed-off-by: Bin Meng <bin.meng@processmission.com>
---

(no changes since v1)

 include/hw/misc/phytium_e2000_ddr.h |  23 ++++
 hw/misc/phytium_e2000_ddr.c         | 197 ++++++++++++++++++++++++++++
 hw/misc/meson.build                 |   1 +
 3 files changed, 221 insertions(+)
 create mode 100644 include/hw/misc/phytium_e2000_ddr.h
 create mode 100644 hw/misc/phytium_e2000_ddr.c

diff --git a/include/hw/misc/phytium_e2000_ddr.h b/include/hw/misc/phytium_e2000_ddr.h
new file mode 100644
index 0000000000..91dc661106
--- /dev/null
+++ b/include/hw/misc/phytium_e2000_ddr.h
@@ -0,0 +1,23 @@
+/*
+ * Phytium E2000 DDR training status
+ *
+ * Copyright (c) 2026 Process Mission
+ *
+ * Author:
+ *   Bin Meng <bin.meng@processmission.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_PHYTIUM_E2000_DDR_H
+#define HW_MISC_PHYTIUM_E2000_DDR_H
+
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_PHYTIUM_E2000_DDR "phytium-e2000-ddr"
+OBJECT_DECLARE_SIMPLE_TYPE(PhytiumE2000DDRState, PHYTIUM_E2000_DDR)
+
+#define PHYTIUM_E2000_DDR_MMIO_SIZE 0x400
+
+#endif
diff --git a/hw/misc/phytium_e2000_ddr.c b/hw/misc/phytium_e2000_ddr.c
new file mode 100644
index 0000000000..ab46a46961
--- /dev/null
+++ b/hw/misc/phytium_e2000_ddr.c
@@ -0,0 +1,197 @@
+/*
+ * Phytium E2000 DDR training status
+ *
+ * The vendor firmware accesses controller and PHY state through an indexed
+ * selector/value window. This functional model reproduces the completion and
+ * error predicates used during boot; it does not simulate analog DDR training
+ * or generate physical calibration results.
+ *
+ * Copyright (c) 2026 Process Mission
+ *
+ * Author:
+ *   Bin Meng <bin.meng@processmission.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/misc/phytium_e2000_ddr.h"
+
+#include "hw/core/register.h"
+#include "migration/vmstate.h"
+#include "qemu/module.h"
+
+REG32(SELECTOR, 0x80)
+REG32(VALUE, 0x84)
+
+#define PHYTIUM_E2000_DDR_R_MAX                  \
+    (PHYTIUM_E2000_DDR_MMIO_SIZE / sizeof(uint32_t))
+/*
+ * Selectors encode a register index as a byte offset. PBF uses separate
+ * direct, indirect, and training banks distinguished by 0x800 and 0x1000
+ * index biases.
+ */
+#define PHYTIUM_E2000_DDR_SELECTOR(reg)          ((reg) * 4)
+#define PHYTIUM_E2000_DDR_INDIRECT_SELECTOR(reg) (((reg) + 0x800) * 4)
+#define PHYTIUM_E2000_DDR_TRAINING_SELECTOR(reg) (((reg) + 0x1000) * 4)
+#define PHYTIUM_E2000_DDR_TRAINING_ERR_FIRST     0xc72
+#define PHYTIUM_E2000_DDR_TRAINING_ERR_LAST      0xc79
+
+struct PhytiumE2000DDRState {
+    SysBusDevice parent_obj;
+
+    uint32_t regs[PHYTIUM_E2000_DDR_R_MAX];
+    RegisterInfo regs_info[PHYTIUM_E2000_DDR_R_MAX];
+    RegisterAccessInfo regs_access_info[PHYTIUM_E2000_DDR_R_MAX];
+};
+
+static uint64_t phytium_e2000_ddr_value_post_read(RegisterInfo *reg,
+                                                  uint64_t value)
+{
+    PhytiumE2000DDRState *s = PHYTIUM_E2000_DDR(reg->opaque);
+    uint32_t selector = s->regs[R_SELECTOR];
+
+    /*
+     * These fixed selectors are controller/PHY polls observed in the tested
+     * firmware. Return only the ready and completion bits that its loops
+     * require, without assigning behavior to the surrounding register bank.
+     */
+    switch (selector) {
+    case PHYTIUM_E2000_DDR_INDIRECT_SELECTOR(0xdc):
+        return BIT(0);
+    case PHYTIUM_E2000_DDR_SELECTOR(0x256):
+        return BIT(0) | BIT(25);
+    case PHYTIUM_E2000_DDR_INDIRECT_SELECTOR(0x76):
+        return BIT(0) | BIT(14) | BIT(27);
+    case PHYTIUM_E2000_DDR_SELECTOR(0x10f):
+        return 0x40U << 24;
+    case PHYTIUM_E2000_DDR_SELECTOR(0x229):
+        return BIT(0);
+    case PHYTIUM_E2000_DDR_SELECTOR(0x257):
+        return BIT(3);
+    case PHYTIUM_E2000_DDR_SELECTOR(0x255):
+        return BIT(16);
+    case PHYTIUM_E2000_DDR_SELECTOR(0x1d5):
+        return BIT(16) | BIT(24) | BIT(25);
+    default:
+        /*
+         * The training bank is read repeatedly for lane state and error
+         * summaries. Error selectors report no failure; the remaining values
+         * are deterministic so repeated sweeps see stable lane data.
+         */
+        if (selector >= PHYTIUM_E2000_DDR_TRAINING_SELECTOR(0) &&
+            selector < PHYTIUM_E2000_DDR_TRAINING_SELECTOR(0x1000)) {
+            uint32_t index = selector / sizeof(uint32_t) - 0x1000;
+
+            if (index >= PHYTIUM_E2000_DDR_TRAINING_ERR_FIRST &&
+                index <= PHYTIUM_E2000_DDR_TRAINING_ERR_LAST) {
+                return 0;
+            }
+            /*
+             * Preserve the masks and flag combinations checked by the PBF
+             * training algorithm for these recurring low-byte selectors.
+             */
+            if ((index & 0xff) == 0x34) {
+                return 0x00000fff;
+            }
+            if ((index & 0xff) == 0x38) {
+                return BIT(4) | BIT(5);
+            }
+            if ((index & 0xff) == 0x83) {
+                return 0;
+            }
+            if ((index & 0xff) == 0x3b) {
+                return 0x01234567U | BIT(26) | BIT(27);
+            }
+            return 0x01234567U;
+        }
+        /*
+         * Unclassified offsets retain ordinary register storage. This keeps
+         * setup writes readable without pretending they affect DDR timing.
+         */
+        return value;
+    }
+}
+
+static const MemoryRegionOps phytium_e2000_ddr_ops = {
+    .read = register_read_memory,
+    .write = register_write_memory,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+static void phytium_e2000_ddr_reset(DeviceState *dev)
+{
+    PhytiumE2000DDRState *s = PHYTIUM_E2000_DDR(dev);
+    int i;
+
+    for (i = 0; i < PHYTIUM_E2000_DDR_R_MAX; i++) {
+        register_reset(&s->regs_info[i]);
+    }
+}
+
+static void phytium_e2000_ddr_init(Object *obj)
+{
+    PhytiumE2000DDRState *s = PHYTIUM_E2000_DDR(obj);
+    RegisterInfoArray *reg_array;
+    int i;
+
+    /*
+     * Firmware may touch any word in this compact window before selecting a
+     * status source, so create registerinfo metadata for the full aperture and
+     * specialize only SELECTOR and VALUE.
+     */
+    for (i = 0; i < PHYTIUM_E2000_DDR_R_MAX; i++) {
+        s->regs_access_info[i].name = "DDR_STATUS";
+        s->regs_access_info[i].addr = i * sizeof(uint32_t);
+    }
+    s->regs_access_info[R_SELECTOR].name = "SELECTOR";
+    s->regs_access_info[R_VALUE].name = "VALUE";
+    s->regs_access_info[R_VALUE].ro = UINT32_MAX;
+    s->regs_access_info[R_VALUE].post_read =
+        phytium_e2000_ddr_value_post_read;
+
+    reg_array = register_init_block32(
+        DEVICE(obj), s->regs_access_info, PHYTIUM_E2000_DDR_R_MAX,
+        s->regs_info, s->regs, &phytium_e2000_ddr_ops, false,
+        PHYTIUM_E2000_DDR_MMIO_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &reg_array->mem);
+}
+
+static const VMStateDescription phytium_e2000_ddr_vmsd = {
+    .name = TYPE_PHYTIUM_E2000_DDR,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, PhytiumE2000DDRState,
+                             PHYTIUM_E2000_DDR_R_MAX),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void phytium_e2000_ddr_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &phytium_e2000_ddr_vmsd;
+    device_class_set_legacy_reset(dc, phytium_e2000_ddr_reset);
+}
+
+static const TypeInfo phytium_e2000_ddr_info = {
+    .name = TYPE_PHYTIUM_E2000_DDR,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PhytiumE2000DDRState),
+    .instance_init = phytium_e2000_ddr_init,
+    .class_init = phytium_e2000_ddr_class_init,
+};
+
+static void phytium_e2000_ddr_register_types(void)
+{
+    type_register_static(&phytium_e2000_ddr_info);
+}
+
+type_init(phytium_e2000_ddr_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 9790afa104..dca5f67ca9 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -16,6 +16,7 @@ system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c'))
 system_ss.add(when: 'CONFIG_INTEGRATOR_DEBUG', if_true: files('arm_integrator_debug.c'))
 system_ss.add(when: 'CONFIG_A9SCU', if_true: files('a9scu.c'))
 system_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
+system_ss.add(when: 'CONFIG_PHYTIUM_E2000', if_true: files('phytium_e2000_ddr.c'))
 
 system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c'))
 
-- 
2.53.0



  parent reply	other threads:[~2026-09-08 10:44 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08 10:41 [PATCH v2 00/32] hw/arm: Add Phytium E2000Q SoC and board support Bin Meng
2026-09-08 10:41 ` [PATCH v2 01/32] hw/arm: Add Phytium E2000 SoC and Phytium Pi machine Bin Meng
2026-09-08 10:41 ` [PATCH v2 02/32] hw/arm: phytium: Add Phytium E2000 PCIe host Bin Meng
2026-09-08 10:41 ` [PATCH v2 04/32] hw/sd: Add Phytium E2000 MCI controller Bin Meng
2026-09-08 10:41 ` [PATCH v2 05/32] hw/arm: phytium: Connect Phytium E2000 MCI controllers Bin Meng
2026-09-08 10:41 ` [PATCH v2 07/32] hw/arm: phytium: Connect Phytium E2000 GEM controllers Bin Meng
2026-09-08 10:41 ` Bin Meng [this message]
2026-09-08 10:41 ` [PATCH v2 09/32] hw/arm: phytium: Connect the Phytium E2000 DDR controller Bin Meng
2026-09-08 10:41 ` [PATCH v2 10/32] hw/misc: Add Phytium E2000 MHU doorbell Bin Meng
2026-09-08 10:41 ` [PATCH v2 11/32] hw/arm: phytium: Connect the Phytium E2000 MHU Bin Meng
2026-09-08 10:41 ` [PATCH v2 12/32] hw/ssi: Add Phytium E2000 QSPI controller Bin Meng
2026-09-08 10:41 ` [PATCH v2 13/32] hw/arm: phytium: Connect the " Bin Meng
2026-09-08 10:41 ` [PATCH v2 14/32] hw/misc: Add Phytium E2000 PBR model Bin Meng
2026-09-08 10:41 ` [PATCH v2 15/32] hw/arm: phytium: Integrate the Phytium E2000 PBR Bin Meng
2026-09-08 10:41 ` [PATCH v2 16/32] hw/arm: phytium: Add Phytium E2000 control region placeholders Bin Meng
2026-09-08 10:41 ` [PATCH v2 17/32] hw/misc: Support Phytium E2000 SCMI CPU power control Bin Meng
2026-09-08 10:41 ` [PATCH v2 18/32] hw/arm: phytium: Select the Phytium E2000 PBR boot medium Bin Meng
2026-09-08 10:41 ` [PATCH v2 19/32] hw/arm: phytium: Connect the Phytium E2000 I2C controller Bin Meng
2026-09-08 10:41 ` [PATCH v2 20/32] hw/arm: phytium: Add Phytium E2000 xHCI controllers Bin Meng
2026-09-08 10:41 ` [PATCH v2 21/32] hw/misc: Model the Phytium E2000 random generator Bin Meng
2026-09-08 10:41 ` [PATCH v2 22/32] hw/arm: phytium: Connect " Bin Meng
2026-09-08 10:41 ` [PATCH v2 23/32] hw/arm: phytium: Support Phytium E2000 direct Linux boot Bin Meng
2026-09-08 10:41 ` [PATCH v2 24/32] hw/arm: phytium: Add Phytium E2000Q COMe machine Bin Meng
2026-09-08 10:41 ` [PATCH v2 26/32] hw/arm: phytium: Connect the Phytium E2000Q COMe QSPI flash Bin Meng
2026-09-08 10:41 ` [PATCH v2 27/32] hw/arm: phytium: Add Phytium E2000 AHCI controllers Bin Meng
2026-09-08 10:41 ` [PATCH v2 28/32] hw/arm: Add Phytium E2000 Linux SCMI channel Bin Meng
2026-09-08 10:41 ` [PATCH v2 29/32] hw/arm: phytium: Connect the Phytium E2000 SMMUv3 Bin Meng
2026-09-08 10:41 ` [PATCH v2 30/32] docs/system/arm: Document Phytium E2000 machines Bin Meng
2026-09-08 10:41 ` [PATCH v2 31/32] tests/functional/aarch64: Add Phytium Pi boot tests Bin Meng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260908104159.1621764-9-bin.meng@processmission.com \
    --to=bin.meng@processmission.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox