This patch introduces an initial ASPEED PCIe PHY/host controller model to
support the AST2600 SoC. It provides a simple register block with MMIO
read/write callbacks, integration into the build system, and trace events
for debugging.

Key changes:

1. PCIe PHY MMIO read/write callbacks
   Implemented aspeed_pcie_phy_read() and aspeed_pcie_phy_write() to
   handle 32-bit register accesses.

2. Build system and Kconfig integration
   Added CONFIG_PCI_EXPRESS_ASPEED in hw/pci-host/Kconfig and meson
   rules.
   Updated ASPEED_SOC in hw/arm/Kconfig to imply PCI_DEVICES and select
   PCI_EXPRESS_ASPEED.

3. Trace events for debug
   New tracepoints aspeed_pcie_phy_read and aspeed_pcie_phy_write allow
   monitoring MMIO accesses.

4. Register space and defaults (AST2600 reference)
   Expose a 0x100 register space, as documented in the AST2600 datasheet.
   On reset, set default values:
   PEHR_ID: Vendor ID = ASPEED, Device ID = 0x1150
   PEHR_CLASS_CODE = 0x06040006
   PEHR_DATALINK = 0xD7040022
   PEHR_LINK: bit[5] set to 1 to indicate link up.

This provides a skeleton device for the AST2600 platform. It enables
firmware to detect the PCIe link as up by default and allows future
extension.

This commit is the starting point of the series to introduce ASPEED PCIe
Root Complex (RC) support. Based on previous work from Cédric Le Goater,
the following commits in this series extend and refine the implementation:

- Add a PCIe Root Port so that devices can be attached without requiring an
extra bridge.
- Restrict the Root Port device instantiation to the AST2600 platform.
- Integrate aspeed_cfg_translate_write() to support both AST2600 and AST2700.
- Add MSI support and a preliminary RC IOMMU address space.
- Fix issues with MSI interrupt clearing.
- Extend support to the AST2700 SoC.
- Drop the AST2600 RC_L support.
- Introduce PCIe RC functional tests covering both AST2600 and AST2700.

Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com>
---
 include/hw/pci-host/aspeed_pcie.h |  42 ++++++++
 hw/pci-host/aspeed_pcie.c         | 157 ++++++++++++++++++++++++++++++
 hw/arm/Kconfig                    |   3 +
 hw/pci-host/Kconfig               |   4 +
 hw/pci-host/meson.build           |   1 +
 hw/pci-host/trace-events          |   4 +
 6 files changed, 211 insertions(+)
 create mode 100644 include/hw/pci-host/aspeed_pcie.h
 create mode 100644 hw/pci-host/aspeed_pcie.c

