xref: /linux/drivers/pci/controller/dwc/pcie-amd-mdb.c (revision 2bd1bea5fa6aa79bc563a57919730eb809651b28)
15f3de23dSThippeswamy Havalige // SPDX-License-Identifier: GPL-2.0
25f3de23dSThippeswamy Havalige /*
35f3de23dSThippeswamy Havalige  * PCIe host controller driver for AMD MDB PCIe Bridge
45f3de23dSThippeswamy Havalige  *
55f3de23dSThippeswamy Havalige  * Copyright (C) 2024-2025, Advanced Micro Devices, Inc.
65f3de23dSThippeswamy Havalige  */
75f3de23dSThippeswamy Havalige 
85f3de23dSThippeswamy Havalige #include <linux/clk.h>
95f3de23dSThippeswamy Havalige #include <linux/delay.h>
105f3de23dSThippeswamy Havalige #include <linux/gpio.h>
115f3de23dSThippeswamy Havalige #include <linux/interrupt.h>
125f3de23dSThippeswamy Havalige #include <linux/irqdomain.h>
135f3de23dSThippeswamy Havalige #include <linux/kernel.h>
145f3de23dSThippeswamy Havalige #include <linux/init.h>
155f3de23dSThippeswamy Havalige #include <linux/of_device.h>
165f3de23dSThippeswamy Havalige #include <linux/pci.h>
175f3de23dSThippeswamy Havalige #include <linux/platform_device.h>
185f3de23dSThippeswamy Havalige #include <linux/resource.h>
195f3de23dSThippeswamy Havalige #include <linux/types.h>
205f3de23dSThippeswamy Havalige 
215f3de23dSThippeswamy Havalige #include "pcie-designware.h"
225f3de23dSThippeswamy Havalige 
235f3de23dSThippeswamy Havalige #define AMD_MDB_TLP_IR_STATUS_MISC		0x4C0
245f3de23dSThippeswamy Havalige #define AMD_MDB_TLP_IR_MASK_MISC		0x4C4
255f3de23dSThippeswamy Havalige #define AMD_MDB_TLP_IR_ENABLE_MISC		0x4C8
265f3de23dSThippeswamy Havalige #define AMD_MDB_TLP_IR_DISABLE_MISC		0x4CC
275f3de23dSThippeswamy Havalige 
285f3de23dSThippeswamy Havalige #define AMD_MDB_TLP_PCIE_INTX_MASK	GENMASK(23, 16)
295f3de23dSThippeswamy Havalige 
305f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_INTX_ASSERT(x)	BIT((x) * 2)
315f3de23dSThippeswamy Havalige 
325f3de23dSThippeswamy Havalige /* Interrupt registers definitions. */
335f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_CMPL_TIMEOUT		15
345f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_INTX			16
355f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_PM_PME_RCVD		24
365f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_PME_TO_ACK_RCVD	25
375f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_MISC_CORRECTABLE	26
385f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_NONFATAL		27
395f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_INTR_FATAL			28
405f3de23dSThippeswamy Havalige 
415f3de23dSThippeswamy Havalige #define IMR(x) BIT(AMD_MDB_PCIE_INTR_ ##x)
425f3de23dSThippeswamy Havalige #define AMD_MDB_PCIE_IMR_ALL_MASK			\
435f3de23dSThippeswamy Havalige 	(						\
445f3de23dSThippeswamy Havalige 		IMR(CMPL_TIMEOUT)	|		\
455f3de23dSThippeswamy Havalige 		IMR(PM_PME_RCVD)	|		\
465f3de23dSThippeswamy Havalige 		IMR(PME_TO_ACK_RCVD)	|		\
475f3de23dSThippeswamy Havalige 		IMR(MISC_CORRECTABLE)	|		\
485f3de23dSThippeswamy Havalige 		IMR(NONFATAL)		|		\
495f3de23dSThippeswamy Havalige 		IMR(FATAL)		|		\
505f3de23dSThippeswamy Havalige 		AMD_MDB_TLP_PCIE_INTX_MASK		\
515f3de23dSThippeswamy Havalige 	)
525f3de23dSThippeswamy Havalige 
535f3de23dSThippeswamy Havalige /**
545f3de23dSThippeswamy Havalige  * struct amd_mdb_pcie - PCIe port information
555f3de23dSThippeswamy Havalige  * @pci: DesignWare PCIe controller structure
565f3de23dSThippeswamy Havalige  * @slcr: MDB System Level Control and Status Register (SLCR) base
575f3de23dSThippeswamy Havalige  * @intx_domain: INTx IRQ domain pointer
585f3de23dSThippeswamy Havalige  * @mdb_domain: MDB IRQ domain pointer
595f3de23dSThippeswamy Havalige  * @intx_irq: INTx IRQ interrupt number
605f3de23dSThippeswamy Havalige  */
615f3de23dSThippeswamy Havalige struct amd_mdb_pcie {
625f3de23dSThippeswamy Havalige 	struct dw_pcie			pci;
635f3de23dSThippeswamy Havalige 	void __iomem			*slcr;
645f3de23dSThippeswamy Havalige 	struct irq_domain		*intx_domain;
655f3de23dSThippeswamy Havalige 	struct irq_domain		*mdb_domain;
665f3de23dSThippeswamy Havalige 	int				intx_irq;
675f3de23dSThippeswamy Havalige };
685f3de23dSThippeswamy Havalige 
695f3de23dSThippeswamy Havalige static const struct dw_pcie_host_ops amd_mdb_pcie_host_ops = {
705f3de23dSThippeswamy Havalige };
715f3de23dSThippeswamy Havalige 
amd_mdb_intx_irq_mask(struct irq_data * data)725f3de23dSThippeswamy Havalige static void amd_mdb_intx_irq_mask(struct irq_data *data)
735f3de23dSThippeswamy Havalige {
745f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(data);
755f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
765f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *port = &pci->pp;
775f3de23dSThippeswamy Havalige 	unsigned long flags;
785f3de23dSThippeswamy Havalige 	u32 val;
795f3de23dSThippeswamy Havalige 
805f3de23dSThippeswamy Havalige 	raw_spin_lock_irqsave(&port->lock, flags);
815f3de23dSThippeswamy Havalige 	val = FIELD_PREP(AMD_MDB_TLP_PCIE_INTX_MASK,
825f3de23dSThippeswamy Havalige 			 AMD_MDB_PCIE_INTR_INTX_ASSERT(data->hwirq));
835f3de23dSThippeswamy Havalige 
845f3de23dSThippeswamy Havalige 	/*
855f3de23dSThippeswamy Havalige 	 * Writing '1' to a bit in AMD_MDB_TLP_IR_DISABLE_MISC disables that
865f3de23dSThippeswamy Havalige 	 * interrupt, writing '0' has no effect.
875f3de23dSThippeswamy Havalige 	 */
885f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
895f3de23dSThippeswamy Havalige 	raw_spin_unlock_irqrestore(&port->lock, flags);
905f3de23dSThippeswamy Havalige }
915f3de23dSThippeswamy Havalige 
amd_mdb_intx_irq_unmask(struct irq_data * data)925f3de23dSThippeswamy Havalige static void amd_mdb_intx_irq_unmask(struct irq_data *data)
935f3de23dSThippeswamy Havalige {
945f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(data);
955f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
965f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *port = &pci->pp;
975f3de23dSThippeswamy Havalige 	unsigned long flags;
985f3de23dSThippeswamy Havalige 	u32 val;
995f3de23dSThippeswamy Havalige 
1005f3de23dSThippeswamy Havalige 	raw_spin_lock_irqsave(&port->lock, flags);
1015f3de23dSThippeswamy Havalige 	val = FIELD_PREP(AMD_MDB_TLP_PCIE_INTX_MASK,
1025f3de23dSThippeswamy Havalige 			 AMD_MDB_PCIE_INTR_INTX_ASSERT(data->hwirq));
1035f3de23dSThippeswamy Havalige 
1045f3de23dSThippeswamy Havalige 	/*
1055f3de23dSThippeswamy Havalige 	 * Writing '1' to a bit in AMD_MDB_TLP_IR_ENABLE_MISC enables that
1065f3de23dSThippeswamy Havalige 	 * interrupt, writing '0' has no effect.
1075f3de23dSThippeswamy Havalige 	 */
1085f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
1095f3de23dSThippeswamy Havalige 	raw_spin_unlock_irqrestore(&port->lock, flags);
1105f3de23dSThippeswamy Havalige }
1115f3de23dSThippeswamy Havalige 
1125f3de23dSThippeswamy Havalige static struct irq_chip amd_mdb_intx_irq_chip = {
1135f3de23dSThippeswamy Havalige 	.name		= "AMD MDB INTx",
1145f3de23dSThippeswamy Havalige 	.irq_mask	= amd_mdb_intx_irq_mask,
1155f3de23dSThippeswamy Havalige 	.irq_unmask	= amd_mdb_intx_irq_unmask,
1165f3de23dSThippeswamy Havalige };
1175f3de23dSThippeswamy Havalige 
1185f3de23dSThippeswamy Havalige /**
1195f3de23dSThippeswamy Havalige  * amd_mdb_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
1205f3de23dSThippeswamy Havalige  * @domain: IRQ domain
1215f3de23dSThippeswamy Havalige  * @irq: Virtual IRQ number
1225f3de23dSThippeswamy Havalige  * @hwirq: Hardware interrupt number
1235f3de23dSThippeswamy Havalige  *
1245f3de23dSThippeswamy Havalige  * Return: Always returns '0'.
1255f3de23dSThippeswamy Havalige  */
amd_mdb_pcie_intx_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)1265f3de23dSThippeswamy Havalige static int amd_mdb_pcie_intx_map(struct irq_domain *domain,
1275f3de23dSThippeswamy Havalige 				 unsigned int irq, irq_hw_number_t hwirq)
1285f3de23dSThippeswamy Havalige {
1295f3de23dSThippeswamy Havalige 	irq_set_chip_and_handler(irq, &amd_mdb_intx_irq_chip,
1305f3de23dSThippeswamy Havalige 				 handle_level_irq);
1315f3de23dSThippeswamy Havalige 	irq_set_chip_data(irq, domain->host_data);
1325f3de23dSThippeswamy Havalige 	irq_set_status_flags(irq, IRQ_LEVEL);
1335f3de23dSThippeswamy Havalige 
1345f3de23dSThippeswamy Havalige 	return 0;
1355f3de23dSThippeswamy Havalige }
1365f3de23dSThippeswamy Havalige 
1375f3de23dSThippeswamy Havalige /* INTx IRQ domain operations. */
1385f3de23dSThippeswamy Havalige static const struct irq_domain_ops amd_intx_domain_ops = {
1395f3de23dSThippeswamy Havalige 	.map = amd_mdb_pcie_intx_map,
1405f3de23dSThippeswamy Havalige };
1415f3de23dSThippeswamy Havalige 
dw_pcie_rp_intx(int irq,void * args)1425f3de23dSThippeswamy Havalige static irqreturn_t dw_pcie_rp_intx(int irq, void *args)
1435f3de23dSThippeswamy Havalige {
1445f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = args;
1455f3de23dSThippeswamy Havalige 	unsigned long val;
1465f3de23dSThippeswamy Havalige 	int i, int_status;
1475f3de23dSThippeswamy Havalige 
1485f3de23dSThippeswamy Havalige 	val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
1495f3de23dSThippeswamy Havalige 	int_status = FIELD_GET(AMD_MDB_TLP_PCIE_INTX_MASK, val);
1505f3de23dSThippeswamy Havalige 
1515f3de23dSThippeswamy Havalige 	for (i = 0; i < PCI_NUM_INTX; i++) {
1525f3de23dSThippeswamy Havalige 		if (int_status & AMD_MDB_PCIE_INTR_INTX_ASSERT(i))
1535f3de23dSThippeswamy Havalige 			generic_handle_domain_irq(pcie->intx_domain, i);
1545f3de23dSThippeswamy Havalige 	}
1555f3de23dSThippeswamy Havalige 
1565f3de23dSThippeswamy Havalige 	return IRQ_HANDLED;
1575f3de23dSThippeswamy Havalige }
1585f3de23dSThippeswamy Havalige 
1595f3de23dSThippeswamy Havalige #define _IC(x, s)[AMD_MDB_PCIE_INTR_ ## x] = { __stringify(x), s }
1605f3de23dSThippeswamy Havalige 
1615f3de23dSThippeswamy Havalige static const struct {
1625f3de23dSThippeswamy Havalige 	const char	*sym;
1635f3de23dSThippeswamy Havalige 	const char	*str;
1645f3de23dSThippeswamy Havalige } intr_cause[32] = {
1655f3de23dSThippeswamy Havalige 	_IC(CMPL_TIMEOUT,	"Completion timeout"),
1665f3de23dSThippeswamy Havalige 	_IC(PM_PME_RCVD,	"PM_PME message received"),
1675f3de23dSThippeswamy Havalige 	_IC(PME_TO_ACK_RCVD,	"PME_TO_ACK message received"),
1685f3de23dSThippeswamy Havalige 	_IC(MISC_CORRECTABLE,	"Correctable error message"),
1695f3de23dSThippeswamy Havalige 	_IC(NONFATAL,		"Non fatal error message"),
1705f3de23dSThippeswamy Havalige 	_IC(FATAL,		"Fatal error message"),
1715f3de23dSThippeswamy Havalige };
1725f3de23dSThippeswamy Havalige 
amd_mdb_event_irq_mask(struct irq_data * d)1735f3de23dSThippeswamy Havalige static void amd_mdb_event_irq_mask(struct irq_data *d)
1745f3de23dSThippeswamy Havalige {
1755f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(d);
1765f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
1775f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *port = &pci->pp;
1785f3de23dSThippeswamy Havalige 	unsigned long flags;
1795f3de23dSThippeswamy Havalige 	u32 val;
1805f3de23dSThippeswamy Havalige 
1815f3de23dSThippeswamy Havalige 	raw_spin_lock_irqsave(&port->lock, flags);
1825f3de23dSThippeswamy Havalige 	val = BIT(d->hwirq);
1835f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
1845f3de23dSThippeswamy Havalige 	raw_spin_unlock_irqrestore(&port->lock, flags);
1855f3de23dSThippeswamy Havalige }
1865f3de23dSThippeswamy Havalige 
amd_mdb_event_irq_unmask(struct irq_data * d)1875f3de23dSThippeswamy Havalige static void amd_mdb_event_irq_unmask(struct irq_data *d)
1885f3de23dSThippeswamy Havalige {
1895f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(d);
1905f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
1915f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *port = &pci->pp;
1925f3de23dSThippeswamy Havalige 	unsigned long flags;
1935f3de23dSThippeswamy Havalige 	u32 val;
1945f3de23dSThippeswamy Havalige 
1955f3de23dSThippeswamy Havalige 	raw_spin_lock_irqsave(&port->lock, flags);
1965f3de23dSThippeswamy Havalige 	val = BIT(d->hwirq);
1975f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
1985f3de23dSThippeswamy Havalige 	raw_spin_unlock_irqrestore(&port->lock, flags);
1995f3de23dSThippeswamy Havalige }
2005f3de23dSThippeswamy Havalige 
2015f3de23dSThippeswamy Havalige static struct irq_chip amd_mdb_event_irq_chip = {
2025f3de23dSThippeswamy Havalige 	.name		= "AMD MDB RC-Event",
2035f3de23dSThippeswamy Havalige 	.irq_mask	= amd_mdb_event_irq_mask,
2045f3de23dSThippeswamy Havalige 	.irq_unmask	= amd_mdb_event_irq_unmask,
2055f3de23dSThippeswamy Havalige };
2065f3de23dSThippeswamy Havalige 
amd_mdb_pcie_event_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)2075f3de23dSThippeswamy Havalige static int amd_mdb_pcie_event_map(struct irq_domain *domain,
2085f3de23dSThippeswamy Havalige 				  unsigned int irq, irq_hw_number_t hwirq)
2095f3de23dSThippeswamy Havalige {
2105f3de23dSThippeswamy Havalige 	irq_set_chip_and_handler(irq, &amd_mdb_event_irq_chip,
2115f3de23dSThippeswamy Havalige 				 handle_level_irq);
2125f3de23dSThippeswamy Havalige 	irq_set_chip_data(irq, domain->host_data);
2135f3de23dSThippeswamy Havalige 	irq_set_status_flags(irq, IRQ_LEVEL);
2145f3de23dSThippeswamy Havalige 
2155f3de23dSThippeswamy Havalige 	return 0;
2165f3de23dSThippeswamy Havalige }
2175f3de23dSThippeswamy Havalige 
2185f3de23dSThippeswamy Havalige static const struct irq_domain_ops event_domain_ops = {
2195f3de23dSThippeswamy Havalige 	.map = amd_mdb_pcie_event_map,
2205f3de23dSThippeswamy Havalige };
2215f3de23dSThippeswamy Havalige 
amd_mdb_pcie_event(int irq,void * args)2225f3de23dSThippeswamy Havalige static irqreturn_t amd_mdb_pcie_event(int irq, void *args)
2235f3de23dSThippeswamy Havalige {
2245f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = args;
2255f3de23dSThippeswamy Havalige 	unsigned long val;
2265f3de23dSThippeswamy Havalige 	int i;
2275f3de23dSThippeswamy Havalige 
2285f3de23dSThippeswamy Havalige 	val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
2295f3de23dSThippeswamy Havalige 	val &= ~readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_MASK_MISC);
2305f3de23dSThippeswamy Havalige 	for_each_set_bit(i, &val, 32)
2315f3de23dSThippeswamy Havalige 		generic_handle_domain_irq(pcie->mdb_domain, i);
2325f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
2335f3de23dSThippeswamy Havalige 
2345f3de23dSThippeswamy Havalige 	return IRQ_HANDLED;
2355f3de23dSThippeswamy Havalige }
2365f3de23dSThippeswamy Havalige 
amd_mdb_pcie_free_irq_domains(struct amd_mdb_pcie * pcie)2375f3de23dSThippeswamy Havalige static void amd_mdb_pcie_free_irq_domains(struct amd_mdb_pcie *pcie)
2385f3de23dSThippeswamy Havalige {
2395f3de23dSThippeswamy Havalige 	if (pcie->intx_domain) {
2405f3de23dSThippeswamy Havalige 		irq_domain_remove(pcie->intx_domain);
2415f3de23dSThippeswamy Havalige 		pcie->intx_domain = NULL;
2425f3de23dSThippeswamy Havalige 	}
2435f3de23dSThippeswamy Havalige 
2445f3de23dSThippeswamy Havalige 	if (pcie->mdb_domain) {
2455f3de23dSThippeswamy Havalige 		irq_domain_remove(pcie->mdb_domain);
2465f3de23dSThippeswamy Havalige 		pcie->mdb_domain = NULL;
2475f3de23dSThippeswamy Havalige 	}
2485f3de23dSThippeswamy Havalige }
2495f3de23dSThippeswamy Havalige 
amd_mdb_pcie_init_port(struct amd_mdb_pcie * pcie)2505f3de23dSThippeswamy Havalige static int amd_mdb_pcie_init_port(struct amd_mdb_pcie *pcie)
2515f3de23dSThippeswamy Havalige {
2525f3de23dSThippeswamy Havalige 	unsigned long val;
2535f3de23dSThippeswamy Havalige 
2545f3de23dSThippeswamy Havalige 	/* Disable all TLP interrupts. */
2555f3de23dSThippeswamy Havalige 	writel_relaxed(AMD_MDB_PCIE_IMR_ALL_MASK,
2565f3de23dSThippeswamy Havalige 		       pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
2575f3de23dSThippeswamy Havalige 
2585f3de23dSThippeswamy Havalige 	/* Clear pending TLP interrupts. */
2595f3de23dSThippeswamy Havalige 	val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
2605f3de23dSThippeswamy Havalige 	val &= AMD_MDB_PCIE_IMR_ALL_MASK;
2615f3de23dSThippeswamy Havalige 	writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
2625f3de23dSThippeswamy Havalige 
2635f3de23dSThippeswamy Havalige 	/* Enable all TLP interrupts. */
2645f3de23dSThippeswamy Havalige 	writel_relaxed(AMD_MDB_PCIE_IMR_ALL_MASK,
2655f3de23dSThippeswamy Havalige 		       pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
2665f3de23dSThippeswamy Havalige 
2675f3de23dSThippeswamy Havalige 	return 0;
2685f3de23dSThippeswamy Havalige }
2695f3de23dSThippeswamy Havalige 
2705f3de23dSThippeswamy Havalige /**
2715f3de23dSThippeswamy Havalige  * amd_mdb_pcie_init_irq_domains - Initialize IRQ domain
2725f3de23dSThippeswamy Havalige  * @pcie: PCIe port information
2735f3de23dSThippeswamy Havalige  * @pdev: Platform device
2745f3de23dSThippeswamy Havalige  *
2755f3de23dSThippeswamy Havalige  * Return: Returns '0' on success and error value on failure.
2765f3de23dSThippeswamy Havalige  */
amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie * pcie,struct platform_device * pdev)2775f3de23dSThippeswamy Havalige static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie,
2785f3de23dSThippeswamy Havalige 					 struct platform_device *pdev)
2795f3de23dSThippeswamy Havalige {
2805f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
2815f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *pp = &pci->pp;
2825f3de23dSThippeswamy Havalige 	struct device *dev = &pdev->dev;
2835f3de23dSThippeswamy Havalige 	struct device_node *node = dev->of_node;
2845f3de23dSThippeswamy Havalige 	struct device_node *pcie_intc_node;
2855f3de23dSThippeswamy Havalige 	int err;
2865f3de23dSThippeswamy Havalige 
2875f3de23dSThippeswamy Havalige 	pcie_intc_node = of_get_next_child(node, NULL);
2885f3de23dSThippeswamy Havalige 	if (!pcie_intc_node) {
2895f3de23dSThippeswamy Havalige 		dev_err(dev, "No PCIe Intc node found\n");
2905f3de23dSThippeswamy Havalige 		return -ENODEV;
2915f3de23dSThippeswamy Havalige 	}
2925f3de23dSThippeswamy Havalige 
293*4b5e1d97SJiri Slaby (SUSE) 	pcie->mdb_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32,
2945f3de23dSThippeswamy Havalige 						    &event_domain_ops, pcie);
2955f3de23dSThippeswamy Havalige 	if (!pcie->mdb_domain) {
2965f3de23dSThippeswamy Havalige 		err = -ENOMEM;
2975f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to add MDB domain\n");
2985f3de23dSThippeswamy Havalige 		goto out;
2995f3de23dSThippeswamy Havalige 	}
3005f3de23dSThippeswamy Havalige 
3015f3de23dSThippeswamy Havalige 	irq_domain_update_bus_token(pcie->mdb_domain, DOMAIN_BUS_NEXUS);
3025f3de23dSThippeswamy Havalige 
303*4b5e1d97SJiri Slaby (SUSE) 	pcie->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node),
304*4b5e1d97SJiri Slaby (SUSE) 						     PCI_NUM_INTX, &amd_intx_domain_ops, pcie);
3055f3de23dSThippeswamy Havalige 	if (!pcie->intx_domain) {
3065f3de23dSThippeswamy Havalige 		err = -ENOMEM;
3075f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to add INTx domain\n");
3085f3de23dSThippeswamy Havalige 		goto mdb_out;
3095f3de23dSThippeswamy Havalige 	}
3105f3de23dSThippeswamy Havalige 
3115f3de23dSThippeswamy Havalige 	of_node_put(pcie_intc_node);
3125f3de23dSThippeswamy Havalige 	irq_domain_update_bus_token(pcie->intx_domain, DOMAIN_BUS_WIRED);
3135f3de23dSThippeswamy Havalige 
3145f3de23dSThippeswamy Havalige 	raw_spin_lock_init(&pp->lock);
3155f3de23dSThippeswamy Havalige 
3165f3de23dSThippeswamy Havalige 	return 0;
3175f3de23dSThippeswamy Havalige mdb_out:
3185f3de23dSThippeswamy Havalige 	amd_mdb_pcie_free_irq_domains(pcie);
3195f3de23dSThippeswamy Havalige out:
3205f3de23dSThippeswamy Havalige 	of_node_put(pcie_intc_node);
3215f3de23dSThippeswamy Havalige 	return err;
3225f3de23dSThippeswamy Havalige }
3235f3de23dSThippeswamy Havalige 
amd_mdb_pcie_intr_handler(int irq,void * args)3245f3de23dSThippeswamy Havalige static irqreturn_t amd_mdb_pcie_intr_handler(int irq, void *args)
3255f3de23dSThippeswamy Havalige {
3265f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie = args;
3275f3de23dSThippeswamy Havalige 	struct device *dev;
3285f3de23dSThippeswamy Havalige 	struct irq_data *d;
3295f3de23dSThippeswamy Havalige 
3305f3de23dSThippeswamy Havalige 	dev = pcie->pci.dev;
3315f3de23dSThippeswamy Havalige 
3325f3de23dSThippeswamy Havalige 	/*
3335f3de23dSThippeswamy Havalige 	 * In the future, error reporting will be hooked to the AER subsystem.
3345f3de23dSThippeswamy Havalige 	 * Currently, the driver prints a warning message to the user.
3355f3de23dSThippeswamy Havalige 	 */
3365f3de23dSThippeswamy Havalige 	d = irq_domain_get_irq_data(pcie->mdb_domain, irq);
3375f3de23dSThippeswamy Havalige 	if (intr_cause[d->hwirq].str)
3385f3de23dSThippeswamy Havalige 		dev_warn(dev, "%s\n", intr_cause[d->hwirq].str);
3395f3de23dSThippeswamy Havalige 	else
3405f3de23dSThippeswamy Havalige 		dev_warn_once(dev, "Unknown IRQ %ld\n", d->hwirq);
3415f3de23dSThippeswamy Havalige 
3425f3de23dSThippeswamy Havalige 	return IRQ_HANDLED;
3435f3de23dSThippeswamy Havalige }
3445f3de23dSThippeswamy Havalige 
amd_mdb_setup_irq(struct amd_mdb_pcie * pcie,struct platform_device * pdev)3455f3de23dSThippeswamy Havalige static int amd_mdb_setup_irq(struct amd_mdb_pcie *pcie,
3465f3de23dSThippeswamy Havalige 			     struct platform_device *pdev)
3475f3de23dSThippeswamy Havalige {
3485f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
3495f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *pp = &pci->pp;
3505f3de23dSThippeswamy Havalige 	struct device *dev = &pdev->dev;
3515f3de23dSThippeswamy Havalige 	int i, irq, err;
3525f3de23dSThippeswamy Havalige 
3535f3de23dSThippeswamy Havalige 	amd_mdb_pcie_init_port(pcie);
3545f3de23dSThippeswamy Havalige 
3555f3de23dSThippeswamy Havalige 	pp->irq = platform_get_irq(pdev, 0);
3565f3de23dSThippeswamy Havalige 	if (pp->irq < 0)
3575f3de23dSThippeswamy Havalige 		return pp->irq;
3585f3de23dSThippeswamy Havalige 
3595f3de23dSThippeswamy Havalige 	for (i = 0; i < ARRAY_SIZE(intr_cause); i++) {
3605f3de23dSThippeswamy Havalige 		if (!intr_cause[i].str)
3615f3de23dSThippeswamy Havalige 			continue;
3625f3de23dSThippeswamy Havalige 
3635f3de23dSThippeswamy Havalige 		irq = irq_create_mapping(pcie->mdb_domain, i);
3645f3de23dSThippeswamy Havalige 		if (!irq) {
3655f3de23dSThippeswamy Havalige 			dev_err(dev, "Failed to map MDB domain interrupt\n");
3665f3de23dSThippeswamy Havalige 			return -ENOMEM;
3675f3de23dSThippeswamy Havalige 		}
3685f3de23dSThippeswamy Havalige 
3695f3de23dSThippeswamy Havalige 		err = devm_request_irq(dev, irq, amd_mdb_pcie_intr_handler,
3705f3de23dSThippeswamy Havalige 				       IRQF_NO_THREAD, intr_cause[i].sym, pcie);
3715f3de23dSThippeswamy Havalige 		if (err) {
3725f3de23dSThippeswamy Havalige 			dev_err(dev, "Failed to request IRQ %d, err=%d\n",
3735f3de23dSThippeswamy Havalige 				irq, err);
3745f3de23dSThippeswamy Havalige 			return err;
3755f3de23dSThippeswamy Havalige 		}
3765f3de23dSThippeswamy Havalige 	}
3775f3de23dSThippeswamy Havalige 
3785f3de23dSThippeswamy Havalige 	pcie->intx_irq = irq_create_mapping(pcie->mdb_domain,
3795f3de23dSThippeswamy Havalige 					    AMD_MDB_PCIE_INTR_INTX);
3805f3de23dSThippeswamy Havalige 	if (!pcie->intx_irq) {
3815f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to map INTx interrupt\n");
3825f3de23dSThippeswamy Havalige 		return -ENXIO;
3835f3de23dSThippeswamy Havalige 	}
3845f3de23dSThippeswamy Havalige 
3855f3de23dSThippeswamy Havalige 	err = devm_request_irq(dev, pcie->intx_irq, dw_pcie_rp_intx,
3865f3de23dSThippeswamy Havalige 			       IRQF_NO_THREAD, NULL, pcie);
3875f3de23dSThippeswamy Havalige 	if (err) {
3885f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to request INTx IRQ %d, err=%d\n",
3895f3de23dSThippeswamy Havalige 			irq, err);
3905f3de23dSThippeswamy Havalige 		return err;
3915f3de23dSThippeswamy Havalige 	}
3925f3de23dSThippeswamy Havalige 
3935f3de23dSThippeswamy Havalige 	/* Plug the main event handler. */
3945f3de23dSThippeswamy Havalige 	err = devm_request_irq(dev, pp->irq, amd_mdb_pcie_event, IRQF_NO_THREAD,
3955f3de23dSThippeswamy Havalige 			       "amd_mdb pcie_irq", pcie);
3965f3de23dSThippeswamy Havalige 	if (err) {
3975f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to request event IRQ %d, err=%d\n",
3985f3de23dSThippeswamy Havalige 			pp->irq, err);
3995f3de23dSThippeswamy Havalige 		return err;
4005f3de23dSThippeswamy Havalige 	}
4015f3de23dSThippeswamy Havalige 
4025f3de23dSThippeswamy Havalige 	return 0;
4035f3de23dSThippeswamy Havalige }
4045f3de23dSThippeswamy Havalige 
amd_mdb_add_pcie_port(struct amd_mdb_pcie * pcie,struct platform_device * pdev)4055f3de23dSThippeswamy Havalige static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie,
4065f3de23dSThippeswamy Havalige 				 struct platform_device *pdev)
4075f3de23dSThippeswamy Havalige {
4085f3de23dSThippeswamy Havalige 	struct dw_pcie *pci = &pcie->pci;
4095f3de23dSThippeswamy Havalige 	struct dw_pcie_rp *pp = &pci->pp;
4105f3de23dSThippeswamy Havalige 	struct device *dev = &pdev->dev;
4115f3de23dSThippeswamy Havalige 	int err;
4125f3de23dSThippeswamy Havalige 
4135f3de23dSThippeswamy Havalige 	pcie->slcr = devm_platform_ioremap_resource_byname(pdev, "slcr");
4145f3de23dSThippeswamy Havalige 	if (IS_ERR(pcie->slcr))
4155f3de23dSThippeswamy Havalige 		return PTR_ERR(pcie->slcr);
4165f3de23dSThippeswamy Havalige 
4175f3de23dSThippeswamy Havalige 	err = amd_mdb_pcie_init_irq_domains(pcie, pdev);
4185f3de23dSThippeswamy Havalige 	if (err)
4195f3de23dSThippeswamy Havalige 		return err;
4205f3de23dSThippeswamy Havalige 
4215f3de23dSThippeswamy Havalige 	err = amd_mdb_setup_irq(pcie, pdev);
4225f3de23dSThippeswamy Havalige 	if (err) {
4235f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to set up interrupts, err=%d\n", err);
4245f3de23dSThippeswamy Havalige 		goto out;
4255f3de23dSThippeswamy Havalige 	}
4265f3de23dSThippeswamy Havalige 
4275f3de23dSThippeswamy Havalige 	pp->ops = &amd_mdb_pcie_host_ops;
4285f3de23dSThippeswamy Havalige 
4295f3de23dSThippeswamy Havalige 	err = dw_pcie_host_init(pp);
4305f3de23dSThippeswamy Havalige 	if (err) {
4315f3de23dSThippeswamy Havalige 		dev_err(dev, "Failed to initialize host, err=%d\n", err);
4325f3de23dSThippeswamy Havalige 		goto out;
4335f3de23dSThippeswamy Havalige 	}
4345f3de23dSThippeswamy Havalige 
4355f3de23dSThippeswamy Havalige 	return 0;
4365f3de23dSThippeswamy Havalige 
4375f3de23dSThippeswamy Havalige out:
4385f3de23dSThippeswamy Havalige 	amd_mdb_pcie_free_irq_domains(pcie);
4395f3de23dSThippeswamy Havalige 	return err;
4405f3de23dSThippeswamy Havalige }
4415f3de23dSThippeswamy Havalige 
amd_mdb_pcie_probe(struct platform_device * pdev)4425f3de23dSThippeswamy Havalige static int amd_mdb_pcie_probe(struct platform_device *pdev)
4435f3de23dSThippeswamy Havalige {
4445f3de23dSThippeswamy Havalige 	struct device *dev = &pdev->dev;
4455f3de23dSThippeswamy Havalige 	struct amd_mdb_pcie *pcie;
4465f3de23dSThippeswamy Havalige 	struct dw_pcie *pci;
4475f3de23dSThippeswamy Havalige 
4485f3de23dSThippeswamy Havalige 	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
4495f3de23dSThippeswamy Havalige 	if (!pcie)
4505f3de23dSThippeswamy Havalige 		return -ENOMEM;
4515f3de23dSThippeswamy Havalige 
4525f3de23dSThippeswamy Havalige 	pci = &pcie->pci;
4535f3de23dSThippeswamy Havalige 	pci->dev = dev;
4545f3de23dSThippeswamy Havalige 
4555f3de23dSThippeswamy Havalige 	platform_set_drvdata(pdev, pcie);
4565f3de23dSThippeswamy Havalige 
4575f3de23dSThippeswamy Havalige 	return amd_mdb_add_pcie_port(pcie, pdev);
4585f3de23dSThippeswamy Havalige }
4595f3de23dSThippeswamy Havalige 
4605f3de23dSThippeswamy Havalige static const struct of_device_id amd_mdb_pcie_of_match[] = {
4615f3de23dSThippeswamy Havalige 	{
4625f3de23dSThippeswamy Havalige 		.compatible = "amd,versal2-mdb-host",
4635f3de23dSThippeswamy Havalige 	},
4645f3de23dSThippeswamy Havalige 	{},
4655f3de23dSThippeswamy Havalige };
4665f3de23dSThippeswamy Havalige 
4675f3de23dSThippeswamy Havalige static struct platform_driver amd_mdb_pcie_driver = {
4685f3de23dSThippeswamy Havalige 	.driver = {
4695f3de23dSThippeswamy Havalige 		.name	= "amd-mdb-pcie",
4705f3de23dSThippeswamy Havalige 		.of_match_table = amd_mdb_pcie_of_match,
4715f3de23dSThippeswamy Havalige 		.suppress_bind_attrs = true,
4725f3de23dSThippeswamy Havalige 	},
4735f3de23dSThippeswamy Havalige 	.probe = amd_mdb_pcie_probe,
4745f3de23dSThippeswamy Havalige };
4755f3de23dSThippeswamy Havalige 
4765f3de23dSThippeswamy Havalige builtin_platform_driver(amd_mdb_pcie_driver);
477