From: Yubin Zou <yubinz@google.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Tyrone Ting <kfting@nuvoton.com>, Hao Wu <wuhaotsh@google.com>,
qemu-arm@nongnu.org, Peter Maydell <peter.maydell@linaro.org>,
Yubin Zou <yubinz@google.com>,
Titus Rwantare <titusr@google.com>
Subject: [PATCH 4/7] hw/pci-host: add Nuvoton PCIe root port
Date: Tue, 09 Sep 2025 22:10:59 +0000 [thread overview]
Message-ID: <20250909-pcie-root-upstream-v1-4-d85883b2688d@google.com> (raw)
In-Reply-To: <20250909-pcie-root-upstream-v1-0-d85883b2688d@google.com>
From: Titus Rwantare <titusr@google.com>
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/arm/npcm8xx.c | 3 +-
hw/pci-host/npcm_pcierc.c | 137 ++++++++++++++++++++++++++++++++++++++
include/hw/pci-host/npcm_pcierc.h | 22 +++++-
3 files changed, 160 insertions(+), 2 deletions(-)
diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c
index 9b3e648e3fc3ca4352d5c8d310a19ea462e62cc7..f7a5ae2d121ffec99c519b484503e71dc8a43695 100644
--- a/hw/arm/npcm8xx.c
+++ b/hw/arm/npcm8xx.c
@@ -51,6 +51,7 @@
#define NPCM8XX_MC_BA 0xf0824000
#define NPCM8XX_RNG_BA 0xf000b000
#define NPCM8XX_PCIERC_BA 0xe1000000
+#define NPCM8XX_PCIE_ROOT_BA 0xe8000000
/* ADC Module */
#define NPCM8XX_ADC_BA 0xf000c000
@@ -772,13 +773,13 @@ static void npcm8xx_realize(DeviceState *dev, Error **errp)
/* PCIe RC */
sysbus_realize(SYS_BUS_DEVICE(&s->pcierc), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcierc), 0, NPCM8XX_PCIERC_BA);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcierc), 1, NPCM8XX_PCIE_ROOT_BA);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcierc), 0,
npcm8xx_irq(s, NPCM8XX_PCIE_RC_IRQ));
create_unimplemented_device("npcm8xx.shm", 0xc0001000, 4 * KiB);
create_unimplemented_device("npcm8xx.gicextra", 0xdfffa000, 24 * KiB);
create_unimplemented_device("npcm8xx.vdmx", 0xe0800000, 4 * KiB);
- create_unimplemented_device("npcm8xx.rootc", 0xe8000000, 128 * MiB);
create_unimplemented_device("npcm8xx.kcs", 0xf0007000, 4 * KiB);
create_unimplemented_device("npcm8xx.gfxi", 0xf000e000, 4 * KiB);
create_unimplemented_device("npcm8xx.fsw", 0xf000f000, 4 * KiB);
diff --git a/hw/pci-host/npcm_pcierc.c b/hw/pci-host/npcm_pcierc.c
index bffdec71acaba6562856b3bdd8aec07c3c153323..a1767335fe79a30464acf32ae94fc14e417c89eb 100644
--- a/hw/pci-host/npcm_pcierc.c
+++ b/hw/pci-host/npcm_pcierc.c
@@ -203,6 +203,7 @@ static void npcm_pcierc_write_window(NPCMPCIERCState *s, hwaddr addr,
npcm_pcie_update_window_maps(s);
}
+/* read root complex configuration registers */
static uint64_t npcm_pcierc_cfg_read(void *opaque, hwaddr addr, unsigned size)
{
NPCMPCIERCState *s = NPCM_PCIERC(opaque);
@@ -248,6 +249,7 @@ static uint64_t npcm_pcierc_cfg_read(void *opaque, hwaddr addr, unsigned size)
return ret;
}
+/* write root complex configuration registers */
static void npcm_pcierc_cfg_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
@@ -291,6 +293,53 @@ static void npcm_pcierc_cfg_write(void *opaque, hwaddr addr, uint64_t data,
}
}
+/* read PCIe configuration space */
+static uint64_t npcm_pcie_host_config_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ NPCMPCIERCState *s = NPCM_PCIERC(opaque);
+ PCIHostState *pcih = PCI_HOST_BRIDGE(opaque);
+ int bus = NPCM_PCIE_RCCFGNUM_BUS(s->rccfgnum);
+ uint8_t devfn = NPCM_PCIE_RCCFGNUM_DEVFN(s->rccfgnum);
+ PCIDevice *pcid = pci_find_device(pcih->bus, bus, devfn);
+
+ if (pcid) {
+ return pci_host_config_read_common(pcid, addr,
+ pci_config_size(pcid),
+ size);
+ }
+ return 0;
+}
+
+/* write PCIe configuration space */
+static void npcm_pcie_host_config_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ NPCMPCIERCState *s = NPCM_PCIERC(opaque);
+ PCIHostState *pcih = PCI_HOST_BRIDGE(opaque);
+ int bus = NPCM_PCIE_RCCFGNUM_BUS(s->rccfgnum);
+ uint8_t devfn = NPCM_PCIE_RCCFGNUM_DEVFN(s->rccfgnum);
+ PCIDevice *pcid = pci_find_device(pcih->bus, bus, devfn);
+
+ if (pcid) {
+ pci_host_config_write_common(pcid, addr,
+ pci_config_size(pcid),
+ data,
+ size);
+ }
+}
+
+static AddressSpace *npcm_pcierc_set_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+ NPCMPCIERCState *s = NPCM_PCIERC(opaque);
+
+ return &s->pcie_space;
+}
+
+static const PCIIOMMUOps npcm_pcierc_iommu_ops = {
+ .get_address_space = npcm_pcierc_set_iommu,
+};
+
static void npcm_pcierc_reset_pcie_windows(NPCMPCIERCState *s)
{
memset(s->axi2pcie, 0, sizeof(s->axi2pcie));
@@ -338,15 +387,73 @@ static const MemoryRegionOps npcm_pcierc_cfg_ops = {
},
};
+static const MemoryRegionOps npcm_pcie_cfg_space_ops = {
+ .read = npcm_pcie_host_config_read,
+ .write = npcm_pcie_host_config_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ }
+};
+
+static void npcm_pcie_set_irq(void *opaque, int irq_num, int level)
+{
+ NPCMPCIERCState *s = NPCM_PCIERC(opaque);
+
+ qemu_set_irq(s->irq, level);
+}
+
static void npcm_pcierc_realize(DeviceState *dev, Error **errp)
{
NPCMPCIERCState *s = NPCM_PCIERC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+ PCIDevice *root = pci_new(PCI_DEVFN(0, 0), TYPE_NPCM_PCIE_ROOT_PORT);
memory_region_init_io(&s->mmio, OBJECT(s), &npcm_pcierc_cfg_ops,
s, TYPE_NPCM_PCIERC, 4 * KiB);
sysbus_init_mmio(sbd, &s->mmio);
sysbus_init_irq(sbd, &s->irq);
+
+ /* IO memory region is needed to create a PCI bus, but is unused on ARM */
+ memory_region_init(&s->pcie_io, OBJECT(s), "npcm-pcie-io", 16);
+
+ /*
+ * pcie_root is a 128 MiB memory region in the BMC physical address space
+ * in which all PCIe windows must have their programmable source or
+ * destination address
+ */
+ memory_region_init_io(&s->pcie_root, OBJECT(s), &npcm_pcie_cfg_space_ops,
+ s, "npcm-pcie-config", 128 * MiB);
+ sysbus_init_mmio(sbd, &s->pcie_root);
+
+ pci->bus = pci_register_root_bus(dev, "pcie",
+ npcm_pcie_set_irq,
+ pci_swizzle_map_irq_fn,
+ s, &s->pcie_root, &s->pcie_io,
+ 0, 4, TYPE_PCIE_BUS);
+
+ address_space_init(&s->pcie_space, &s->pcie_root, "pcie-address-space");
+ pci_realize_and_unref(root, pci->bus, &error_fatal);
+ pci_setup_iommu(pci->bus, &npcm_pcierc_iommu_ops, s);
+}
+
+static void npcm_pcie_root_port_realize(DeviceState *dev, Error **errp)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ rpc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
static void npcm_pcierc_instance_init(Object *obj)
@@ -369,6 +476,28 @@ static void npcm_pcierc_class_init(ObjectClass *klass, const void *data)
dc->fw_name = "pci";
}
+static void npcm_pcie_rp_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pk = PCI_DEVICE_CLASS(klass);
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
+
+ dc->desc = "Nuvoton PCIe Root Port";
+ dc->user_creatable = false;
+
+ device_class_set_parent_realize(dc,
+ npcm_pcie_root_port_realize,
+ &rpc->parent_realize);
+
+ /* TODO(b/229132071) replace with real values */
+ pk->vendor_id = PCI_VENDOR_ID_QEMU;
+ pk->device_id = 0;
+ pk->class_id = PCI_CLASS_BRIDGE_PCI;
+
+ rpc->exp_offset = NPCM_PCIE_HEADER_OFFSET; /* Express capabilities offset */
+ rpc->aer_offset = NPCM_PCIE_AER_OFFSET;
+}
+
static const TypeInfo npcm_pcierc_type_info = {
.name = TYPE_NPCM_PCIERC,
.parent = TYPE_PCIE_HOST_BRIDGE,
@@ -377,9 +506,17 @@ static const TypeInfo npcm_pcierc_type_info = {
.class_init = npcm_pcierc_class_init,
};
+static const TypeInfo npcm_pcie_port_type_info = {
+ .name = TYPE_NPCM_PCIE_ROOT_PORT,
+ .parent = TYPE_PCIE_ROOT_PORT,
+ .instance_size = sizeof(NPCMPCIERootPort),
+ .class_init = npcm_pcie_rp_class_init,
+};
+
static void npcm_pcierc_register_types(void)
{
type_register_static(&npcm_pcierc_type_info);
+ type_register_static(&npcm_pcie_port_type_info);
}
type_init(npcm_pcierc_register_types)
diff --git a/include/hw/pci-host/npcm_pcierc.h b/include/hw/pci-host/npcm_pcierc.h
index 410b34d1c1ced0e25f63fc7693d87bb625a80776..a47eae0084b88ba4388681b24ab97f77a4338594 100644
--- a/include/hw/pci-host/npcm_pcierc.h
+++ b/include/hw/pci-host/npcm_pcierc.h
@@ -23,11 +23,14 @@
#include "hw/sysbus.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie_host.h"
+#include "hw/pci/pcie_port.h"
#include "qom/object.h"
/* PCIe Root Complex Registers */
-#define LINKSTAT 0x92
+#define NPCM_PCIE_LINK_CTRL 0x90
#define NPCM_PCIERC_RCCFGNUM 0x140 /* Configuration Number */
+#define NPCM_PCIE_RCCFGNUM_BUS(a) (((a) >> 8) & 0xFF)
+#define NPCM_PCIE_RCCFGNUM_DEVFN(a) ((a) & 0xFF)
#define NPCM_PCIERC_INTEN 0x180 /* Interrupt Enable */
#define NPCM_PCIERC_INTST 0x184 /* Interrupt Status */
#define NPCM_PCIERC_IMSI_ADDR 0x190
@@ -84,6 +87,10 @@
#define NPCM_PCIERC_NUM_PA_WINDOWS 2
#define NPCM_PCIERC_NUM_AP_WINDOWS 5
+/* PCIe extended config space offsets */
+#define NPCM_PCIE_HEADER_OFFSET 0x80
+#define NPCM_PCIE_AER_OFFSET 0x100
+
#define TYPE_NPCM_PCIERC "npcm-pcie-root-complex"
OBJECT_DECLARE_SIMPLE_TYPE(NPCMPCIERCState, NPCM_PCIERC)
@@ -105,6 +112,13 @@ typedef struct NPCMPCIEWindow {
uint8_t id;
} NPCMPCIEWindow;
+#define TYPE_NPCM_PCIE_ROOT_PORT "npcm-pcie-root-port"
+OBJECT_DECLARE_SIMPLE_TYPE(NPCMPCIERootPort, NPCM_PCIE_ROOT_PORT)
+
+struct NPCMPCIERootPort {
+ PCIESlot parent;
+};
+
struct NPCMPCIERCState {
PCIExpressHost parent;
@@ -118,6 +132,12 @@ struct NPCMPCIERCState {
uint32_t rcimsiaddr;
uint32_t rcmsisstat;
uint32_t axierr;
+
+ /* Address translation state */
+ AddressSpace pcie_space;
+ MemoryRegion pcie_root;
+ MemoryRegion pcie_io; /* unused - but required for IO space PCI */
+ NPCMPCIERootPort port;
/* PCIe to AXI Windows */
NPCMPCIEWindow pcie2axi[NPCM_PCIERC_NUM_PA_WINDOWS];
--
2.51.0.384.g4c02a37b29-goog
next prev parent reply other threads:[~2025-09-09 22:14 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-09 22:10 [PATCH 0/7] Introduce PCIE Root Complex on Nuvoton npcm8xx and npcm7xx Yubin Zou
2025-09-09 22:10 ` [PATCH 1/7] hw/pci-host: implement Nuvoton PCIE Root Complex stub Yubin Zou
2025-09-30 1:33 ` KFTING
2025-09-09 22:10 ` [PATCH 2/7] hw/pci-host: add basic Nuvoton PCIe window support Yubin Zou
2025-09-25 16:38 ` Peter Maydell
2025-09-25 19:39 ` Titus Rwantare
2025-09-26 9:07 ` Peter Maydell
2025-09-30 1:34 ` KFTING
2025-09-09 22:10 ` [PATCH 3/7] hw/arm: attach PCIe root complex to npmcm8xx Yubin Zou
2025-09-30 1:35 ` KFTING
2025-09-09 22:10 ` Yubin Zou [this message]
2025-09-25 16:42 ` [PATCH 4/7] hw/pci-host: add Nuvoton PCIe root port Peter Maydell
2025-09-30 1:34 ` KFTING
2025-09-09 22:11 ` [PATCH 5/7] hw/pci-host: enable MSI on npcm PCIe root complex Yubin Zou
2025-09-30 1:36 ` KFTING
2025-09-09 22:11 ` [PATCH 6/7] hw/pci-host: rework Nuvoton PCIe windowing and memory regions Yubin Zou
2025-09-25 16:40 ` Peter Maydell
2025-09-30 1:34 ` KFTING
2025-09-09 22:11 ` [PATCH 7/7] hw/arm: Add PCIERC to NPCM7xx SoC Yubin Zou
2025-09-30 1:36 ` KFTING
2025-09-25 16:43 ` [PATCH 0/7] Introduce PCIE Root Complex on Nuvoton npcm8xx and npcm7xx Peter Maydell
2025-09-30 1:32 ` KFTING
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=20250909-pcie-root-upstream-v1-4-d85883b2688d@google.com \
--to=yubinz@google.com \
--cc=kfting@nuvoton.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=titusr@google.com \
--cc=wuhaotsh@google.com \
/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;
as well as URLs for NNTP newsgroup(s).