1508f6106SBharat Kumar Gogada // SPDX-License-Identifier: GPL-2.0+
2508f6106SBharat Kumar Gogada /*
3508f6106SBharat Kumar Gogada  * PCIe host controller driver for Xilinx Versal CPM DMA Bridge
4508f6106SBharat Kumar Gogada  *
5508f6106SBharat Kumar Gogada  * (C) Copyright 2019 - 2020, Xilinx, Inc.
6508f6106SBharat Kumar Gogada  */
7508f6106SBharat Kumar Gogada 
8508f6106SBharat Kumar Gogada #include <linux/bitfield.h>
9508f6106SBharat Kumar Gogada #include <linux/interrupt.h>
10508f6106SBharat Kumar Gogada #include <linux/irq.h>
11508f6106SBharat Kumar Gogada #include <linux/irqchip.h>
12508f6106SBharat Kumar Gogada #include <linux/irqchip/chained_irq.h>
13508f6106SBharat Kumar Gogada #include <linux/irqdomain.h>
14508f6106SBharat Kumar Gogada #include <linux/kernel.h>
15508f6106SBharat Kumar Gogada #include <linux/module.h>
16508f6106SBharat Kumar Gogada #include <linux/of_address.h>
17508f6106SBharat Kumar Gogada #include <linux/of_pci.h>
18508f6106SBharat Kumar Gogada #include <linux/of_platform.h>
19508f6106SBharat Kumar Gogada 
20508f6106SBharat Kumar Gogada #include "../pci.h"
21*a977ee94SThippeswamy Havalige #include "pcie-xilinx-common.h"
22508f6106SBharat Kumar Gogada 
23508f6106SBharat Kumar Gogada /* Register definitions */
24508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_IDR		0x00000E10
25508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_IMR		0x00000E14
26508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_PSCR	0x00000E1C
27508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_RPSC	0x00000E20
28508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_RPEFR	0x00000E2C
29508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_IDRN	0x00000E38
30508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_IDRN_MASK	0x00000E3C
31508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_MISC_IR_STATUS	0x00000340
32508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_MISC_IR_ENABLE	0x00000348
33508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_MISC_IR_LOCAL	BIT(1)
34508f6106SBharat Kumar Gogada 
3551f1ffc0SBharat Kumar Gogada #define XILINX_CPM_PCIE_IR_STATUS       0x000002A0
3651f1ffc0SBharat Kumar Gogada #define XILINX_CPM_PCIE_IR_ENABLE       0x000002A8
3751f1ffc0SBharat Kumar Gogada #define XILINX_CPM_PCIE_IR_LOCAL        BIT(0)
3851f1ffc0SBharat Kumar Gogada 
39*a977ee94SThippeswamy Havalige #define IMR(x) BIT(XILINX_PCIE_INTR_ ##x)
40508f6106SBharat Kumar Gogada 
41508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_IMR_ALL_MASK			\
42508f6106SBharat Kumar Gogada 	(						\
43508f6106SBharat Kumar Gogada 		IMR(LINK_DOWN)		|		\
44508f6106SBharat Kumar Gogada 		IMR(HOT_RESET)		|		\
45508f6106SBharat Kumar Gogada 		IMR(CFG_PCIE_TIMEOUT)	|		\
46508f6106SBharat Kumar Gogada 		IMR(CFG_TIMEOUT)	|		\
47508f6106SBharat Kumar Gogada 		IMR(CORRECTABLE)	|		\
48508f6106SBharat Kumar Gogada 		IMR(NONFATAL)		|		\
49508f6106SBharat Kumar Gogada 		IMR(FATAL)		|		\
50508f6106SBharat Kumar Gogada 		IMR(CFG_ERR_POISON)	|		\
51508f6106SBharat Kumar Gogada 		IMR(PME_TO_ACK_RCVD)	|		\
52508f6106SBharat Kumar Gogada 		IMR(INTX)		|		\
53508f6106SBharat Kumar Gogada 		IMR(PM_PME_RCVD)	|		\
54508f6106SBharat Kumar Gogada 		IMR(SLV_UNSUPP)		|		\
55508f6106SBharat Kumar Gogada 		IMR(SLV_UNEXP)		|		\
56508f6106SBharat Kumar Gogada 		IMR(SLV_COMPL)		|		\
57508f6106SBharat Kumar Gogada 		IMR(SLV_ERRP)		|		\
58508f6106SBharat Kumar Gogada 		IMR(SLV_CMPABT)		|		\
59508f6106SBharat Kumar Gogada 		IMR(SLV_ILLBUR)		|		\
60508f6106SBharat Kumar Gogada 		IMR(MST_DECERR)		|		\
61508f6106SBharat Kumar Gogada 		IMR(MST_SLVERR)		|		\
62508f6106SBharat Kumar Gogada 		IMR(SLV_PCIE_TIMEOUT)			\
63508f6106SBharat Kumar Gogada 	)
64508f6106SBharat Kumar Gogada 
65508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_IDR_ALL_MASK		0xFFFFFFFF
66508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_IDRN_MASK		GENMASK(19, 16)
67508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_IDRN_SHIFT		16
68508f6106SBharat Kumar Gogada 
69508f6106SBharat Kumar Gogada /* Root Port Error FIFO Read Register definitions */
70508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_RPEFR_ERR_VALID		BIT(18)
71508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_RPEFR_REQ_ID		GENMASK(15, 0)
72508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_RPEFR_ALL_MASK		0xFFFFFFFF
73508f6106SBharat Kumar Gogada 
74508f6106SBharat Kumar Gogada /* Root Port Status/control Register definitions */
75508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_RPSC_BEN		BIT(0)
76508f6106SBharat Kumar Gogada 
77508f6106SBharat Kumar Gogada /* Phy Status/Control Register definitions */
78508f6106SBharat Kumar Gogada #define XILINX_CPM_PCIE_REG_PSCR_LNKUP		BIT(11)
79508f6106SBharat Kumar Gogada 
8051f1ffc0SBharat Kumar Gogada enum xilinx_cpm_version {
8151f1ffc0SBharat Kumar Gogada 	CPM,
8251f1ffc0SBharat Kumar Gogada 	CPM5,
8351f1ffc0SBharat Kumar Gogada };
8451f1ffc0SBharat Kumar Gogada 
8551f1ffc0SBharat Kumar Gogada /**
8651f1ffc0SBharat Kumar Gogada  * struct xilinx_cpm_variant - CPM variant information
8751f1ffc0SBharat Kumar Gogada  * @version: CPM version
8851f1ffc0SBharat Kumar Gogada  */
8951f1ffc0SBharat Kumar Gogada struct xilinx_cpm_variant {
9051f1ffc0SBharat Kumar Gogada 	enum xilinx_cpm_version version;
9151f1ffc0SBharat Kumar Gogada };
9251f1ffc0SBharat Kumar Gogada 
93508f6106SBharat Kumar Gogada /**
94dacee587SBjorn Helgaas  * struct xilinx_cpm_pcie - PCIe port information
95dacee587SBjorn Helgaas  * @dev: Device pointer
96508f6106SBharat Kumar Gogada  * @reg_base: Bridge Register Base
97508f6106SBharat Kumar Gogada  * @cpm_base: CPM System Level Control and Status Register(SLCR) Base
98508f6106SBharat Kumar Gogada  * @intx_domain: Legacy IRQ domain pointer
99508f6106SBharat Kumar Gogada  * @cpm_domain: CPM IRQ domain pointer
100508f6106SBharat Kumar Gogada  * @cfg: Holds mappings of config space window
101508f6106SBharat Kumar Gogada  * @intx_irq: legacy interrupt number
102508f6106SBharat Kumar Gogada  * @irq: Error interrupt number
103508f6106SBharat Kumar Gogada  * @lock: lock protecting shared register access
10451f1ffc0SBharat Kumar Gogada  * @variant: CPM version check pointer
105508f6106SBharat Kumar Gogada  */
106dacee587SBjorn Helgaas struct xilinx_cpm_pcie {
107dacee587SBjorn Helgaas 	struct device			*dev;
108508f6106SBharat Kumar Gogada 	void __iomem			*reg_base;
109508f6106SBharat Kumar Gogada 	void __iomem			*cpm_base;
110508f6106SBharat Kumar Gogada 	struct irq_domain		*intx_domain;
111508f6106SBharat Kumar Gogada 	struct irq_domain		*cpm_domain;
112508f6106SBharat Kumar Gogada 	struct pci_config_window	*cfg;
113508f6106SBharat Kumar Gogada 	int				intx_irq;
114508f6106SBharat Kumar Gogada 	int				irq;
115508f6106SBharat Kumar Gogada 	raw_spinlock_t			lock;
11651f1ffc0SBharat Kumar Gogada 	const struct xilinx_cpm_variant   *variant;
117508f6106SBharat Kumar Gogada };
118508f6106SBharat Kumar Gogada 
pcie_read(struct xilinx_cpm_pcie * port,u32 reg)119dacee587SBjorn Helgaas static u32 pcie_read(struct xilinx_cpm_pcie *port, u32 reg)
120508f6106SBharat Kumar Gogada {
121508f6106SBharat Kumar Gogada 	return readl_relaxed(port->reg_base + reg);
122508f6106SBharat Kumar Gogada }
123508f6106SBharat Kumar Gogada 
pcie_write(struct xilinx_cpm_pcie * port,u32 val,u32 reg)124dacee587SBjorn Helgaas static void pcie_write(struct xilinx_cpm_pcie *port,
125508f6106SBharat Kumar Gogada 		       u32 val, u32 reg)
126508f6106SBharat Kumar Gogada {
127508f6106SBharat Kumar Gogada 	writel_relaxed(val, port->reg_base + reg);
128508f6106SBharat Kumar Gogada }
129508f6106SBharat Kumar Gogada 
cpm_pcie_link_up(struct xilinx_cpm_pcie * port)130dacee587SBjorn Helgaas static bool cpm_pcie_link_up(struct xilinx_cpm_pcie *port)
131508f6106SBharat Kumar Gogada {
132508f6106SBharat Kumar Gogada 	return (pcie_read(port, XILINX_CPM_PCIE_REG_PSCR) &
133508f6106SBharat Kumar Gogada 		XILINX_CPM_PCIE_REG_PSCR_LNKUP);
134508f6106SBharat Kumar Gogada }
135508f6106SBharat Kumar Gogada 
cpm_pcie_clear_err_interrupts(struct xilinx_cpm_pcie * port)136dacee587SBjorn Helgaas static void cpm_pcie_clear_err_interrupts(struct xilinx_cpm_pcie *port)
137508f6106SBharat Kumar Gogada {
138508f6106SBharat Kumar Gogada 	unsigned long val = pcie_read(port, XILINX_CPM_PCIE_REG_RPEFR);
139508f6106SBharat Kumar Gogada 
140508f6106SBharat Kumar Gogada 	if (val & XILINX_CPM_PCIE_RPEFR_ERR_VALID) {
141508f6106SBharat Kumar Gogada 		dev_dbg(port->dev, "Requester ID %lu\n",
142508f6106SBharat Kumar Gogada 			val & XILINX_CPM_PCIE_RPEFR_REQ_ID);
143508f6106SBharat Kumar Gogada 		pcie_write(port, XILINX_CPM_PCIE_RPEFR_ALL_MASK,
144508f6106SBharat Kumar Gogada 			   XILINX_CPM_PCIE_REG_RPEFR);
145508f6106SBharat Kumar Gogada 	}
146508f6106SBharat Kumar Gogada }
147508f6106SBharat Kumar Gogada 
xilinx_cpm_mask_leg_irq(struct irq_data * data)148508f6106SBharat Kumar Gogada static void xilinx_cpm_mask_leg_irq(struct irq_data *data)
149508f6106SBharat Kumar Gogada {
150dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_data_get_irq_chip_data(data);
151508f6106SBharat Kumar Gogada 	unsigned long flags;
152508f6106SBharat Kumar Gogada 	u32 mask;
153508f6106SBharat Kumar Gogada 	u32 val;
154508f6106SBharat Kumar Gogada 
155508f6106SBharat Kumar Gogada 	mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT);
156508f6106SBharat Kumar Gogada 	raw_spin_lock_irqsave(&port->lock, flags);
157508f6106SBharat Kumar Gogada 	val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK);
158508f6106SBharat Kumar Gogada 	pcie_write(port, (val & (~mask)), XILINX_CPM_PCIE_REG_IDRN_MASK);
159508f6106SBharat Kumar Gogada 	raw_spin_unlock_irqrestore(&port->lock, flags);
160508f6106SBharat Kumar Gogada }
161508f6106SBharat Kumar Gogada 
xilinx_cpm_unmask_leg_irq(struct irq_data * data)162508f6106SBharat Kumar Gogada static void xilinx_cpm_unmask_leg_irq(struct irq_data *data)
163508f6106SBharat Kumar Gogada {
164dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_data_get_irq_chip_data(data);
165508f6106SBharat Kumar Gogada 	unsigned long flags;
166508f6106SBharat Kumar Gogada 	u32 mask;
167508f6106SBharat Kumar Gogada 	u32 val;
168508f6106SBharat Kumar Gogada 
169508f6106SBharat Kumar Gogada 	mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT);
170508f6106SBharat Kumar Gogada 	raw_spin_lock_irqsave(&port->lock, flags);
171508f6106SBharat Kumar Gogada 	val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK);
172508f6106SBharat Kumar Gogada 	pcie_write(port, (val | mask), XILINX_CPM_PCIE_REG_IDRN_MASK);
173508f6106SBharat Kumar Gogada 	raw_spin_unlock_irqrestore(&port->lock, flags);
174508f6106SBharat Kumar Gogada }
175508f6106SBharat Kumar Gogada 
176508f6106SBharat Kumar Gogada static struct irq_chip xilinx_cpm_leg_irq_chip = {
177508f6106SBharat Kumar Gogada 	.name		= "INTx",
178508f6106SBharat Kumar Gogada 	.irq_mask	= xilinx_cpm_mask_leg_irq,
179508f6106SBharat Kumar Gogada 	.irq_unmask	= xilinx_cpm_unmask_leg_irq,
180508f6106SBharat Kumar Gogada };
181508f6106SBharat Kumar Gogada 
182508f6106SBharat Kumar Gogada /**
183508f6106SBharat Kumar Gogada  * xilinx_cpm_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
184508f6106SBharat Kumar Gogada  * @domain: IRQ domain
185508f6106SBharat Kumar Gogada  * @irq: Virtual IRQ number
186508f6106SBharat Kumar Gogada  * @hwirq: HW interrupt number
187508f6106SBharat Kumar Gogada  *
188508f6106SBharat Kumar Gogada  * Return: Always returns 0.
189508f6106SBharat Kumar Gogada  */
xilinx_cpm_pcie_intx_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)190508f6106SBharat Kumar Gogada static int xilinx_cpm_pcie_intx_map(struct irq_domain *domain,
191508f6106SBharat Kumar Gogada 				    unsigned int irq, irq_hw_number_t hwirq)
192508f6106SBharat Kumar Gogada {
193508f6106SBharat Kumar Gogada 	irq_set_chip_and_handler(irq, &xilinx_cpm_leg_irq_chip,
194508f6106SBharat Kumar Gogada 				 handle_level_irq);
195508f6106SBharat Kumar Gogada 	irq_set_chip_data(irq, domain->host_data);
196508f6106SBharat Kumar Gogada 	irq_set_status_flags(irq, IRQ_LEVEL);
197508f6106SBharat Kumar Gogada 
198508f6106SBharat Kumar Gogada 	return 0;
199508f6106SBharat Kumar Gogada }
200508f6106SBharat Kumar Gogada 
201508f6106SBharat Kumar Gogada /* INTx IRQ Domain operations */
202508f6106SBharat Kumar Gogada static const struct irq_domain_ops intx_domain_ops = {
203508f6106SBharat Kumar Gogada 	.map = xilinx_cpm_pcie_intx_map,
204508f6106SBharat Kumar Gogada };
205508f6106SBharat Kumar Gogada 
xilinx_cpm_pcie_intx_flow(struct irq_desc * desc)206508f6106SBharat Kumar Gogada static void xilinx_cpm_pcie_intx_flow(struct irq_desc *desc)
207508f6106SBharat Kumar Gogada {
208dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_desc_get_handler_data(desc);
209508f6106SBharat Kumar Gogada 	struct irq_chip *chip = irq_desc_get_chip(desc);
210508f6106SBharat Kumar Gogada 	unsigned long val;
211508f6106SBharat Kumar Gogada 	int i;
212508f6106SBharat Kumar Gogada 
213508f6106SBharat Kumar Gogada 	chained_irq_enter(chip, desc);
214508f6106SBharat Kumar Gogada 
215508f6106SBharat Kumar Gogada 	val = FIELD_GET(XILINX_CPM_PCIE_IDRN_MASK,
216508f6106SBharat Kumar Gogada 			pcie_read(port, XILINX_CPM_PCIE_REG_IDRN));
217508f6106SBharat Kumar Gogada 
218508f6106SBharat Kumar Gogada 	for_each_set_bit(i, &val, PCI_NUM_INTX)
219d21faba1SMarc Zyngier 		generic_handle_domain_irq(port->intx_domain, i);
220508f6106SBharat Kumar Gogada 
221508f6106SBharat Kumar Gogada 	chained_irq_exit(chip, desc);
222508f6106SBharat Kumar Gogada }
223508f6106SBharat Kumar Gogada 
xilinx_cpm_mask_event_irq(struct irq_data * d)224508f6106SBharat Kumar Gogada static void xilinx_cpm_mask_event_irq(struct irq_data *d)
225508f6106SBharat Kumar Gogada {
226dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_data_get_irq_chip_data(d);
227508f6106SBharat Kumar Gogada 	u32 val;
228508f6106SBharat Kumar Gogada 
229508f6106SBharat Kumar Gogada 	raw_spin_lock(&port->lock);
230508f6106SBharat Kumar Gogada 	val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
231508f6106SBharat Kumar Gogada 	val &= ~BIT(d->hwirq);
232508f6106SBharat Kumar Gogada 	pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR);
233508f6106SBharat Kumar Gogada 	raw_spin_unlock(&port->lock);
234508f6106SBharat Kumar Gogada }
235508f6106SBharat Kumar Gogada 
xilinx_cpm_unmask_event_irq(struct irq_data * d)236508f6106SBharat Kumar Gogada static void xilinx_cpm_unmask_event_irq(struct irq_data *d)
237508f6106SBharat Kumar Gogada {
238dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_data_get_irq_chip_data(d);
239508f6106SBharat Kumar Gogada 	u32 val;
240508f6106SBharat Kumar Gogada 
241508f6106SBharat Kumar Gogada 	raw_spin_lock(&port->lock);
242508f6106SBharat Kumar Gogada 	val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
243508f6106SBharat Kumar Gogada 	val |= BIT(d->hwirq);
244508f6106SBharat Kumar Gogada 	pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR);
245508f6106SBharat Kumar Gogada 	raw_spin_unlock(&port->lock);
246508f6106SBharat Kumar Gogada }
247508f6106SBharat Kumar Gogada 
248508f6106SBharat Kumar Gogada static struct irq_chip xilinx_cpm_event_irq_chip = {
249508f6106SBharat Kumar Gogada 	.name		= "RC-Event",
250508f6106SBharat Kumar Gogada 	.irq_mask	= xilinx_cpm_mask_event_irq,
251508f6106SBharat Kumar Gogada 	.irq_unmask	= xilinx_cpm_unmask_event_irq,
252508f6106SBharat Kumar Gogada };
253508f6106SBharat Kumar Gogada 
xilinx_cpm_pcie_event_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)254508f6106SBharat Kumar Gogada static int xilinx_cpm_pcie_event_map(struct irq_domain *domain,
255508f6106SBharat Kumar Gogada 				     unsigned int irq, irq_hw_number_t hwirq)
256508f6106SBharat Kumar Gogada {
257508f6106SBharat Kumar Gogada 	irq_set_chip_and_handler(irq, &xilinx_cpm_event_irq_chip,
258508f6106SBharat Kumar Gogada 				 handle_level_irq);
259508f6106SBharat Kumar Gogada 	irq_set_chip_data(irq, domain->host_data);
260508f6106SBharat Kumar Gogada 	irq_set_status_flags(irq, IRQ_LEVEL);
261508f6106SBharat Kumar Gogada 	return 0;
262508f6106SBharat Kumar Gogada }
263508f6106SBharat Kumar Gogada 
264508f6106SBharat Kumar Gogada static const struct irq_domain_ops event_domain_ops = {
265508f6106SBharat Kumar Gogada 	.map = xilinx_cpm_pcie_event_map,
266508f6106SBharat Kumar Gogada };
267508f6106SBharat Kumar Gogada 
xilinx_cpm_pcie_event_flow(struct irq_desc * desc)268508f6106SBharat Kumar Gogada static void xilinx_cpm_pcie_event_flow(struct irq_desc *desc)
269508f6106SBharat Kumar Gogada {
270dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = irq_desc_get_handler_data(desc);
271508f6106SBharat Kumar Gogada 	struct irq_chip *chip = irq_desc_get_chip(desc);
272508f6106SBharat Kumar Gogada 	unsigned long val;
273508f6106SBharat Kumar Gogada 	int i;
274508f6106SBharat Kumar Gogada 
275508f6106SBharat Kumar Gogada 	chained_irq_enter(chip, desc);
276508f6106SBharat Kumar Gogada 	val =  pcie_read(port, XILINX_CPM_PCIE_REG_IDR);
277508f6106SBharat Kumar Gogada 	val &= pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
278508f6106SBharat Kumar Gogada 	for_each_set_bit(i, &val, 32)
279d21faba1SMarc Zyngier 		generic_handle_domain_irq(port->cpm_domain, i);
280508f6106SBharat Kumar Gogada 	pcie_write(port, val, XILINX_CPM_PCIE_REG_IDR);
281508f6106SBharat Kumar Gogada 
28251f1ffc0SBharat Kumar Gogada 	if (port->variant->version == CPM5) {
28351f1ffc0SBharat Kumar Gogada 		val = readl_relaxed(port->cpm_base + XILINX_CPM_PCIE_IR_STATUS);
28451f1ffc0SBharat Kumar Gogada 		if (val)
28551f1ffc0SBharat Kumar Gogada 			writel_relaxed(val, port->cpm_base +
28651f1ffc0SBharat Kumar Gogada 					    XILINX_CPM_PCIE_IR_STATUS);
28751f1ffc0SBharat Kumar Gogada 	}
28851f1ffc0SBharat Kumar Gogada 
289508f6106SBharat Kumar Gogada 	/*
290508f6106SBharat Kumar Gogada 	 * XILINX_CPM_PCIE_MISC_IR_STATUS register is mapped to
291508f6106SBharat Kumar Gogada 	 * CPM SLCR block.
292508f6106SBharat Kumar Gogada 	 */
293508f6106SBharat Kumar Gogada 	val = readl_relaxed(port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS);
294508f6106SBharat Kumar Gogada 	if (val)
295508f6106SBharat Kumar Gogada 		writel_relaxed(val,
296508f6106SBharat Kumar Gogada 			       port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS);
297508f6106SBharat Kumar Gogada 
298508f6106SBharat Kumar Gogada 	chained_irq_exit(chip, desc);
299508f6106SBharat Kumar Gogada }
300508f6106SBharat Kumar Gogada 
301508f6106SBharat Kumar Gogada #define _IC(x, s)                              \
302*a977ee94SThippeswamy Havalige 	[XILINX_PCIE_INTR_ ## x] = { __stringify(x), s }
303508f6106SBharat Kumar Gogada 
304508f6106SBharat Kumar Gogada static const struct {
305508f6106SBharat Kumar Gogada 	const char      *sym;
306508f6106SBharat Kumar Gogada 	const char      *str;
307508f6106SBharat Kumar Gogada } intr_cause[32] = {
308508f6106SBharat Kumar Gogada 	_IC(LINK_DOWN,		"Link Down"),
309508f6106SBharat Kumar Gogada 	_IC(HOT_RESET,		"Hot reset"),
310508f6106SBharat Kumar Gogada 	_IC(CFG_TIMEOUT,	"ECAM access timeout"),
311508f6106SBharat Kumar Gogada 	_IC(CORRECTABLE,	"Correctable error message"),
312508f6106SBharat Kumar Gogada 	_IC(NONFATAL,		"Non fatal error message"),
313508f6106SBharat Kumar Gogada 	_IC(FATAL,		"Fatal error message"),
314508f6106SBharat Kumar Gogada 	_IC(SLV_UNSUPP,		"Slave unsupported request"),
315508f6106SBharat Kumar Gogada 	_IC(SLV_UNEXP,		"Slave unexpected completion"),
316508f6106SBharat Kumar Gogada 	_IC(SLV_COMPL,		"Slave completion timeout"),
317508f6106SBharat Kumar Gogada 	_IC(SLV_ERRP,		"Slave Error Poison"),
318508f6106SBharat Kumar Gogada 	_IC(SLV_CMPABT,		"Slave Completer Abort"),
319508f6106SBharat Kumar Gogada 	_IC(SLV_ILLBUR,		"Slave Illegal Burst"),
320508f6106SBharat Kumar Gogada 	_IC(MST_DECERR,		"Master decode error"),
321508f6106SBharat Kumar Gogada 	_IC(MST_SLVERR,		"Master slave error"),
322508f6106SBharat Kumar Gogada 	_IC(CFG_PCIE_TIMEOUT,	"PCIe ECAM access timeout"),
323508f6106SBharat Kumar Gogada 	_IC(CFG_ERR_POISON,	"ECAM poisoned completion received"),
324508f6106SBharat Kumar Gogada 	_IC(PME_TO_ACK_RCVD,	"PME_TO_ACK message received"),
325508f6106SBharat Kumar Gogada 	_IC(PM_PME_RCVD,	"PM_PME message received"),
326508f6106SBharat Kumar Gogada 	_IC(SLV_PCIE_TIMEOUT,	"PCIe completion timeout received"),
327508f6106SBharat Kumar Gogada };
328508f6106SBharat Kumar Gogada 
xilinx_cpm_pcie_intr_handler(int irq,void * dev_id)329508f6106SBharat Kumar Gogada static irqreturn_t xilinx_cpm_pcie_intr_handler(int irq, void *dev_id)
330508f6106SBharat Kumar Gogada {
331dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port = dev_id;
332508f6106SBharat Kumar Gogada 	struct device *dev = port->dev;
333508f6106SBharat Kumar Gogada 	struct irq_data *d;
334508f6106SBharat Kumar Gogada 
335508f6106SBharat Kumar Gogada 	d = irq_domain_get_irq_data(port->cpm_domain, irq);
336508f6106SBharat Kumar Gogada 
337508f6106SBharat Kumar Gogada 	switch (d->hwirq) {
338*a977ee94SThippeswamy Havalige 	case XILINX_PCIE_INTR_CORRECTABLE:
339*a977ee94SThippeswamy Havalige 	case XILINX_PCIE_INTR_NONFATAL:
340*a977ee94SThippeswamy Havalige 	case XILINX_PCIE_INTR_FATAL:
341508f6106SBharat Kumar Gogada 		cpm_pcie_clear_err_interrupts(port);
342508f6106SBharat Kumar Gogada 		fallthrough;
343508f6106SBharat Kumar Gogada 
344508f6106SBharat Kumar Gogada 	default:
345508f6106SBharat Kumar Gogada 		if (intr_cause[d->hwirq].str)
346508f6106SBharat Kumar Gogada 			dev_warn(dev, "%s\n", intr_cause[d->hwirq].str);
347508f6106SBharat Kumar Gogada 		else
348508f6106SBharat Kumar Gogada 			dev_warn(dev, "Unknown IRQ %ld\n", d->hwirq);
349508f6106SBharat Kumar Gogada 	}
350508f6106SBharat Kumar Gogada 
351508f6106SBharat Kumar Gogada 	return IRQ_HANDLED;
352508f6106SBharat Kumar Gogada }
353508f6106SBharat Kumar Gogada 
xilinx_cpm_free_irq_domains(struct xilinx_cpm_pcie * port)354dacee587SBjorn Helgaas static void xilinx_cpm_free_irq_domains(struct xilinx_cpm_pcie *port)
355508f6106SBharat Kumar Gogada {
356508f6106SBharat Kumar Gogada 	if (port->intx_domain) {
357508f6106SBharat Kumar Gogada 		irq_domain_remove(port->intx_domain);
358508f6106SBharat Kumar Gogada 		port->intx_domain = NULL;
359508f6106SBharat Kumar Gogada 	}
360508f6106SBharat Kumar Gogada 
361508f6106SBharat Kumar Gogada 	if (port->cpm_domain) {
362508f6106SBharat Kumar Gogada 		irq_domain_remove(port->cpm_domain);
363508f6106SBharat Kumar Gogada 		port->cpm_domain = NULL;
364508f6106SBharat Kumar Gogada 	}
365508f6106SBharat Kumar Gogada }
366508f6106SBharat Kumar Gogada 
367508f6106SBharat Kumar Gogada /**
368508f6106SBharat Kumar Gogada  * xilinx_cpm_pcie_init_irq_domain - Initialize IRQ domain
369508f6106SBharat Kumar Gogada  * @port: PCIe port information
370508f6106SBharat Kumar Gogada  *
371508f6106SBharat Kumar Gogada  * Return: '0' on success and error value on failure
372508f6106SBharat Kumar Gogada  */
xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie * port)373dacee587SBjorn Helgaas static int xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie *port)
374508f6106SBharat Kumar Gogada {
375508f6106SBharat Kumar Gogada 	struct device *dev = port->dev;
376508f6106SBharat Kumar Gogada 	struct device_node *node = dev->of_node;
377508f6106SBharat Kumar Gogada 	struct device_node *pcie_intc_node;
378508f6106SBharat Kumar Gogada 
379508f6106SBharat Kumar Gogada 	/* Setup INTx */
380508f6106SBharat Kumar Gogada 	pcie_intc_node = of_get_next_child(node, NULL);
381508f6106SBharat Kumar Gogada 	if (!pcie_intc_node) {
382508f6106SBharat Kumar Gogada 		dev_err(dev, "No PCIe Intc node found\n");
383508f6106SBharat Kumar Gogada 		return -EINVAL;
384508f6106SBharat Kumar Gogada 	}
385508f6106SBharat Kumar Gogada 
386508f6106SBharat Kumar Gogada 	port->cpm_domain = irq_domain_add_linear(pcie_intc_node, 32,
387508f6106SBharat Kumar Gogada 						 &event_domain_ops,
388508f6106SBharat Kumar Gogada 						 port);
389508f6106SBharat Kumar Gogada 	if (!port->cpm_domain)
390508f6106SBharat Kumar Gogada 		goto out;
391508f6106SBharat Kumar Gogada 
392508f6106SBharat Kumar Gogada 	irq_domain_update_bus_token(port->cpm_domain, DOMAIN_BUS_NEXUS);
393508f6106SBharat Kumar Gogada 
394508f6106SBharat Kumar Gogada 	port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
395508f6106SBharat Kumar Gogada 						  &intx_domain_ops,
396508f6106SBharat Kumar Gogada 						  port);
397508f6106SBharat Kumar Gogada 	if (!port->intx_domain)
398508f6106SBharat Kumar Gogada 		goto out;
399508f6106SBharat Kumar Gogada 
400508f6106SBharat Kumar Gogada 	irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
401508f6106SBharat Kumar Gogada 
402508f6106SBharat Kumar Gogada 	of_node_put(pcie_intc_node);
403508f6106SBharat Kumar Gogada 	raw_spin_lock_init(&port->lock);
404508f6106SBharat Kumar Gogada 
405508f6106SBharat Kumar Gogada 	return 0;
406508f6106SBharat Kumar Gogada out:
407508f6106SBharat Kumar Gogada 	xilinx_cpm_free_irq_domains(port);
408ae191d2eSPan Bian 	of_node_put(pcie_intc_node);
409508f6106SBharat Kumar Gogada 	dev_err(dev, "Failed to allocate IRQ domains\n");
410508f6106SBharat Kumar Gogada 
411508f6106SBharat Kumar Gogada 	return -ENOMEM;
412508f6106SBharat Kumar Gogada }
413508f6106SBharat Kumar Gogada 
xilinx_cpm_setup_irq(struct xilinx_cpm_pcie * port)414dacee587SBjorn Helgaas static int xilinx_cpm_setup_irq(struct xilinx_cpm_pcie *port)
415508f6106SBharat Kumar Gogada {
416508f6106SBharat Kumar Gogada 	struct device *dev = port->dev;
417508f6106SBharat Kumar Gogada 	struct platform_device *pdev = to_platform_device(dev);
418508f6106SBharat Kumar Gogada 	int i, irq;
419508f6106SBharat Kumar Gogada 
420508f6106SBharat Kumar Gogada 	port->irq = platform_get_irq(pdev, 0);
421508f6106SBharat Kumar Gogada 	if (port->irq < 0)
422508f6106SBharat Kumar Gogada 		return port->irq;
423508f6106SBharat Kumar Gogada 
424508f6106SBharat Kumar Gogada 	for (i = 0; i < ARRAY_SIZE(intr_cause); i++) {
425508f6106SBharat Kumar Gogada 		int err;
426508f6106SBharat Kumar Gogada 
427508f6106SBharat Kumar Gogada 		if (!intr_cause[i].str)
428508f6106SBharat Kumar Gogada 			continue;
429508f6106SBharat Kumar Gogada 
430508f6106SBharat Kumar Gogada 		irq = irq_create_mapping(port->cpm_domain, i);
431508f6106SBharat Kumar Gogada 		if (!irq) {
432508f6106SBharat Kumar Gogada 			dev_err(dev, "Failed to map interrupt\n");
433508f6106SBharat Kumar Gogada 			return -ENXIO;
434508f6106SBharat Kumar Gogada 		}
435508f6106SBharat Kumar Gogada 
436508f6106SBharat Kumar Gogada 		err = devm_request_irq(dev, irq, xilinx_cpm_pcie_intr_handler,
437508f6106SBharat Kumar Gogada 				       0, intr_cause[i].sym, port);
438508f6106SBharat Kumar Gogada 		if (err) {
439508f6106SBharat Kumar Gogada 			dev_err(dev, "Failed to request IRQ %d\n", irq);
440508f6106SBharat Kumar Gogada 			return err;
441508f6106SBharat Kumar Gogada 		}
442508f6106SBharat Kumar Gogada 	}
443508f6106SBharat Kumar Gogada 
444508f6106SBharat Kumar Gogada 	port->intx_irq = irq_create_mapping(port->cpm_domain,
445*a977ee94SThippeswamy Havalige 					    XILINX_PCIE_INTR_INTX);
446508f6106SBharat Kumar Gogada 	if (!port->intx_irq) {
447508f6106SBharat Kumar Gogada 		dev_err(dev, "Failed to map INTx interrupt\n");
448508f6106SBharat Kumar Gogada 		return -ENXIO;
449508f6106SBharat Kumar Gogada 	}
450508f6106SBharat Kumar Gogada 
451508f6106SBharat Kumar Gogada 	/* Plug the INTx chained handler */
452508f6106SBharat Kumar Gogada 	irq_set_chained_handler_and_data(port->intx_irq,
453508f6106SBharat Kumar Gogada 					 xilinx_cpm_pcie_intx_flow, port);
454508f6106SBharat Kumar Gogada 
455508f6106SBharat Kumar Gogada 	/* Plug the main event chained handler */
456508f6106SBharat Kumar Gogada 	irq_set_chained_handler_and_data(port->irq,
457508f6106SBharat Kumar Gogada 					 xilinx_cpm_pcie_event_flow, port);
458508f6106SBharat Kumar Gogada 
459508f6106SBharat Kumar Gogada 	return 0;
460508f6106SBharat Kumar Gogada }
461508f6106SBharat Kumar Gogada 
462508f6106SBharat Kumar Gogada /**
463508f6106SBharat Kumar Gogada  * xilinx_cpm_pcie_init_port - Initialize hardware
464508f6106SBharat Kumar Gogada  * @port: PCIe port information
465508f6106SBharat Kumar Gogada  */
xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie * port)466dacee587SBjorn Helgaas static void xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie *port)
467508f6106SBharat Kumar Gogada {
468508f6106SBharat Kumar Gogada 	if (cpm_pcie_link_up(port))
469508f6106SBharat Kumar Gogada 		dev_info(port->dev, "PCIe Link is UP\n");
470508f6106SBharat Kumar Gogada 	else
471508f6106SBharat Kumar Gogada 		dev_info(port->dev, "PCIe Link is DOWN\n");
472508f6106SBharat Kumar Gogada 
473508f6106SBharat Kumar Gogada 	/* Disable all interrupts */
474508f6106SBharat Kumar Gogada 	pcie_write(port, ~XILINX_CPM_PCIE_IDR_ALL_MASK,
475508f6106SBharat Kumar Gogada 		   XILINX_CPM_PCIE_REG_IMR);
476508f6106SBharat Kumar Gogada 
477508f6106SBharat Kumar Gogada 	/* Clear pending interrupts */
478508f6106SBharat Kumar Gogada 	pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_IDR) &
479508f6106SBharat Kumar Gogada 		   XILINX_CPM_PCIE_IMR_ALL_MASK,
480508f6106SBharat Kumar Gogada 		   XILINX_CPM_PCIE_REG_IDR);
481508f6106SBharat Kumar Gogada 
482508f6106SBharat Kumar Gogada 	/*
483508f6106SBharat Kumar Gogada 	 * XILINX_CPM_PCIE_MISC_IR_ENABLE register is mapped to
484508f6106SBharat Kumar Gogada 	 * CPM SLCR block.
485508f6106SBharat Kumar Gogada 	 */
486508f6106SBharat Kumar Gogada 	writel(XILINX_CPM_PCIE_MISC_IR_LOCAL,
487508f6106SBharat Kumar Gogada 	       port->cpm_base + XILINX_CPM_PCIE_MISC_IR_ENABLE);
48851f1ffc0SBharat Kumar Gogada 
48951f1ffc0SBharat Kumar Gogada 	if (port->variant->version == CPM5) {
49051f1ffc0SBharat Kumar Gogada 		writel(XILINX_CPM_PCIE_IR_LOCAL,
49151f1ffc0SBharat Kumar Gogada 		       port->cpm_base + XILINX_CPM_PCIE_IR_ENABLE);
49251f1ffc0SBharat Kumar Gogada 	}
49351f1ffc0SBharat Kumar Gogada 
494508f6106SBharat Kumar Gogada 	/* Enable the Bridge enable bit */
495508f6106SBharat Kumar Gogada 	pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_RPSC) |
496508f6106SBharat Kumar Gogada 		   XILINX_CPM_PCIE_REG_RPSC_BEN,
497508f6106SBharat Kumar Gogada 		   XILINX_CPM_PCIE_REG_RPSC);
498508f6106SBharat Kumar Gogada }
499508f6106SBharat Kumar Gogada 
500508f6106SBharat Kumar Gogada /**
501508f6106SBharat Kumar Gogada  * xilinx_cpm_pcie_parse_dt - Parse Device tree
502508f6106SBharat Kumar Gogada  * @port: PCIe port information
503508f6106SBharat Kumar Gogada  * @bus_range: Bus resource
504508f6106SBharat Kumar Gogada  *
505508f6106SBharat Kumar Gogada  * Return: '0' on success and error value on failure
506508f6106SBharat Kumar Gogada  */
xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie * port,struct resource * bus_range)507dacee587SBjorn Helgaas static int xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie *port,
508508f6106SBharat Kumar Gogada 				    struct resource *bus_range)
509508f6106SBharat Kumar Gogada {
510508f6106SBharat Kumar Gogada 	struct device *dev = port->dev;
511508f6106SBharat Kumar Gogada 	struct platform_device *pdev = to_platform_device(dev);
512508f6106SBharat Kumar Gogada 	struct resource *res;
513508f6106SBharat Kumar Gogada 
514508f6106SBharat Kumar Gogada 	port->cpm_base = devm_platform_ioremap_resource_byname(pdev,
515508f6106SBharat Kumar Gogada 							       "cpm_slcr");
516508f6106SBharat Kumar Gogada 	if (IS_ERR(port->cpm_base))
517508f6106SBharat Kumar Gogada 		return PTR_ERR(port->cpm_base);
518508f6106SBharat Kumar Gogada 
519508f6106SBharat Kumar Gogada 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
520508f6106SBharat Kumar Gogada 	if (!res)
521508f6106SBharat Kumar Gogada 		return -ENXIO;
522508f6106SBharat Kumar Gogada 
523508f6106SBharat Kumar Gogada 	port->cfg = pci_ecam_create(dev, res, bus_range,
524508f6106SBharat Kumar Gogada 				    &pci_generic_ecam_ops);
525508f6106SBharat Kumar Gogada 	if (IS_ERR(port->cfg))
526508f6106SBharat Kumar Gogada 		return PTR_ERR(port->cfg);
527508f6106SBharat Kumar Gogada 
52851f1ffc0SBharat Kumar Gogada 	if (port->variant->version == CPM5) {
52951f1ffc0SBharat Kumar Gogada 		port->reg_base = devm_platform_ioremap_resource_byname(pdev,
53051f1ffc0SBharat Kumar Gogada 								    "cpm_csr");
53151f1ffc0SBharat Kumar Gogada 		if (IS_ERR(port->reg_base))
53251f1ffc0SBharat Kumar Gogada 			return PTR_ERR(port->reg_base);
53351f1ffc0SBharat Kumar Gogada 	} else {
534508f6106SBharat Kumar Gogada 		port->reg_base = port->cfg->win;
53551f1ffc0SBharat Kumar Gogada 	}
536508f6106SBharat Kumar Gogada 
537508f6106SBharat Kumar Gogada 	return 0;
538508f6106SBharat Kumar Gogada }
539508f6106SBharat Kumar Gogada 
xilinx_cpm_free_interrupts(struct xilinx_cpm_pcie * port)540dacee587SBjorn Helgaas static void xilinx_cpm_free_interrupts(struct xilinx_cpm_pcie *port)
541508f6106SBharat Kumar Gogada {
542508f6106SBharat Kumar Gogada 	irq_set_chained_handler_and_data(port->intx_irq, NULL, NULL);
543508f6106SBharat Kumar Gogada 	irq_set_chained_handler_and_data(port->irq, NULL, NULL);
544508f6106SBharat Kumar Gogada }
545508f6106SBharat Kumar Gogada 
546508f6106SBharat Kumar Gogada /**
547508f6106SBharat Kumar Gogada  * xilinx_cpm_pcie_probe - Probe function
548508f6106SBharat Kumar Gogada  * @pdev: Platform device pointer
549508f6106SBharat Kumar Gogada  *
550508f6106SBharat Kumar Gogada  * Return: '0' on success and error value on failure
551508f6106SBharat Kumar Gogada  */
xilinx_cpm_pcie_probe(struct platform_device * pdev)552508f6106SBharat Kumar Gogada static int xilinx_cpm_pcie_probe(struct platform_device *pdev)
553508f6106SBharat Kumar Gogada {
554dacee587SBjorn Helgaas 	struct xilinx_cpm_pcie *port;
555508f6106SBharat Kumar Gogada 	struct device *dev = &pdev->dev;
556508f6106SBharat Kumar Gogada 	struct pci_host_bridge *bridge;
55749e427e6SBjorn Helgaas 	struct resource_entry *bus;
558508f6106SBharat Kumar Gogada 	int err;
559508f6106SBharat Kumar Gogada 
560508f6106SBharat Kumar Gogada 	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
561508f6106SBharat Kumar Gogada 	if (!bridge)
562508f6106SBharat Kumar Gogada 		return -ENODEV;
563508f6106SBharat Kumar Gogada 
564508f6106SBharat Kumar Gogada 	port = pci_host_bridge_priv(bridge);
565508f6106SBharat Kumar Gogada 
566508f6106SBharat Kumar Gogada 	port->dev = dev;
567508f6106SBharat Kumar Gogada 
568508f6106SBharat Kumar Gogada 	err = xilinx_cpm_pcie_init_irq_domain(port);
569508f6106SBharat Kumar Gogada 	if (err)
570508f6106SBharat Kumar Gogada 		return err;
571508f6106SBharat Kumar Gogada 
57249e427e6SBjorn Helgaas 	bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
57349e427e6SBjorn Helgaas 	if (!bus)
57449e427e6SBjorn Helgaas 		return -ENODEV;
57549e427e6SBjorn Helgaas 
57651f1ffc0SBharat Kumar Gogada 	port->variant = of_device_get_match_data(dev);
57751f1ffc0SBharat Kumar Gogada 
57849e427e6SBjorn Helgaas 	err = xilinx_cpm_pcie_parse_dt(port, bus->res);
579508f6106SBharat Kumar Gogada 	if (err) {
580508f6106SBharat Kumar Gogada 		dev_err(dev, "Parsing DT failed\n");
581508f6106SBharat Kumar Gogada 		goto err_parse_dt;
582508f6106SBharat Kumar Gogada 	}
583508f6106SBharat Kumar Gogada 
584508f6106SBharat Kumar Gogada 	xilinx_cpm_pcie_init_port(port);
585508f6106SBharat Kumar Gogada 
586508f6106SBharat Kumar Gogada 	err = xilinx_cpm_setup_irq(port);
587508f6106SBharat Kumar Gogada 	if (err) {
588508f6106SBharat Kumar Gogada 		dev_err(dev, "Failed to set up interrupts\n");
589508f6106SBharat Kumar Gogada 		goto err_setup_irq;
590508f6106SBharat Kumar Gogada 	}
591508f6106SBharat Kumar Gogada 
592508f6106SBharat Kumar Gogada 	bridge->sysdata = port->cfg;
593508f6106SBharat Kumar Gogada 	bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
594508f6106SBharat Kumar Gogada 
595508f6106SBharat Kumar Gogada 	err = pci_host_probe(bridge);
596508f6106SBharat Kumar Gogada 	if (err < 0)
597508f6106SBharat Kumar Gogada 		goto err_host_bridge;
598508f6106SBharat Kumar Gogada 
599508f6106SBharat Kumar Gogada 	return 0;
600508f6106SBharat Kumar Gogada 
601508f6106SBharat Kumar Gogada err_host_bridge:
602508f6106SBharat Kumar Gogada 	xilinx_cpm_free_interrupts(port);
603508f6106SBharat Kumar Gogada err_setup_irq:
604508f6106SBharat Kumar Gogada 	pci_ecam_free(port->cfg);
605508f6106SBharat Kumar Gogada err_parse_dt:
606508f6106SBharat Kumar Gogada 	xilinx_cpm_free_irq_domains(port);
607508f6106SBharat Kumar Gogada 	return err;
608508f6106SBharat Kumar Gogada }
609508f6106SBharat Kumar Gogada 
61051f1ffc0SBharat Kumar Gogada static const struct xilinx_cpm_variant cpm_host = {
61151f1ffc0SBharat Kumar Gogada 	.version = CPM,
61251f1ffc0SBharat Kumar Gogada };
61351f1ffc0SBharat Kumar Gogada 
61451f1ffc0SBharat Kumar Gogada static const struct xilinx_cpm_variant cpm5_host = {
61551f1ffc0SBharat Kumar Gogada 	.version = CPM5,
61651f1ffc0SBharat Kumar Gogada };
61751f1ffc0SBharat Kumar Gogada 
618508f6106SBharat Kumar Gogada static const struct of_device_id xilinx_cpm_pcie_of_match[] = {
61951f1ffc0SBharat Kumar Gogada 	{
62051f1ffc0SBharat Kumar Gogada 		.compatible = "xlnx,versal-cpm-host-1.00",
62151f1ffc0SBharat Kumar Gogada 		.data = &cpm_host,
62251f1ffc0SBharat Kumar Gogada 	},
62351f1ffc0SBharat Kumar Gogada 	{
62451f1ffc0SBharat Kumar Gogada 		.compatible = "xlnx,versal-cpm5-host",
62551f1ffc0SBharat Kumar Gogada 		.data = &cpm5_host,
62651f1ffc0SBharat Kumar Gogada 	},
627508f6106SBharat Kumar Gogada 	{}
628508f6106SBharat Kumar Gogada };
629508f6106SBharat Kumar Gogada 
630508f6106SBharat Kumar Gogada static struct platform_driver xilinx_cpm_pcie_driver = {
631508f6106SBharat Kumar Gogada 	.driver = {
632508f6106SBharat Kumar Gogada 		.name = "xilinx-cpm-pcie",
633508f6106SBharat Kumar Gogada 		.of_match_table = xilinx_cpm_pcie_of_match,
634508f6106SBharat Kumar Gogada 		.suppress_bind_attrs = true,
635508f6106SBharat Kumar Gogada 	},
636508f6106SBharat Kumar Gogada 	.probe = xilinx_cpm_pcie_probe,
637508f6106SBharat Kumar Gogada };
638508f6106SBharat Kumar Gogada 
639508f6106SBharat Kumar Gogada builtin_platform_driver(xilinx_cpm_pcie_driver);
640