Re: [PATCH 3/3] PCI: altera: add Agilex 5 support

From: Manivannan Sadhasivam

Date: Tue May 12 2026 - 09:17:40 EST


On Fri, Apr 24, 2026 at 02:49:13AM -0700, Mahesh Vaidya wrote:
> Add PCIe root port controller support for the Agilex 5 (V4) family

There is no 'root port controller'. Root Port and Controller (Root Complex) are
two different IPs.

> of SoC FPGAs.
>
> The Agilex 5 PCIe Hard IP reuses the same config-space access path
> as Agilex 7 (V3). Root port and endpoint configuration reads/writes
> use direct MMIO to the HIP and CRA regions.
>
> The difference is in the HIP port-level registers (IRQ status and IRQ
> enable). On V3 these are directly mapped through the HIP MMIO window.
> On V4 these registers are only reachable through an indirect access
> mailbox (CFG REG IA CTRL) in the PCIe Subsystem AXI-Lite interface,
> documented in the GTS AXI Streaming IP for PCIe User Guide.
>
> This adds:
> - ALTERA_PCIE_V4 version and platform data
> - Indirect register read/write helpers using readl_poll_timeout_atomic
> - Chained IRQ handler (aglx5_isr) for the V4 interrupt path
> - OF match for "altr,pcie-root-port-4.0"
>
> Co-developed-by: Matthew Gerlach <matthew.gerlach@xxxxxxxxxxxxxxx>
> Signed-off-by: Matthew Gerlach <matthew.gerlach@xxxxxxxxxxxxxxx>
> Co-developed-by: Peter Colberg <peter.colberg@xxxxxxxxx>
> Signed-off-by: Peter Colberg <peter.colberg@xxxxxxxxx>
> Signed-off-by: Mahesh Vaidya <mahesh.vaidya@xxxxxxxxxx>
> ---
> drivers/pci/controller/pcie-altera.c | 156 ++++++++++++++++++++++++++-
> 1 file changed, 155 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
> index 025ba74d1ee2..db8149d84c96 100644
> --- a/drivers/pci/controller/pcie-altera.c
> +++ b/drivers/pci/controller/pcie-altera.c
> @@ -12,6 +12,8 @@
> #include <linux/irqchip/chained_irq.h>
> #include <linux/irqdomain.h>
> #include <linux/init.h>
> +#include <linux/bitfield.h>
> +#include <linux/iopoll.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/of_pci.h>
> @@ -93,16 +95,36 @@
> #define AGLX_CFG_TARGET_LOCAL_2000 2
> #define AGLX_CFG_TARGET_LOCAL_3000 3
>
> +/* PCIe subsystem indirect register access */
> +#define PCIE_SS_IA_CTL 0xc8 /* control register */
> +#define PCIE_SS_IA_FN_NUM 0xcc /* function number */
> +#define PCIE_SS_IA_FN_WRDATA 0xd0 /* write data */
> +#define PCIE_SS_IA_FN_RDDATA 0xd4 /* read data */
> +
> +/* PCIE_SS_IA_CTL bitfields */
> +#define PCIE_SS_IA_CTL_INITIATE BIT(0)
> +#define PCIE_SS_IA_CTL_WRITE BIT(1)
> +#define PCIE_SS_IA_CTL_BYTE_EN GENMASK(5, 2)
> +#define PCIE_SS_IA_CTL_ADDR GENMASK(31, 6)
> +
> +/* PCIE_SS_IA_FN_NUM function types */
> +#define PCIE_SS_IA_FN_TYPE_HIP 2
> +
> +#define AGLX5_INDIRECT_SLEEP_US 1
> +#define AGLX5_INDIRECT_TIMEOUT_US 1000
> +
> enum altera_pcie_version {
> ALTERA_PCIE_V1 = 0,
> ALTERA_PCIE_V2,
> ALTERA_PCIE_V3,
> + ALTERA_PCIE_V4,
> };
>
> struct altera_pcie {
> struct platform_device *pdev;
> void __iomem *cra_base;
> void __iomem *hip_base;
> + void __iomem *controller_base;
> int irq;
> u8 root_bus_nr;
> struct irq_domain *irq_domain;
> @@ -849,6 +871,98 @@ static void aglx_isr(struct irq_desc *desc)
> chained_irq_exit(chip, desc);
> }
>
> +/*
> + * Indirect register access to HIP registers via the PCIe Subsystem
> + * AXI-Lite mailbox, documented in the GTS AXI Streaming IP for PCIe
> + * User Guide. Called from chained IRQ handler (hardirq) and probe
> + * (before handler is installed), so no locking is required.
> + */
> +static int aglx5_indirect_readl(const struct altera_pcie *pcie,
> + unsigned int addr, unsigned int *val)

s/unsigned int/u32

> +{
> + unsigned int ctl;

s/unsigned int/u32

> + int ret;
> +
> + writel(PCIE_SS_IA_FN_TYPE_HIP,
> + pcie->controller_base + PCIE_SS_IA_FN_NUM);
> +
> + ctl = FIELD_PREP(PCIE_SS_IA_CTL_ADDR, addr >> 2) |
> + PCIE_SS_IA_CTL_BYTE_EN | PCIE_SS_IA_CTL_INITIATE;
> + writel(ctl, (pcie->controller_base + PCIE_SS_IA_CTL));
> +
> + ret = readl_poll_timeout_atomic(pcie->controller_base + PCIE_SS_IA_CTL,
> + ctl, !(ctl & PCIE_SS_IA_CTL_INITIATE),
> + AGLX5_INDIRECT_SLEEP_US,
> + AGLX5_INDIRECT_TIMEOUT_US);
> + if (ret)
> + return ret;
> +
> + *val = readl(pcie->controller_base + PCIE_SS_IA_FN_RDDATA);
> +
> + return 0;
> +}
> +
> +static int aglx5_indirect_writel(const struct altera_pcie *pcie,
> + unsigned int addr, unsigned int val)

s/unsigned int/u32

> +{
> + unsigned int ctl;

s/unsigned int/u32

> + int ret;
> +
> + writel(PCIE_SS_IA_FN_TYPE_HIP,
> + pcie->controller_base + PCIE_SS_IA_FN_NUM);
> + writel(val, pcie->controller_base + PCIE_SS_IA_FN_WRDATA);
> +
> + ctl = FIELD_PREP(PCIE_SS_IA_CTL_ADDR, addr >> 2) |
> + PCIE_SS_IA_CTL_BYTE_EN | PCIE_SS_IA_CTL_WRITE |
> + PCIE_SS_IA_CTL_INITIATE;
> + writel(ctl, pcie->controller_base + PCIE_SS_IA_CTL);
> +
> + ret = readl_poll_timeout_atomic(pcie->controller_base + PCIE_SS_IA_CTL,
> + ctl, !(ctl & PCIE_SS_IA_CTL_INITIATE),
> + AGLX5_INDIRECT_SLEEP_US,
> + AGLX5_INDIRECT_TIMEOUT_US);
> +
> + return ret;

return readl_poll_timeout_atomic();

- Mani

--
மணிவண்ணன் சதாசிவம்