diff --git a/include/hw/pci-host/aspeed_pcie.h 
b/include/hw/pci-host/aspeed_pcie.h
new file mode 100644
index 0000000000..d9fb829048
--- /dev/null
+++ b/include/hw/pci-host/aspeed_pcie.h
@@ -0,0 +1,42 @@
+/*
+ * ASPEED PCIe Host Controller
+ *
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ * Copyright (c) 2022 Cédric Le Goater <c...@kaod.org>
+ *
+ * Authors:
+ *   Cédric Le Goater <c...@kaod.org>
+ *   Jamin Lin <jamin_...@aspeedtech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Based on previous work from Cédric Le Goater.
+ * Modifications extend support for the ASPEED AST2600 and AST2700 platforms.
+ */
+
+#ifndef ASPEED_PCIE_H
+#define ASPEED_PCIE_H
+
+#include "hw/sysbus.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pcie_host.h"
+#include "qom/object.h"
+
+#define TYPE_ASPEED_PCIE_PHY "aspeed.pcie-phy"
+OBJECT_DECLARE_TYPE(AspeedPCIEPhyState, AspeedPCIEPhyClass, ASPEED_PCIE_PHY);
+
+struct AspeedPCIEPhyState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion mmio;
+    uint32_t *regs;
+    uint32_t id;
+};
+
+struct AspeedPCIEPhyClass {
+    SysBusDeviceClass parent_class;
+
+    uint64_t nr_regs;
+};
+
+#endif /* ASPEED_PCIE_H */
diff --git a/hw/pci-host/aspeed_pcie.c b/hw/pci-host/aspeed_pcie.c
new file mode 100644
index 0000000000..110c963779
--- /dev/null
+++ b/hw/pci-host/aspeed_pcie.c
@@ -0,0 +1,157 @@
+/*
+ * ASPEED PCIe Host Controller
+ *
+ * Copyright (C) 2025 ASPEED Technology Inc.
+ * Copyright (c) 2022 Cédric Le Goater <c...@kaod.org>
+ *
+ * Authors:
+ *   Cédric Le Goater <c...@kaod.org>
+ *   Jamin Lin <jamin_...@aspeedtech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Based on previous work from Cédric Le Goater.
+ * Modifications extend support for the ASPEED AST2600 and AST2700 platforms.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/registerfields.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_host.h"
+#include "hw/pci-host/aspeed_pcie.h"
+#include "hw/pci/msi.h"
+#include "trace.h"
+
+/*
+ * PCIe PHY
+ *
+ * PCIe Host Controller (PCIEH)
+ */
+
+/* AST2600 */
+REG32(PEHR_ID,     0x00)
+    FIELD(PEHR_ID, DEV, 16, 16)
+REG32(PEHR_CLASS_CODE,  0x04)
+REG32(PEHR_DATALINK,    0x10)
+REG32(PEHR_PROTECT,     0x7C)
+    FIELD(PEHR_PROTECT, LOCK, 0, 8)
+REG32(PEHR_LINK,        0xC0)
+    FIELD(PEHR_LINK, STS, 5, 1)
+
+#define ASPEED_PCIE_PHY_UNLOCK  0xA8
+
+static uint64_t aspeed_pcie_phy_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque);
+    uint32_t reg = addr >> 2;
+    uint32_t value = 0;
+
+    value = s->regs[reg];
+
+    trace_aspeed_pcie_phy_read(s->id, addr, value);
+
+    return value;
+}
+
+static void aspeed_pcie_phy_write(void *opaque, hwaddr addr, uint64_t data,
+                                  unsigned int size)
+{
+    AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(opaque);
+    uint32_t reg = addr >> 2;
+
+    trace_aspeed_pcie_phy_write(s->id, addr, data);
+
+    switch (reg) {
+    case R_PEHR_PROTECT:
+        data &= R_PEHR_PROTECT_LOCK_MASK;
+        s->regs[reg] = !!(data == ASPEED_PCIE_PHY_UNLOCK);
+        break;
+    default:
+        s->regs[reg] = data;
+        break;
+    }
+}
+
+static const MemoryRegionOps aspeed_pcie_phy_ops = {
+    .read = aspeed_pcie_phy_read,
+    .write = aspeed_pcie_phy_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static void aspeed_pcie_phy_reset(DeviceState *dev)
+{
+    AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev);
+    AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s);
+
+    memset(s->regs, 0, apc->nr_regs << 2);
+
+    s->regs[R_PEHR_ID] =
+        (0x1150 << R_PEHR_ID_DEV_SHIFT) | PCI_VENDOR_ID_ASPEED;
+    s->regs[R_PEHR_CLASS_CODE] = 0x06040006;
+    s->regs[R_PEHR_DATALINK] = 0xD7040022;
+    s->regs[R_PEHR_LINK] = R_PEHR_LINK_STS_MASK;
+}
+
+static void aspeed_pcie_phy_realize(DeviceState *dev, Error **errp)
+{
+    AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev);
+    AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_GET_CLASS(s);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    g_autofree char *name;
+
+    s->regs = g_new(uint32_t, apc->nr_regs);
+    name = g_strdup_printf(TYPE_ASPEED_PCIE_PHY ".regs.%d", s->id);
+    memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_pcie_phy_ops, s, name,
+                          apc->nr_regs << 2);
+    sysbus_init_mmio(sbd, &s->mmio);
+}
+
+static void aspeed_pcie_phy_unrealize(DeviceState *dev)
+{
+    AspeedPCIEPhyState *s = ASPEED_PCIE_PHY(dev);
+
+    g_free(s->regs);
+    s->regs = NULL;
+}
+
+static const Property aspeed_pcie_phy_props[] = {
+    DEFINE_PROP_UINT32("id", AspeedPCIEPhyState, id, 0),
+};
+
+static void aspeed_pcie_phy_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    AspeedPCIEPhyClass *apc = ASPEED_PCIE_PHY_CLASS(klass);
+
+    dc->desc = "ASPEED PCIe Phy";
+    dc->realize = aspeed_pcie_phy_realize;
+    dc->unrealize = aspeed_pcie_phy_unrealize;
+    device_class_set_legacy_reset(dc, aspeed_pcie_phy_reset);
+    device_class_set_props(dc, aspeed_pcie_phy_props);
+
+    apc->nr_regs = 0x100 >> 2;
+}
+
+static const TypeInfo aspeed_pcie_phy_info = {
+    .name       = TYPE_ASPEED_PCIE_PHY,
+    .parent     = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AspeedPCIEPhyState),
+    .class_init = aspeed_pcie_phy_class_init,
+    .class_size = sizeof(AspeedPCIEPhyClass),
+};
+
+static void aspeed_pcie_register_types(void)
+{
+    type_register_static(&aspeed_pcie_phy_info);
+}
+
+type_init(aspeed_pcie_register_types);
+
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 3baa6c6c74..b44b85f436 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -541,6 +541,7 @@ config ASPEED_SOC
     bool
     default y
     depends on TCG && ARM
+    imply PCI_DEVICES
     select DS1338
     select FTGMAC100
     select I2C
@@ -561,6 +562,8 @@ config ASPEED_SOC
     select MAX31785
     select FSI_APB2OPB_ASPEED
     select AT24C
+    select PCI_EXPRESS
+    select PCI_EXPRESS_ASPEED
 
 config MPS2
     bool
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 9824fa188d..8cbb8304a3 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -46,6 +46,10 @@ config PCI_I440FX
     select PCI
     select PAM
 
+config PCI_EXPRESS_ASPEED
+    bool
+    select PCI_EXPRESS
+
 config PCI_EXPRESS_Q35
     bool
     select PCI_EXPRESS
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 937a0f72ac..86b754d0b0 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -2,6 +2,7 @@ pci_ss = ss.source_set()
 pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c'))
 pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c'))
 pci_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64120.c'))
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_ASPEED', if_true: files('aspeed_pcie.c'))
 pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: 
files('designware.c'))
 pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c'))
 pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], 
if_true: files('gpex-acpi.c'))
diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events
index 0a816b9aa1..3438516756 100644
--- a/hw/pci-host/trace-events
+++ b/hw/pci-host/trace-events
@@ -1,5 +1,9 @@
 # See docs/devel/tracing.rst for syntax documentation.
 
+# aspeed_pcie.c
+aspeed_pcie_phy_read(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 
0x%" PRIx64 " value 0x%" PRIx32
+aspeed_pcie_phy_write(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 
0x%" PRIx64 " value 0x%" PRIx32
+
 # bonito.c
 bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address 
is smaller then 32-bit, addr: 0x%"PRIx64", size: %u"
 
-- 
2.43.0


Reply via email to