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), ®_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
next prev 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