Add the amd,versal2-cpm6-host1 compatible to support the second CPM6
PCIe host controller, alongside the existing MDB5 and CPM6 host0.
On init, disable and clear pending interrupts.
Signed-off-by: Pranav Sanwal <[email protected]>
Message-ID:
<1d855c8127c24e3423e62671a4a5c08a9e4a6e32.1789111144.git.pranav.san...@amd.com>
---
drivers/pci/pcie_dw_amd.c | 116 ++++++++++++++++++++++++++++++++------
1 file changed, 98 insertions(+), 18 deletions(-)
diff --git a/drivers/pci/pcie_dw_amd.c b/drivers/pci/pcie_dw_amd.c
index 944458e668c..9e545d6ec7e 100644
--- a/drivers/pci/pcie_dw_amd.c
+++ b/drivers/pci/pcie_dw_amd.c
@@ -19,14 +19,23 @@
#include "pcie_dw_common.h"
-/*
- * SLCR (System Level Control Register) Interrupt Register Offsets
- * These are relative to the SLCR base address from device tree
- */
+/* MDB5 SLCR (System Level Control Register) interrupt register offsets */
#define AMD_DW_TLP_IR_STATUS_MISC 0x4c0
#define AMD_DW_TLP_IR_DISABLE_MISC 0x4cc
-/* Interrupt bit definitions */
+/* CPM6 per-host MISC_EVENT registers, in the separate "intr" region */
+#define AMD_CPM6_MISC_EVENT_STATUS 0x514
+#define AMD_CPM6_MISC_EVENT_DISABLE 0x520
+
+/* CPM6 shared aggregators in the "slcr" region, common to both hosts */
+#define AMD_CPM6_PS_MISC_IR_STATUS 0x340
+#define AMD_CPM6_PS_IR_MERGED BIT(21)
+#define AMD_CPM6_MERGED_STATUS 0x648
+#define AMD_CPM6_MERGED_DISABLE 0x654
+#define AMD_CPM6_MERGED_MISC_EVENT_HOST0 14
+#define AMD_CPM6_MERGED_MISC_EVENT_HOST1 17
+
+/* MDB5 TLP_IR interrupt bit definitions */
#define AMD_DW_PCIE_INTR_CMPL_TIMEOUT 15
#define AMD_DW_PCIE_INTR_PM_PME_RCVD 24
#define AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD 25
@@ -45,6 +54,8 @@
BIT(AMD_DW_PCIE_INTR_FATAL) | \
AMD_DW_PCIE_INTR_INTX_MASK)
+#define AMD_CPM6_PCIE_INTR_MASK BIT(22)
+
/* DW PCIe Debug Registers (in DBI space) */
#define AMD_DW_PCIE_PORT_DEBUG1 0x72c
#define AMD_DW_PCIE_PORT_DEBUG1_LINK_UP BIT(4)
@@ -58,31 +69,88 @@
#define PCIE_RESET_CONFIG_WAIT_MS 100
#define PCIE_T_PERST_WAIT_MS 1
+/**
+ * enum amd_dw_pcie_version - AMD DesignWare PCIe controller variant
+ * @AMD_DW_PCIE_MDB5: amd,versal2-mdb-host
+ * @AMD_DW_PCIE_CPM6_HOST0: amd,versal2-cpm6-host
+ * @AMD_DW_PCIE_CPM6_HOST1: amd,versal2-cpm6-host1
+ */
+enum amd_dw_pcie_version {
+ AMD_DW_PCIE_MDB5,
+ AMD_DW_PCIE_CPM6_HOST0,
+ AMD_DW_PCIE_CPM6_HOST1,
+};
+
/**
* struct amd_dw_pcie - AMD DesignWare PCIe controller private data
* @dw: DesignWare PCIe common structure
- * @slcr_base: System Level Control Register base (for interrupts)
+ * @slcr_base: System Level Control Register base (IR block on MDB5, MERGED
aggregator on CPM6)
+ * @intr_base: Per-host interrupt register base (aliases @slcr_base on MDB5)
+ * @version: Matched compatible variant
*/
struct amd_dw_pcie {
struct pcie_dw dw;
void __iomem *slcr_base;
+ void __iomem *intr_base;
+ enum amd_dw_pcie_version version;
};
-static void amd_dw_pcie_init_port(struct amd_dw_pcie *pcie)
+static void amd_dw_pcie_init_port_mdb5(struct amd_dw_pcie *pcie)
{
u32 val;
- if (!pcie->slcr_base)
- return;
-
/* Disable all TLP interrupts */
writel(AMD_DW_PCIE_IMR_ALL_MASK,
- pcie->slcr_base + AMD_DW_TLP_IR_DISABLE_MISC);
+ pcie->intr_base + AMD_DW_TLP_IR_DISABLE_MISC);
/* Clear any pending TLP interrupts */
- val = readl(pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC);
+ val = readl(pcie->intr_base + AMD_DW_TLP_IR_STATUS_MISC);
val &= AMD_DW_PCIE_IMR_ALL_MASK;
- writel(val, pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC);
+ writel(val, pcie->intr_base + AMD_DW_TLP_IR_STATUS_MISC);
+}
+
+static void amd_dw_pcie_init_port_cpm6(struct amd_dw_pcie *pcie)
+{
+ u32 host_bit;
+ u32 val;
+
+ writel(AMD_CPM6_PCIE_INTR_MASK,
+ pcie->intr_base + AMD_CPM6_MISC_EVENT_DISABLE);
+
+ /* Clear every pending MISC_EVENT bit, not just the ones this driver
knows */
+ val = readl(pcie->intr_base + AMD_CPM6_MISC_EVENT_STATUS);
+ writel(val, pcie->intr_base + AMD_CPM6_MISC_EVENT_STATUS);
+
+ if (!pcie->slcr_base)
+ return;
+
+ switch (pcie->version) {
+ case AMD_DW_PCIE_CPM6_HOST1:
+ host_bit = AMD_CPM6_MERGED_MISC_EVENT_HOST1;
+ break;
+ default:
+ host_bit = AMD_CPM6_MERGED_MISC_EVENT_HOST0;
+ break;
+ }
+
+ /* Mask this host's bit in the shared MERGED aggregator */
+ writel(BIT(host_bit), pcie->slcr_base + AMD_CPM6_MERGED_DISABLE);
+
+ /* Clear the latched aggregate: this host's MERGED bit and PS_MISC's
MERGED bit */
+ writel(BIT(host_bit), pcie->slcr_base + AMD_CPM6_MERGED_STATUS);
+ writel(AMD_CPM6_PS_IR_MERGED,
+ pcie->slcr_base + AMD_CPM6_PS_MISC_IR_STATUS);
+}
+
+static void amd_dw_pcie_init_port(struct amd_dw_pcie *pcie)
+{
+ if (!pcie->intr_base)
+ return;
+
+ if (pcie->version == AMD_DW_PCIE_MDB5)
+ amd_dw_pcie_init_port_mdb5(pcie);
+ else
+ amd_dw_pcie_init_port_cpm6(pcie);
}
static void amd_dw_pcie_start_link(struct amd_dw_pcie *pcie)
@@ -179,9 +247,20 @@ static int amd_dw_pcie_of_to_plat(struct udevice *dev)
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
}
+ pcie->version = (enum amd_dw_pcie_version)dev_get_driver_data(dev);
+
pcie->slcr_base = dev_read_addr_name_ptr(dev, "slcr");
if (!pcie->slcr_base)
- dev_dbg(dev, "No 'slcr' region, interrupt features disabled\n");
+ dev_dbg(dev, "No 'slcr' region available\n");
+
+ if (pcie->version == AMD_DW_PCIE_MDB5) {
+ /* MDB5 has no separate 'intr' region; it aliases 'slcr' */
+ pcie->intr_base = pcie->slcr_base;
+ } else {
+ pcie->intr_base = dev_read_addr_name_ptr(dev, "intr");
+ if (!pcie->intr_base)
+ dev_dbg(dev, "No 'intr' region, interrupt features
disabled\n");
+ }
ret = pci_get_regions(dev, &io_region, &mem_region, &pref_region);
if (ret < 0) {
@@ -222,9 +301,9 @@ static int amd_dw_pcie_probe(struct udevice *dev)
dev_warn(dev, "No MEM region configured!\n");
}
- dev_dbg(dev, "dbi: 0x%lx | config: 0x%lx | atu: 0x%lx | slcr: 0x%lx\n",
+ dev_dbg(dev, "dbi: 0x%lx | config: 0x%lx | atu: 0x%lx | slcr: 0x%lx | intr:
0x%lx\n",
(long)pci->dbi_base, (long)pci->cfg_base,
- (long)pci->atu_base, (long)pcie->slcr_base);
+ (long)pci->atu_base, (long)pcie->slcr_base,
(long)pcie->intr_base);
return 0;
}
@@ -235,8 +314,9 @@ static const struct dm_pci_ops amd_dw_pcie_ops = {
};
static const struct udevice_id amd_dw_pcie_ids[] = {
- { .compatible = "amd,versal2-mdb-host" },
- { .compatible = "amd,versal2-cpm6-host" },
+ { .compatible = "amd,versal2-mdb-host", .data = AMD_DW_PCIE_MDB5 },
+ { .compatible = "amd,versal2-cpm6-host", .data = AMD_DW_PCIE_CPM6_HOST0
},
+ { .compatible = "amd,versal2-cpm6-host1", .data =
AMD_DW_PCIE_CPM6_HOST1 },
{ }
};