xref: /linux/drivers/pci/controller/pcie-aspeed.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*9aa0cb68SJacky Chou // SPDX-License-Identifier: GPL-2.0+
2*9aa0cb68SJacky Chou /*
3*9aa0cb68SJacky Chou  * Copyright 2025 Aspeed Technology Inc.
4*9aa0cb68SJacky Chou  */
5*9aa0cb68SJacky Chou #include <linux/bitfield.h>
6*9aa0cb68SJacky Chou #include <linux/clk.h>
7*9aa0cb68SJacky Chou #include <linux/interrupt.h>
8*9aa0cb68SJacky Chou #include <linux/irq.h>
9*9aa0cb68SJacky Chou #include <linux/irqdomain.h>
10*9aa0cb68SJacky Chou #include <linux/irqchip/chained_irq.h>
11*9aa0cb68SJacky Chou #include <linux/irqchip/irq-msi-lib.h>
12*9aa0cb68SJacky Chou #include <linux/kernel.h>
13*9aa0cb68SJacky Chou #include <linux/mfd/syscon.h>
14*9aa0cb68SJacky Chou #include <linux/module.h>
15*9aa0cb68SJacky Chou #include <linux/msi.h>
16*9aa0cb68SJacky Chou #include <linux/mutex.h>
17*9aa0cb68SJacky Chou #include <linux/of.h>
18*9aa0cb68SJacky Chou #include <linux/of_address.h>
19*9aa0cb68SJacky Chou #include <linux/of_pci.h>
20*9aa0cb68SJacky Chou #include <linux/pci.h>
21*9aa0cb68SJacky Chou #include <linux/platform_device.h>
22*9aa0cb68SJacky Chou #include <linux/phy/pcie.h>
23*9aa0cb68SJacky Chou #include <linux/phy/phy.h>
24*9aa0cb68SJacky Chou #include <linux/regmap.h>
25*9aa0cb68SJacky Chou #include <linux/reset.h>
26*9aa0cb68SJacky Chou 
27*9aa0cb68SJacky Chou #include "../pci.h"
28*9aa0cb68SJacky Chou 
29*9aa0cb68SJacky Chou #define MAX_MSI_HOST_IRQS	64
30*9aa0cb68SJacky Chou #define ASPEED_RESET_RC_WAIT_MS	10
31*9aa0cb68SJacky Chou 
32*9aa0cb68SJacky Chou /* AST2600 AHBC Registers */
33*9aa0cb68SJacky Chou #define ASPEED_AHBC_KEY			0x00
34*9aa0cb68SJacky Chou #define  ASPEED_AHBC_UNLOCK_KEY			0xaeed1a03
35*9aa0cb68SJacky Chou #define  ASPEED_AHBC_UNLOCK			0x01
36*9aa0cb68SJacky Chou #define ASPEED_AHBC_ADDR_MAPPING	0x8c
37*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RC_MEMORY_EN		BIT(5)
38*9aa0cb68SJacky Chou 
39*9aa0cb68SJacky Chou /* AST2600 H2X Controller Registers */
40*9aa0cb68SJacky Chou #define ASPEED_H2X_INT_STS		0x08
41*9aa0cb68SJacky Chou #define  ASPEED_PCIE_TX_IDLE_CLEAR		BIT(0)
42*9aa0cb68SJacky Chou #define  ASPEED_PCIE_INTX_STS			GENMASK(3, 0)
43*9aa0cb68SJacky Chou #define ASPEED_H2X_HOST_RX_DESC_DATA	0x0c
44*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC0		0x10
45*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC1		0x14
46*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC2		0x18
47*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC3		0x1c
48*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC_DATA		0x20
49*9aa0cb68SJacky Chou #define ASPEED_H2X_STS			0x24
50*9aa0cb68SJacky Chou #define  ASPEED_PCIE_TX_IDLE			BIT(31)
51*9aa0cb68SJacky Chou #define  ASPEED_PCIE_STATUS_OF_TX		GENMASK(25, 24)
52*9aa0cb68SJacky Chou #define	ASPEED_PCIE_RC_H_TX_COMPLETE		BIT(25)
53*9aa0cb68SJacky Chou #define  ASPEED_PCIE_TRIGGER_TX			BIT(0)
54*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG0	0x60
55*9aa0cb68SJacky Chou #define  ASPEED_AHB_REMAP_LO_ADDR(x)		(x & GENMASK(15, 4))
56*9aa0cb68SJacky Chou #define  ASPEED_AHB_MASK_LO_ADDR(x)		FIELD_PREP(GENMASK(31, 20), x)
57*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG1	0x64
58*9aa0cb68SJacky Chou #define  ASPEED_AHB_REMAP_HI_ADDR(x)		(x)
59*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG2	0x68
60*9aa0cb68SJacky Chou #define  ASPEED_AHB_MASK_HI_ADDR(x)		(x)
61*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_CTRL		0xc0
62*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RX_DMA_EN			BIT(9)
63*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RX_LINEAR			BIT(8)
64*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RX_MSI_SEL			BIT(7)
65*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RX_MSI_EN			BIT(6)
66*9aa0cb68SJacky Chou #define  ASPEED_PCIE_UNLOCK_RX_BUFF		BIT(4)
67*9aa0cb68SJacky Chou #define  ASPEED_PCIE_WAIT_RX_TLP_CLR		BIT(2)
68*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RC_RX_ENABLE		BIT(1)
69*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RC_ENABLE			BIT(0)
70*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_STS		0xc8
71*9aa0cb68SJacky Chou #define  ASPEED_PCIE_RC_RX_DONE_ISR		BIT(4)
72*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_RX_DESC_DATA	0xcc
73*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_RX_DESC1		0xd4
74*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_TX_TAG		0xfc
75*9aa0cb68SJacky Chou #define  ASPEED_RC_TLP_TX_TAG_NUM		0x28
76*9aa0cb68SJacky Chou 
77*9aa0cb68SJacky Chou /* AST2700 H2X */
78*9aa0cb68SJacky Chou #define ASPEED_H2X_CTRL			0x00
79*9aa0cb68SJacky Chou #define  ASPEED_H2X_BRIDGE_EN			BIT(0)
80*9aa0cb68SJacky Chou #define  ASPEED_H2X_BRIDGE_DIRECT_EN		BIT(1)
81*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_INT_STS		0x08
82*9aa0cb68SJacky Chou #define  ASPEED_CFGE_TX_IDLE			BIT(0)
83*9aa0cb68SJacky Chou #define  ASPEED_CFGE_RX_BUSY			BIT(1)
84*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_TLP		0x20
85*9aa0cb68SJacky Chou #define  ASPEED_CFGI_BYTE_EN_MASK		GENMASK(19, 16)
86*9aa0cb68SJacky Chou #define  ASPEED_CFGI_BYTE_EN(x) \
87*9aa0cb68SJacky Chou 		FIELD_PREP(ASPEED_CFGI_BYTE_EN_MASK, (x))
88*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_WR_DATA		0x24
89*9aa0cb68SJacky Chou #define  ASPEED_CFGI_WRITE			BIT(20)
90*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_CTRL		0x28
91*9aa0cb68SJacky Chou #define  ASPEED_CFGI_TLP_FIRE			BIT(0)
92*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_RET_DATA	0x2c
93*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_TLP_1ST		0x30
94*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_TLP_NEXT	0x34
95*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_CTRL		0x38
96*9aa0cb68SJacky Chou #define  ASPEED_CFGE_TLP_FIRE			BIT(0)
97*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_RET_DATA	0x3c
98*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PREF_ADDR	0x70
99*9aa0cb68SJacky Chou #define  ASPEED_REMAP_PREF_ADDR_63_32(x)	(x)
100*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PCI_ADDR_HI	0x74
101*9aa0cb68SJacky Chou #define  ASPEED_REMAP_PCI_ADDR_63_32(x)		(((x) >> 32) & GENMASK(31, 0))
102*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PCI_ADDR_LO	0x78
103*9aa0cb68SJacky Chou #define  ASPEED_REMAP_PCI_ADDR_31_12(x)		((x) & GENMASK(31, 12))
104*9aa0cb68SJacky Chou 
105*9aa0cb68SJacky Chou /* AST2700 SCU */
106*9aa0cb68SJacky Chou #define ASPEED_SCU_60			0x60
107*9aa0cb68SJacky Chou #define  ASPEED_RC_E2M_PATH_EN			BIT(0)
108*9aa0cb68SJacky Chou #define  ASPEED_RC_H2XS_PATH_EN			BIT(16)
109*9aa0cb68SJacky Chou #define  ASPEED_RC_H2XD_PATH_EN			BIT(17)
110*9aa0cb68SJacky Chou #define  ASPEED_RC_H2XX_PATH_EN			BIT(18)
111*9aa0cb68SJacky Chou #define  ASPEED_RC_UPSTREAM_MEM_EN		BIT(19)
112*9aa0cb68SJacky Chou #define ASPEED_SCU_64			0x64
113*9aa0cb68SJacky Chou #define  ASPEED_RC0_DECODE_DMA_BASE(x)		FIELD_PREP(GENMASK(7, 0), x)
114*9aa0cb68SJacky Chou #define  ASPEED_RC0_DECODE_DMA_LIMIT(x)		FIELD_PREP(GENMASK(15, 8), x)
115*9aa0cb68SJacky Chou #define  ASPEED_RC1_DECODE_DMA_BASE(x)		FIELD_PREP(GENMASK(23, 16), x)
116*9aa0cb68SJacky Chou #define  ASPEED_RC1_DECODE_DMA_LIMIT(x)		FIELD_PREP(GENMASK(31, 24), x)
117*9aa0cb68SJacky Chou #define ASPEED_SCU_70			0x70
118*9aa0cb68SJacky Chou #define  ASPEED_DISABLE_EP_FUNC			0
119*9aa0cb68SJacky Chou 
120*9aa0cb68SJacky Chou /* Macro to combine Fmt and Type into the 8-bit field */
121*9aa0cb68SJacky Chou #define ASPEED_TLP_FMT_TYPE(fmt, type)	((((fmt) & 0x7) << 5) | ((type) & 0x1f))
122*9aa0cb68SJacky Chou #define ASPEED_TLP_COMMON_FIELDS	GENMASK(31, 24)
123*9aa0cb68SJacky Chou 
124*9aa0cb68SJacky Chou /* Completion status */
125*9aa0cb68SJacky Chou #define CPL_STS(x)	FIELD_GET(GENMASK(15, 13), (x))
126*9aa0cb68SJacky Chou /* TLP configuration type 0 and type 1 */
127*9aa0cb68SJacky Chou #define CFG0_READ_FMTTYPE                                        \
128*9aa0cb68SJacky Chou 	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                     \
129*9aa0cb68SJacky Chou 		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \
130*9aa0cb68SJacky Chou 				       PCIE_TLP_TYPE_CFG0_RD))
131*9aa0cb68SJacky Chou #define CFG0_WRITE_FMTTYPE                                    \
132*9aa0cb68SJacky Chou 	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                  \
133*9aa0cb68SJacky Chou 		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \
134*9aa0cb68SJacky Chou 				       PCIE_TLP_TYPE_CFG0_WR))
135*9aa0cb68SJacky Chou #define CFG1_READ_FMTTYPE                                        \
136*9aa0cb68SJacky Chou 	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                     \
137*9aa0cb68SJacky Chou 		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \
138*9aa0cb68SJacky Chou 				       PCIE_TLP_TYPE_CFG1_RD))
139*9aa0cb68SJacky Chou #define CFG1_WRITE_FMTTYPE                                    \
140*9aa0cb68SJacky Chou 	FIELD_PREP(ASPEED_TLP_COMMON_FIELDS,                  \
141*9aa0cb68SJacky Chou 		   ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \
142*9aa0cb68SJacky Chou 				       PCIE_TLP_TYPE_CFG1_WR))
143*9aa0cb68SJacky Chou #define CFG_PAYLOAD_SIZE		0x01 /* 1 DWORD */
144*9aa0cb68SJacky Chou #define TLP_HEADER_BYTE_EN(x, y)	((GENMASK((x) - 1, 0) << ((y) % 4)))
145*9aa0cb68SJacky Chou #define TLP_GET_VALUE(x, y, z)	\
146*9aa0cb68SJacky Chou 	(((x) >> ((((z) % 4)) * 8)) & GENMASK((8 * (y)) - 1, 0))
147*9aa0cb68SJacky Chou #define TLP_SET_VALUE(x, y, z)	\
148*9aa0cb68SJacky Chou 	((((x) & GENMASK((8 * (y)) - 1, 0)) << ((((z) % 4)) * 8)))
149*9aa0cb68SJacky Chou #define AST2600_TX_DESC1_VALUE		0x00002000
150*9aa0cb68SJacky Chou #define AST2700_TX_DESC1_VALUE		0x00401000
151*9aa0cb68SJacky Chou 
152*9aa0cb68SJacky Chou /**
153*9aa0cb68SJacky Chou  * struct aspeed_pcie_port - PCIe port information
154*9aa0cb68SJacky Chou  * @list: port list
155*9aa0cb68SJacky Chou  * @pcie: pointer to PCIe host info
156*9aa0cb68SJacky Chou  * @clk: pointer to the port clock gate
157*9aa0cb68SJacky Chou  * @phy: pointer to PCIe PHY
158*9aa0cb68SJacky Chou  * @perst: pointer to port reset control
159*9aa0cb68SJacky Chou  * @slot: port slot
160*9aa0cb68SJacky Chou  */
161*9aa0cb68SJacky Chou struct aspeed_pcie_port {
162*9aa0cb68SJacky Chou 	struct list_head list;
163*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie;
164*9aa0cb68SJacky Chou 	struct clk *clk;
165*9aa0cb68SJacky Chou 	struct phy *phy;
166*9aa0cb68SJacky Chou 	struct reset_control *perst;
167*9aa0cb68SJacky Chou 	u32 slot;
168*9aa0cb68SJacky Chou };
169*9aa0cb68SJacky Chou 
170*9aa0cb68SJacky Chou /**
171*9aa0cb68SJacky Chou  * struct aspeed_pcie - PCIe RC information
172*9aa0cb68SJacky Chou  * @host: pointer to PCIe host bridge
173*9aa0cb68SJacky Chou  * @dev: pointer to device structure
174*9aa0cb68SJacky Chou  * @reg: PCIe host register base address
175*9aa0cb68SJacky Chou  * @ahbc: pointer to AHHC register map
176*9aa0cb68SJacky Chou  * @cfg: pointer to Aspeed PCIe configuration register map
177*9aa0cb68SJacky Chou  * @platform: platform specific information
178*9aa0cb68SJacky Chou  * @ports: list of PCIe ports
179*9aa0cb68SJacky Chou  * @tx_tag: current TX tag for the port
180*9aa0cb68SJacky Chou  * @root_bus_nr: bus number of the host bridge
181*9aa0cb68SJacky Chou  * @h2xrst: pointer to H2X reset control
182*9aa0cb68SJacky Chou  * @intx_domain: IRQ domain for INTx interrupts
183*9aa0cb68SJacky Chou  * @msi_domain: IRQ domain for MSI interrupts
184*9aa0cb68SJacky Chou  * @lock: mutex to protect MSI bitmap variable
185*9aa0cb68SJacky Chou  * @msi_irq_in_use: bitmap to track used MSI host IRQs
186*9aa0cb68SJacky Chou  * @clear_msi_twice: AST2700 workaround to clear MSI status twice
187*9aa0cb68SJacky Chou  */
188*9aa0cb68SJacky Chou struct aspeed_pcie {
189*9aa0cb68SJacky Chou 	struct pci_host_bridge *host;
190*9aa0cb68SJacky Chou 	struct device *dev;
191*9aa0cb68SJacky Chou 	void __iomem *reg;
192*9aa0cb68SJacky Chou 	struct regmap *ahbc;
193*9aa0cb68SJacky Chou 	struct regmap *cfg;
194*9aa0cb68SJacky Chou 	const struct aspeed_pcie_rc_platform *platform;
195*9aa0cb68SJacky Chou 	struct list_head ports;
196*9aa0cb68SJacky Chou 
197*9aa0cb68SJacky Chou 	u8 tx_tag;
198*9aa0cb68SJacky Chou 	u8 root_bus_nr;
199*9aa0cb68SJacky Chou 
200*9aa0cb68SJacky Chou 	struct reset_control *h2xrst;
201*9aa0cb68SJacky Chou 
202*9aa0cb68SJacky Chou 	struct irq_domain *intx_domain;
203*9aa0cb68SJacky Chou 	struct irq_domain *msi_domain;
204*9aa0cb68SJacky Chou 	struct mutex lock;
205*9aa0cb68SJacky Chou 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS);
206*9aa0cb68SJacky Chou 
207*9aa0cb68SJacky Chou 	bool clear_msi_twice;		/* AST2700 workaround */
208*9aa0cb68SJacky Chou };
209*9aa0cb68SJacky Chou 
210*9aa0cb68SJacky Chou /**
211*9aa0cb68SJacky Chou  * struct aspeed_pcie_rc_platform - Platform information
212*9aa0cb68SJacky Chou  * @setup: initialization function
213*9aa0cb68SJacky Chou  * @pcie_map_ranges: function to map PCIe address ranges
214*9aa0cb68SJacky Chou  * @reg_intx_en: INTx enable register offset
215*9aa0cb68SJacky Chou  * @reg_intx_sts: INTx status register offset
216*9aa0cb68SJacky Chou  * @reg_msi_en: MSI enable register offset
217*9aa0cb68SJacky Chou  * @reg_msi_sts: MSI enable register offset
218*9aa0cb68SJacky Chou  * @msi_address: HW fixed MSI address
219*9aa0cb68SJacky Chou  */
220*9aa0cb68SJacky Chou struct aspeed_pcie_rc_platform {
221*9aa0cb68SJacky Chou 	int (*setup)(struct platform_device *pdev);
222*9aa0cb68SJacky Chou 	void (*pcie_map_ranges)(struct aspeed_pcie *pcie, u64 pci_addr);
223*9aa0cb68SJacky Chou 	int reg_intx_en;
224*9aa0cb68SJacky Chou 	int reg_intx_sts;
225*9aa0cb68SJacky Chou 	int reg_msi_en;
226*9aa0cb68SJacky Chou 	int reg_msi_sts;
227*9aa0cb68SJacky Chou 	u32 msi_address;
228*9aa0cb68SJacky Chou };
229*9aa0cb68SJacky Chou 
230*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_ack(struct irq_data *d)
231*9aa0cb68SJacky Chou {
232*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
233*9aa0cb68SJacky Chou 	int intx_en = pcie->platform->reg_intx_en;
234*9aa0cb68SJacky Chou 	u32 en;
235*9aa0cb68SJacky Chou 
236*9aa0cb68SJacky Chou 	en = readl(pcie->reg + intx_en);
237*9aa0cb68SJacky Chou 	en |= BIT(d->hwirq);
238*9aa0cb68SJacky Chou 	writel(en, pcie->reg + intx_en);
239*9aa0cb68SJacky Chou }
240*9aa0cb68SJacky Chou 
241*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_mask(struct irq_data *d)
242*9aa0cb68SJacky Chou {
243*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
244*9aa0cb68SJacky Chou 	int intx_en = pcie->platform->reg_intx_en;
245*9aa0cb68SJacky Chou 	u32 en;
246*9aa0cb68SJacky Chou 
247*9aa0cb68SJacky Chou 	en = readl(pcie->reg + intx_en);
248*9aa0cb68SJacky Chou 	en &= ~BIT(d->hwirq);
249*9aa0cb68SJacky Chou 	writel(en, pcie->reg + intx_en);
250*9aa0cb68SJacky Chou }
251*9aa0cb68SJacky Chou 
252*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_unmask(struct irq_data *d)
253*9aa0cb68SJacky Chou {
254*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d);
255*9aa0cb68SJacky Chou 	int intx_en = pcie->platform->reg_intx_en;
256*9aa0cb68SJacky Chou 	u32 en;
257*9aa0cb68SJacky Chou 
258*9aa0cb68SJacky Chou 	en = readl(pcie->reg + intx_en);
259*9aa0cb68SJacky Chou 	en |= BIT(d->hwirq);
260*9aa0cb68SJacky Chou 	writel(en, pcie->reg + intx_en);
261*9aa0cb68SJacky Chou }
262*9aa0cb68SJacky Chou 
263*9aa0cb68SJacky Chou static struct irq_chip aspeed_intx_irq_chip = {
264*9aa0cb68SJacky Chou 	.name = "INTx",
265*9aa0cb68SJacky Chou 	.irq_ack = aspeed_pcie_intx_irq_ack,
266*9aa0cb68SJacky Chou 	.irq_mask = aspeed_pcie_intx_irq_mask,
267*9aa0cb68SJacky Chou 	.irq_unmask = aspeed_pcie_intx_irq_unmask,
268*9aa0cb68SJacky Chou };
269*9aa0cb68SJacky Chou 
270*9aa0cb68SJacky Chou static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
271*9aa0cb68SJacky Chou 				irq_hw_number_t hwirq)
272*9aa0cb68SJacky Chou {
273*9aa0cb68SJacky Chou 	irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq);
274*9aa0cb68SJacky Chou 	irq_set_chip_data(irq, domain->host_data);
275*9aa0cb68SJacky Chou 	irq_set_status_flags(irq, IRQ_LEVEL);
276*9aa0cb68SJacky Chou 
277*9aa0cb68SJacky Chou 	return 0;
278*9aa0cb68SJacky Chou }
279*9aa0cb68SJacky Chou 
280*9aa0cb68SJacky Chou static const struct irq_domain_ops aspeed_intx_domain_ops = {
281*9aa0cb68SJacky Chou 	.map = aspeed_pcie_intx_map,
282*9aa0cb68SJacky Chou };
283*9aa0cb68SJacky Chou 
284*9aa0cb68SJacky Chou static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id)
285*9aa0cb68SJacky Chou {
286*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = dev_id;
287*9aa0cb68SJacky Chou 	const struct aspeed_pcie_rc_platform *platform = pcie->platform;
288*9aa0cb68SJacky Chou 	unsigned long status;
289*9aa0cb68SJacky Chou 	unsigned long intx;
290*9aa0cb68SJacky Chou 	u32 bit;
291*9aa0cb68SJacky Chou 	int i;
292*9aa0cb68SJacky Chou 
293*9aa0cb68SJacky Chou 	intx = FIELD_GET(ASPEED_PCIE_INTX_STS,
294*9aa0cb68SJacky Chou 			 readl(pcie->reg + platform->reg_intx_sts));
295*9aa0cb68SJacky Chou 	for_each_set_bit(bit, &intx, PCI_NUM_INTX)
296*9aa0cb68SJacky Chou 		generic_handle_domain_irq(pcie->intx_domain, bit);
297*9aa0cb68SJacky Chou 
298*9aa0cb68SJacky Chou 	for (i = 0; i < 2; i++) {
299*9aa0cb68SJacky Chou 		int msi_sts_reg = platform->reg_msi_sts + (i * 4);
300*9aa0cb68SJacky Chou 
301*9aa0cb68SJacky Chou 		status = readl(pcie->reg + msi_sts_reg);
302*9aa0cb68SJacky Chou 		writel(status, pcie->reg + msi_sts_reg);
303*9aa0cb68SJacky Chou 
304*9aa0cb68SJacky Chou 		/*
305*9aa0cb68SJacky Chou 		 * AST2700 workaround:
306*9aa0cb68SJacky Chou 		 * The MSI status needs to clear one more time.
307*9aa0cb68SJacky Chou 		 */
308*9aa0cb68SJacky Chou 		if (pcie->clear_msi_twice)
309*9aa0cb68SJacky Chou 			writel(status, pcie->reg + msi_sts_reg);
310*9aa0cb68SJacky Chou 
311*9aa0cb68SJacky Chou 		for_each_set_bit(bit, &status, 32) {
312*9aa0cb68SJacky Chou 			bit += (i * 32);
313*9aa0cb68SJacky Chou 			generic_handle_domain_irq(pcie->msi_domain, bit);
314*9aa0cb68SJacky Chou 		}
315*9aa0cb68SJacky Chou 	}
316*9aa0cb68SJacky Chou 
317*9aa0cb68SJacky Chou 	return IRQ_HANDLED;
318*9aa0cb68SJacky Chou }
319*9aa0cb68SJacky Chou 
320*9aa0cb68SJacky Chou static u32 aspeed_pcie_get_bdf_offset(struct pci_bus *bus, unsigned int devfn,
321*9aa0cb68SJacky Chou 				      int where)
322*9aa0cb68SJacky Chou {
323*9aa0cb68SJacky Chou 	return ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) |
324*9aa0cb68SJacky Chou 		(PCI_FUNC(devfn) << 16) | (where & ~3);
325*9aa0cb68SJacky Chou }
326*9aa0cb68SJacky Chou 
327*9aa0cb68SJacky Chou static int aspeed_ast2600_conf(struct pci_bus *bus, unsigned int devfn,
328*9aa0cb68SJacky Chou 			       int where, int size, u32 *val, u32 fmt_type,
329*9aa0cb68SJacky Chou 			       bool write)
330*9aa0cb68SJacky Chou {
331*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = bus->sysdata;
332*9aa0cb68SJacky Chou 	u32 bdf_offset, cfg_val, isr;
333*9aa0cb68SJacky Chou 	int ret;
334*9aa0cb68SJacky Chou 
335*9aa0cb68SJacky Chou 	bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where);
336*9aa0cb68SJacky Chou 
337*9aa0cb68SJacky Chou 	/* Driver may set unlock RX buffer before triggering next TX config */
338*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL);
339*9aa0cb68SJacky Chou 	writel(ASPEED_PCIE_UNLOCK_RX_BUFF | cfg_val,
340*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_DEV_CTRL);
341*9aa0cb68SJacky Chou 
342*9aa0cb68SJacky Chou 	cfg_val = fmt_type | CFG_PAYLOAD_SIZE;
343*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC0);
344*9aa0cb68SJacky Chou 
345*9aa0cb68SJacky Chou 	cfg_val = AST2600_TX_DESC1_VALUE |
346*9aa0cb68SJacky Chou 		  FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) |
347*9aa0cb68SJacky Chou 		  TLP_HEADER_BYTE_EN(size, where);
348*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC1);
349*9aa0cb68SJacky Chou 
350*9aa0cb68SJacky Chou 	writel(bdf_offset, pcie->reg + ASPEED_H2X_TX_DESC2);
351*9aa0cb68SJacky Chou 	writel(0, pcie->reg + ASPEED_H2X_TX_DESC3);
352*9aa0cb68SJacky Chou 	if (write)
353*9aa0cb68SJacky Chou 		writel(TLP_SET_VALUE(*val, size, where),
354*9aa0cb68SJacky Chou 		       pcie->reg + ASPEED_H2X_TX_DESC_DATA);
355*9aa0cb68SJacky Chou 
356*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_STS);
357*9aa0cb68SJacky Chou 	cfg_val |= ASPEED_PCIE_TRIGGER_TX;
358*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_STS);
359*9aa0cb68SJacky Chou 
360*9aa0cb68SJacky Chou 	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_STS, cfg_val,
361*9aa0cb68SJacky Chou 				 (cfg_val & ASPEED_PCIE_TX_IDLE), 0, 50);
362*9aa0cb68SJacky Chou 	if (ret) {
363*9aa0cb68SJacky Chou 		dev_err(pcie->dev,
364*9aa0cb68SJacky Chou 			"%02x:%02x.%d CR tx timeout sts: 0x%08x\n",
365*9aa0cb68SJacky Chou 			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), cfg_val);
366*9aa0cb68SJacky Chou 		ret = PCIBIOS_SET_FAILED;
367*9aa0cb68SJacky Chou 		PCI_SET_ERROR_RESPONSE(val);
368*9aa0cb68SJacky Chou 		goto out;
369*9aa0cb68SJacky Chou 	}
370*9aa0cb68SJacky Chou 
371*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_INT_STS);
372*9aa0cb68SJacky Chou 	cfg_val |= ASPEED_PCIE_TX_IDLE_CLEAR;
373*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_INT_STS);
374*9aa0cb68SJacky Chou 
375*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_STS);
376*9aa0cb68SJacky Chou 	switch (cfg_val & ASPEED_PCIE_STATUS_OF_TX) {
377*9aa0cb68SJacky Chou 	case ASPEED_PCIE_RC_H_TX_COMPLETE:
378*9aa0cb68SJacky Chou 		ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_DEV_STS, isr,
379*9aa0cb68SJacky Chou 					 (isr & ASPEED_PCIE_RC_RX_DONE_ISR), 0,
380*9aa0cb68SJacky Chou 					 50);
381*9aa0cb68SJacky Chou 		if (ret) {
382*9aa0cb68SJacky Chou 			dev_err(pcie->dev,
383*9aa0cb68SJacky Chou 				"%02x:%02x.%d CR rx timeout sts: 0x%08x\n",
384*9aa0cb68SJacky Chou 				bus->number, PCI_SLOT(devfn),
385*9aa0cb68SJacky Chou 				PCI_FUNC(devfn), isr);
386*9aa0cb68SJacky Chou 			ret = PCIBIOS_SET_FAILED;
387*9aa0cb68SJacky Chou 			PCI_SET_ERROR_RESPONSE(val);
388*9aa0cb68SJacky Chou 			goto out;
389*9aa0cb68SJacky Chou 		}
390*9aa0cb68SJacky Chou 		if (!write) {
391*9aa0cb68SJacky Chou 			cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_RX_DESC1);
392*9aa0cb68SJacky Chou 			if (CPL_STS(cfg_val) != PCIE_CPL_STS_SUCCESS) {
393*9aa0cb68SJacky Chou 				ret = PCIBIOS_SET_FAILED;
394*9aa0cb68SJacky Chou 				PCI_SET_ERROR_RESPONSE(val);
395*9aa0cb68SJacky Chou 				goto out;
396*9aa0cb68SJacky Chou 			} else {
397*9aa0cb68SJacky Chou 				*val = readl(pcie->reg +
398*9aa0cb68SJacky Chou 					     ASPEED_H2X_DEV_RX_DESC_DATA);
399*9aa0cb68SJacky Chou 			}
400*9aa0cb68SJacky Chou 		}
401*9aa0cb68SJacky Chou 		break;
402*9aa0cb68SJacky Chou 	case ASPEED_PCIE_STATUS_OF_TX:
403*9aa0cb68SJacky Chou 		ret = PCIBIOS_SET_FAILED;
404*9aa0cb68SJacky Chou 		PCI_SET_ERROR_RESPONSE(val);
405*9aa0cb68SJacky Chou 		goto out;
406*9aa0cb68SJacky Chou 	default:
407*9aa0cb68SJacky Chou 		*val = readl(pcie->reg + ASPEED_H2X_HOST_RX_DESC_DATA);
408*9aa0cb68SJacky Chou 		break;
409*9aa0cb68SJacky Chou 	}
410*9aa0cb68SJacky Chou 
411*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL);
412*9aa0cb68SJacky Chou 	cfg_val |= ASPEED_PCIE_UNLOCK_RX_BUFF;
413*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_CTRL);
414*9aa0cb68SJacky Chou 
415*9aa0cb68SJacky Chou 	*val = TLP_GET_VALUE(*val, size, where);
416*9aa0cb68SJacky Chou 
417*9aa0cb68SJacky Chou 	ret = PCIBIOS_SUCCESSFUL;
418*9aa0cb68SJacky Chou out:
419*9aa0cb68SJacky Chou 	cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_STS);
420*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_STS);
421*9aa0cb68SJacky Chou 	pcie->tx_tag = (pcie->tx_tag + 1) % 0x8;
422*9aa0cb68SJacky Chou 	return ret;
423*9aa0cb68SJacky Chou }
424*9aa0cb68SJacky Chou 
425*9aa0cb68SJacky Chou static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn,
426*9aa0cb68SJacky Chou 				  int where, int size, u32 *val)
427*9aa0cb68SJacky Chou {
428*9aa0cb68SJacky Chou 	/*
429*9aa0cb68SJacky Chou 	 * AST2600 has only one Root Port on the root bus.
430*9aa0cb68SJacky Chou 	 */
431*9aa0cb68SJacky Chou 	if (PCI_SLOT(devfn) != 8)
432*9aa0cb68SJacky Chou 		return PCIBIOS_DEVICE_NOT_FOUND;
433*9aa0cb68SJacky Chou 
434*9aa0cb68SJacky Chou 	return aspeed_ast2600_conf(bus, devfn, where, size, val,
435*9aa0cb68SJacky Chou 				   CFG0_READ_FMTTYPE, false);
436*9aa0cb68SJacky Chou }
437*9aa0cb68SJacky Chou 
438*9aa0cb68SJacky Chou static int aspeed_ast2600_child_rd_conf(struct pci_bus *bus, unsigned int devfn,
439*9aa0cb68SJacky Chou 					int where, int size, u32 *val)
440*9aa0cb68SJacky Chou {
441*9aa0cb68SJacky Chou 	return aspeed_ast2600_conf(bus, devfn, where, size, val,
442*9aa0cb68SJacky Chou 				   CFG1_READ_FMTTYPE, false);
443*9aa0cb68SJacky Chou }
444*9aa0cb68SJacky Chou 
445*9aa0cb68SJacky Chou static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn,
446*9aa0cb68SJacky Chou 				  int where, int size, u32 val)
447*9aa0cb68SJacky Chou {
448*9aa0cb68SJacky Chou 	/*
449*9aa0cb68SJacky Chou 	 * AST2600 has only one Root Port on the root bus.
450*9aa0cb68SJacky Chou 	 */
451*9aa0cb68SJacky Chou 	if (PCI_SLOT(devfn) != 8)
452*9aa0cb68SJacky Chou 		return PCIBIOS_DEVICE_NOT_FOUND;
453*9aa0cb68SJacky Chou 
454*9aa0cb68SJacky Chou 	return aspeed_ast2600_conf(bus, devfn, where, size, &val,
455*9aa0cb68SJacky Chou 				   CFG0_WRITE_FMTTYPE, true);
456*9aa0cb68SJacky Chou }
457*9aa0cb68SJacky Chou 
458*9aa0cb68SJacky Chou static int aspeed_ast2600_child_wr_conf(struct pci_bus *bus, unsigned int devfn,
459*9aa0cb68SJacky Chou 					int where, int size, u32 val)
460*9aa0cb68SJacky Chou {
461*9aa0cb68SJacky Chou 	return aspeed_ast2600_conf(bus, devfn, where, size, &val,
462*9aa0cb68SJacky Chou 				   CFG1_WRITE_FMTTYPE, true);
463*9aa0cb68SJacky Chou }
464*9aa0cb68SJacky Chou 
465*9aa0cb68SJacky Chou static int aspeed_ast2700_config(struct pci_bus *bus, unsigned int devfn,
466*9aa0cb68SJacky Chou 				 int where, int size, u32 *val, bool write)
467*9aa0cb68SJacky Chou {
468*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = bus->sysdata;
469*9aa0cb68SJacky Chou 	u32 cfg_val;
470*9aa0cb68SJacky Chou 
471*9aa0cb68SJacky Chou 	cfg_val = ASPEED_CFGI_BYTE_EN(TLP_HEADER_BYTE_EN(size, where)) |
472*9aa0cb68SJacky Chou 		  (where & ~3);
473*9aa0cb68SJacky Chou 	if (write)
474*9aa0cb68SJacky Chou 		cfg_val |= ASPEED_CFGI_WRITE;
475*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGI_TLP);
476*9aa0cb68SJacky Chou 
477*9aa0cb68SJacky Chou 	writel(TLP_SET_VALUE(*val, size, where),
478*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_CFGI_WR_DATA);
479*9aa0cb68SJacky Chou 	writel(ASPEED_CFGI_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGI_CTRL);
480*9aa0cb68SJacky Chou 	*val = readl(pcie->reg + ASPEED_H2X_CFGI_RET_DATA);
481*9aa0cb68SJacky Chou 	*val = TLP_GET_VALUE(*val, size, where);
482*9aa0cb68SJacky Chou 
483*9aa0cb68SJacky Chou 	return PCIBIOS_SUCCESSFUL;
484*9aa0cb68SJacky Chou }
485*9aa0cb68SJacky Chou 
486*9aa0cb68SJacky Chou static int aspeed_ast2700_child_config(struct pci_bus *bus, unsigned int devfn,
487*9aa0cb68SJacky Chou 				       int where, int size, u32 *val,
488*9aa0cb68SJacky Chou 				       bool write)
489*9aa0cb68SJacky Chou {
490*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = bus->sysdata;
491*9aa0cb68SJacky Chou 	u32 bdf_offset, status, cfg_val;
492*9aa0cb68SJacky Chou 	int ret;
493*9aa0cb68SJacky Chou 
494*9aa0cb68SJacky Chou 	bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where);
495*9aa0cb68SJacky Chou 
496*9aa0cb68SJacky Chou 	cfg_val = CFG_PAYLOAD_SIZE;
497*9aa0cb68SJacky Chou 	if (write)
498*9aa0cb68SJacky Chou 		cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ?
499*9aa0cb68SJacky Chou 				   CFG0_WRITE_FMTTYPE :
500*9aa0cb68SJacky Chou 				   CFG1_WRITE_FMTTYPE;
501*9aa0cb68SJacky Chou 	else
502*9aa0cb68SJacky Chou 		cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ?
503*9aa0cb68SJacky Chou 				   CFG0_READ_FMTTYPE :
504*9aa0cb68SJacky Chou 				   CFG1_READ_FMTTYPE;
505*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_1ST);
506*9aa0cb68SJacky Chou 
507*9aa0cb68SJacky Chou 	cfg_val = AST2700_TX_DESC1_VALUE |
508*9aa0cb68SJacky Chou 		  FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) |
509*9aa0cb68SJacky Chou 		  TLP_HEADER_BYTE_EN(size, where);
510*9aa0cb68SJacky Chou 	writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
511*9aa0cb68SJacky Chou 
512*9aa0cb68SJacky Chou 	writel(bdf_offset, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
513*9aa0cb68SJacky Chou 	if (write)
514*9aa0cb68SJacky Chou 		writel(TLP_SET_VALUE(*val, size, where),
515*9aa0cb68SJacky Chou 		       pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT);
516*9aa0cb68SJacky Chou 	writel(ASPEED_CFGE_TX_IDLE | ASPEED_CFGE_RX_BUSY,
517*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_CFGE_INT_STS);
518*9aa0cb68SJacky Chou 	writel(ASPEED_CFGE_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGE_CTRL);
519*9aa0cb68SJacky Chou 
520*9aa0cb68SJacky Chou 	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status,
521*9aa0cb68SJacky Chou 				 (status & ASPEED_CFGE_TX_IDLE), 0, 50);
522*9aa0cb68SJacky Chou 	if (ret) {
523*9aa0cb68SJacky Chou 		dev_err(pcie->dev,
524*9aa0cb68SJacky Chou 			"%02x:%02x.%d CR tx timeout sts: 0x%08x\n",
525*9aa0cb68SJacky Chou 			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status);
526*9aa0cb68SJacky Chou 		ret = PCIBIOS_SET_FAILED;
527*9aa0cb68SJacky Chou 		PCI_SET_ERROR_RESPONSE(val);
528*9aa0cb68SJacky Chou 		goto out;
529*9aa0cb68SJacky Chou 	}
530*9aa0cb68SJacky Chou 
531*9aa0cb68SJacky Chou 	ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status,
532*9aa0cb68SJacky Chou 				 (status & ASPEED_CFGE_RX_BUSY), 0, 50);
533*9aa0cb68SJacky Chou 	if (ret) {
534*9aa0cb68SJacky Chou 		dev_err(pcie->dev,
535*9aa0cb68SJacky Chou 			"%02x:%02x.%d CR rx timeout sts: 0x%08x\n",
536*9aa0cb68SJacky Chou 			bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status);
537*9aa0cb68SJacky Chou 		ret = PCIBIOS_SET_FAILED;
538*9aa0cb68SJacky Chou 		PCI_SET_ERROR_RESPONSE(val);
539*9aa0cb68SJacky Chou 		goto out;
540*9aa0cb68SJacky Chou 	}
541*9aa0cb68SJacky Chou 	*val = readl(pcie->reg + ASPEED_H2X_CFGE_RET_DATA);
542*9aa0cb68SJacky Chou 	*val = TLP_GET_VALUE(*val, size, where);
543*9aa0cb68SJacky Chou 
544*9aa0cb68SJacky Chou 	ret = PCIBIOS_SUCCESSFUL;
545*9aa0cb68SJacky Chou out:
546*9aa0cb68SJacky Chou 	writel(status, pcie->reg + ASPEED_H2X_CFGE_INT_STS);
547*9aa0cb68SJacky Chou 	pcie->tx_tag = (pcie->tx_tag + 1) % 0xf;
548*9aa0cb68SJacky Chou 	return ret;
549*9aa0cb68SJacky Chou }
550*9aa0cb68SJacky Chou 
551*9aa0cb68SJacky Chou static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn,
552*9aa0cb68SJacky Chou 				  int where, int size, u32 *val)
553*9aa0cb68SJacky Chou {
554*9aa0cb68SJacky Chou 	/*
555*9aa0cb68SJacky Chou 	 * AST2700 has only one Root Port on the root bus.
556*9aa0cb68SJacky Chou 	 */
557*9aa0cb68SJacky Chou 	if (devfn != 0)
558*9aa0cb68SJacky Chou 		return PCIBIOS_DEVICE_NOT_FOUND;
559*9aa0cb68SJacky Chou 
560*9aa0cb68SJacky Chou 	return aspeed_ast2700_config(bus, devfn, where, size, val, false);
561*9aa0cb68SJacky Chou }
562*9aa0cb68SJacky Chou 
563*9aa0cb68SJacky Chou static int aspeed_ast2700_child_rd_conf(struct pci_bus *bus, unsigned int devfn,
564*9aa0cb68SJacky Chou 					int where, int size, u32 *val)
565*9aa0cb68SJacky Chou {
566*9aa0cb68SJacky Chou 	return aspeed_ast2700_child_config(bus, devfn, where, size, val, false);
567*9aa0cb68SJacky Chou }
568*9aa0cb68SJacky Chou 
569*9aa0cb68SJacky Chou static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn,
570*9aa0cb68SJacky Chou 				  int where, int size, u32 val)
571*9aa0cb68SJacky Chou {
572*9aa0cb68SJacky Chou 	/*
573*9aa0cb68SJacky Chou 	 * AST2700 has only one Root Port on the root bus.
574*9aa0cb68SJacky Chou 	 */
575*9aa0cb68SJacky Chou 	if (devfn != 0)
576*9aa0cb68SJacky Chou 		return PCIBIOS_DEVICE_NOT_FOUND;
577*9aa0cb68SJacky Chou 
578*9aa0cb68SJacky Chou 	return aspeed_ast2700_config(bus, devfn, where, size, &val, true);
579*9aa0cb68SJacky Chou }
580*9aa0cb68SJacky Chou 
581*9aa0cb68SJacky Chou static int aspeed_ast2700_child_wr_conf(struct pci_bus *bus, unsigned int devfn,
582*9aa0cb68SJacky Chou 					int where, int size, u32 val)
583*9aa0cb68SJacky Chou {
584*9aa0cb68SJacky Chou 	return aspeed_ast2700_child_config(bus, devfn, where, size, &val, true);
585*9aa0cb68SJacky Chou }
586*9aa0cb68SJacky Chou 
587*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2600_pcie_ops = {
588*9aa0cb68SJacky Chou 	.read = aspeed_ast2600_rd_conf,
589*9aa0cb68SJacky Chou 	.write = aspeed_ast2600_wr_conf,
590*9aa0cb68SJacky Chou };
591*9aa0cb68SJacky Chou 
592*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2600_pcie_child_ops = {
593*9aa0cb68SJacky Chou 	.read = aspeed_ast2600_child_rd_conf,
594*9aa0cb68SJacky Chou 	.write = aspeed_ast2600_child_wr_conf,
595*9aa0cb68SJacky Chou };
596*9aa0cb68SJacky Chou 
597*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2700_pcie_ops = {
598*9aa0cb68SJacky Chou 	.read = aspeed_ast2700_rd_conf,
599*9aa0cb68SJacky Chou 	.write = aspeed_ast2700_wr_conf,
600*9aa0cb68SJacky Chou };
601*9aa0cb68SJacky Chou 
602*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2700_pcie_child_ops = {
603*9aa0cb68SJacky Chou 	.read = aspeed_ast2700_child_rd_conf,
604*9aa0cb68SJacky Chou 	.write = aspeed_ast2700_child_wr_conf,
605*9aa0cb68SJacky Chou };
606*9aa0cb68SJacky Chou 
607*9aa0cb68SJacky Chou static void aspeed_irq_compose_msi_msg(struct irq_data *data,
608*9aa0cb68SJacky Chou 				       struct msi_msg *msg)
609*9aa0cb68SJacky Chou {
610*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data);
611*9aa0cb68SJacky Chou 
612*9aa0cb68SJacky Chou 	msg->address_hi = 0;
613*9aa0cb68SJacky Chou 	msg->address_lo = pcie->platform->msi_address;
614*9aa0cb68SJacky Chou 	msg->data = data->hwirq;
615*9aa0cb68SJacky Chou }
616*9aa0cb68SJacky Chou 
617*9aa0cb68SJacky Chou static struct irq_chip aspeed_msi_bottom_irq_chip = {
618*9aa0cb68SJacky Chou 	.name = "ASPEED MSI",
619*9aa0cb68SJacky Chou 	.irq_compose_msi_msg = aspeed_irq_compose_msi_msg,
620*9aa0cb68SJacky Chou };
621*9aa0cb68SJacky Chou 
622*9aa0cb68SJacky Chou static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain,
623*9aa0cb68SJacky Chou 				       unsigned int virq, unsigned int nr_irqs,
624*9aa0cb68SJacky Chou 				       void *args)
625*9aa0cb68SJacky Chou {
626*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = domain->host_data;
627*9aa0cb68SJacky Chou 	int bit;
628*9aa0cb68SJacky Chou 	int i;
629*9aa0cb68SJacky Chou 
630*9aa0cb68SJacky Chou 	guard(mutex)(&pcie->lock);
631*9aa0cb68SJacky Chou 
632*9aa0cb68SJacky Chou 	bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS,
633*9aa0cb68SJacky Chou 				      get_count_order(nr_irqs));
634*9aa0cb68SJacky Chou 
635*9aa0cb68SJacky Chou 	if (bit < 0)
636*9aa0cb68SJacky Chou 		return -ENOSPC;
637*9aa0cb68SJacky Chou 
638*9aa0cb68SJacky Chou 	for (i = 0; i < nr_irqs; i++) {
639*9aa0cb68SJacky Chou 		irq_domain_set_info(domain, virq + i, bit + i,
640*9aa0cb68SJacky Chou 				    &aspeed_msi_bottom_irq_chip,
641*9aa0cb68SJacky Chou 				    domain->host_data, handle_simple_irq, NULL,
642*9aa0cb68SJacky Chou 				    NULL);
643*9aa0cb68SJacky Chou 	}
644*9aa0cb68SJacky Chou 
645*9aa0cb68SJacky Chou 	return 0;
646*9aa0cb68SJacky Chou }
647*9aa0cb68SJacky Chou 
648*9aa0cb68SJacky Chou static void aspeed_irq_msi_domain_free(struct irq_domain *domain,
649*9aa0cb68SJacky Chou 				       unsigned int virq, unsigned int nr_irqs)
650*9aa0cb68SJacky Chou {
651*9aa0cb68SJacky Chou 	struct irq_data *data = irq_domain_get_irq_data(domain, virq);
652*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data);
653*9aa0cb68SJacky Chou 
654*9aa0cb68SJacky Chou 	guard(mutex)(&pcie->lock);
655*9aa0cb68SJacky Chou 
656*9aa0cb68SJacky Chou 	bitmap_release_region(pcie->msi_irq_in_use, data->hwirq,
657*9aa0cb68SJacky Chou 			      get_count_order(nr_irqs));
658*9aa0cb68SJacky Chou }
659*9aa0cb68SJacky Chou 
660*9aa0cb68SJacky Chou static const struct irq_domain_ops aspeed_msi_domain_ops = {
661*9aa0cb68SJacky Chou 	.alloc = aspeed_irq_msi_domain_alloc,
662*9aa0cb68SJacky Chou 	.free = aspeed_irq_msi_domain_free,
663*9aa0cb68SJacky Chou };
664*9aa0cb68SJacky Chou 
665*9aa0cb68SJacky Chou #define ASPEED_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS	| \
666*9aa0cb68SJacky Chou 				  MSI_FLAG_USE_DEF_CHIP_OPS	| \
667*9aa0cb68SJacky Chou 				  MSI_FLAG_NO_AFFINITY)
668*9aa0cb68SJacky Chou 
669*9aa0cb68SJacky Chou #define ASPEED_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK	| \
670*9aa0cb68SJacky Chou 				   MSI_FLAG_MULTI_PCI_MSI	| \
671*9aa0cb68SJacky Chou 				   MSI_FLAG_PCI_MSIX)
672*9aa0cb68SJacky Chou 
673*9aa0cb68SJacky Chou static const struct msi_parent_ops aspeed_msi_parent_ops = {
674*9aa0cb68SJacky Chou 	.required_flags		= ASPEED_MSI_FLAGS_REQUIRED,
675*9aa0cb68SJacky Chou 	.supported_flags	= ASPEED_MSI_FLAGS_SUPPORTED,
676*9aa0cb68SJacky Chou 	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
677*9aa0cb68SJacky Chou 	.chip_flags		= MSI_CHIP_FLAG_SET_ACK,
678*9aa0cb68SJacky Chou 	.prefix			= "ASPEED-",
679*9aa0cb68SJacky Chou 	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
680*9aa0cb68SJacky Chou };
681*9aa0cb68SJacky Chou 
682*9aa0cb68SJacky Chou static int aspeed_pcie_msi_init(struct aspeed_pcie *pcie)
683*9aa0cb68SJacky Chou {
684*9aa0cb68SJacky Chou 	writel(~0, pcie->reg + pcie->platform->reg_msi_en);
685*9aa0cb68SJacky Chou 	writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04);
686*9aa0cb68SJacky Chou 	writel(~0, pcie->reg + pcie->platform->reg_msi_sts);
687*9aa0cb68SJacky Chou 	writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04);
688*9aa0cb68SJacky Chou 
689*9aa0cb68SJacky Chou 	struct irq_domain_info info = {
690*9aa0cb68SJacky Chou 		.fwnode		= dev_fwnode(pcie->dev),
691*9aa0cb68SJacky Chou 		.ops		= &aspeed_msi_domain_ops,
692*9aa0cb68SJacky Chou 		.host_data	= pcie,
693*9aa0cb68SJacky Chou 		.size		= MAX_MSI_HOST_IRQS,
694*9aa0cb68SJacky Chou 	};
695*9aa0cb68SJacky Chou 
696*9aa0cb68SJacky Chou 	pcie->msi_domain = msi_create_parent_irq_domain(&info,
697*9aa0cb68SJacky Chou 							&aspeed_msi_parent_ops);
698*9aa0cb68SJacky Chou 	if (!pcie->msi_domain)
699*9aa0cb68SJacky Chou 		return dev_err_probe(pcie->dev, -ENOMEM,
700*9aa0cb68SJacky Chou 				     "failed to create MSI domain\n");
701*9aa0cb68SJacky Chou 
702*9aa0cb68SJacky Chou 	return 0;
703*9aa0cb68SJacky Chou }
704*9aa0cb68SJacky Chou 
705*9aa0cb68SJacky Chou static void aspeed_pcie_msi_free(struct aspeed_pcie *pcie)
706*9aa0cb68SJacky Chou {
707*9aa0cb68SJacky Chou 	if (pcie->msi_domain) {
708*9aa0cb68SJacky Chou 		irq_domain_remove(pcie->msi_domain);
709*9aa0cb68SJacky Chou 		pcie->msi_domain = NULL;
710*9aa0cb68SJacky Chou 	}
711*9aa0cb68SJacky Chou }
712*9aa0cb68SJacky Chou 
713*9aa0cb68SJacky Chou static void aspeed_pcie_irq_domain_free(void *d)
714*9aa0cb68SJacky Chou {
715*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = d;
716*9aa0cb68SJacky Chou 
717*9aa0cb68SJacky Chou 	if (pcie->intx_domain) {
718*9aa0cb68SJacky Chou 		irq_domain_remove(pcie->intx_domain);
719*9aa0cb68SJacky Chou 		pcie->intx_domain = NULL;
720*9aa0cb68SJacky Chou 	}
721*9aa0cb68SJacky Chou 	aspeed_pcie_msi_free(pcie);
722*9aa0cb68SJacky Chou }
723*9aa0cb68SJacky Chou 
724*9aa0cb68SJacky Chou static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie)
725*9aa0cb68SJacky Chou {
726*9aa0cb68SJacky Chou 	int ret;
727*9aa0cb68SJacky Chou 
728*9aa0cb68SJacky Chou 	pcie->intx_domain = irq_domain_add_linear(pcie->dev->of_node,
729*9aa0cb68SJacky Chou 						  PCI_NUM_INTX,
730*9aa0cb68SJacky Chou 						  &aspeed_intx_domain_ops,
731*9aa0cb68SJacky Chou 						  pcie);
732*9aa0cb68SJacky Chou 	if (!pcie->intx_domain) {
733*9aa0cb68SJacky Chou 		ret = dev_err_probe(pcie->dev, -ENOMEM,
734*9aa0cb68SJacky Chou 				    "failed to get INTx IRQ domain\n");
735*9aa0cb68SJacky Chou 		goto err;
736*9aa0cb68SJacky Chou 	}
737*9aa0cb68SJacky Chou 
738*9aa0cb68SJacky Chou 	writel(0, pcie->reg + pcie->platform->reg_intx_en);
739*9aa0cb68SJacky Chou 	writel(~0, pcie->reg + pcie->platform->reg_intx_sts);
740*9aa0cb68SJacky Chou 
741*9aa0cb68SJacky Chou 	ret = aspeed_pcie_msi_init(pcie);
742*9aa0cb68SJacky Chou 	if (ret)
743*9aa0cb68SJacky Chou 		goto err;
744*9aa0cb68SJacky Chou 
745*9aa0cb68SJacky Chou 	return 0;
746*9aa0cb68SJacky Chou err:
747*9aa0cb68SJacky Chou 	aspeed_pcie_irq_domain_free(pcie);
748*9aa0cb68SJacky Chou 	return ret;
749*9aa0cb68SJacky Chou }
750*9aa0cb68SJacky Chou 
751*9aa0cb68SJacky Chou static int aspeed_pcie_port_init(struct aspeed_pcie_port *port)
752*9aa0cb68SJacky Chou {
753*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = port->pcie;
754*9aa0cb68SJacky Chou 	struct device *dev = pcie->dev;
755*9aa0cb68SJacky Chou 	int ret;
756*9aa0cb68SJacky Chou 
757*9aa0cb68SJacky Chou 	ret = clk_prepare_enable(port->clk);
758*9aa0cb68SJacky Chou 	if (ret)
759*9aa0cb68SJacky Chou 		return dev_err_probe(dev, ret,
760*9aa0cb68SJacky Chou 				     "failed to set clock for slot (%d)\n",
761*9aa0cb68SJacky Chou 				     port->slot);
762*9aa0cb68SJacky Chou 
763*9aa0cb68SJacky Chou 	ret = phy_init(port->phy);
764*9aa0cb68SJacky Chou 	if (ret)
765*9aa0cb68SJacky Chou 		return dev_err_probe(dev, ret,
766*9aa0cb68SJacky Chou 				     "failed to init phy pcie for slot (%d)\n",
767*9aa0cb68SJacky Chou 				     port->slot);
768*9aa0cb68SJacky Chou 
769*9aa0cb68SJacky Chou 	ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
770*9aa0cb68SJacky Chou 	if (ret)
771*9aa0cb68SJacky Chou 		return dev_err_probe(dev, ret,
772*9aa0cb68SJacky Chou 				     "failed to set phy mode for slot (%d)\n",
773*9aa0cb68SJacky Chou 				     port->slot);
774*9aa0cb68SJacky Chou 
775*9aa0cb68SJacky Chou 	reset_control_deassert(port->perst);
776*9aa0cb68SJacky Chou 	msleep(PCIE_RESET_CONFIG_WAIT_MS);
777*9aa0cb68SJacky Chou 
778*9aa0cb68SJacky Chou 	return 0;
779*9aa0cb68SJacky Chou }
780*9aa0cb68SJacky Chou 
781*9aa0cb68SJacky Chou static void aspeed_host_reset(struct aspeed_pcie *pcie)
782*9aa0cb68SJacky Chou {
783*9aa0cb68SJacky Chou 	reset_control_assert(pcie->h2xrst);
784*9aa0cb68SJacky Chou 	mdelay(ASPEED_RESET_RC_WAIT_MS);
785*9aa0cb68SJacky Chou 	reset_control_deassert(pcie->h2xrst);
786*9aa0cb68SJacky Chou }
787*9aa0cb68SJacky Chou 
788*9aa0cb68SJacky Chou static void aspeed_pcie_map_ranges(struct aspeed_pcie *pcie)
789*9aa0cb68SJacky Chou {
790*9aa0cb68SJacky Chou 	struct pci_host_bridge *bridge = pcie->host;
791*9aa0cb68SJacky Chou 	struct resource_entry *window;
792*9aa0cb68SJacky Chou 
793*9aa0cb68SJacky Chou 	resource_list_for_each_entry(window, &bridge->windows) {
794*9aa0cb68SJacky Chou 		u64 pci_addr;
795*9aa0cb68SJacky Chou 
796*9aa0cb68SJacky Chou 		if (resource_type(window->res) != IORESOURCE_MEM)
797*9aa0cb68SJacky Chou 			continue;
798*9aa0cb68SJacky Chou 
799*9aa0cb68SJacky Chou 		pci_addr = window->res->start - window->offset;
800*9aa0cb68SJacky Chou 		pcie->platform->pcie_map_ranges(pcie, pci_addr);
801*9aa0cb68SJacky Chou 		break;
802*9aa0cb68SJacky Chou 	}
803*9aa0cb68SJacky Chou }
804*9aa0cb68SJacky Chou 
805*9aa0cb68SJacky Chou static void aspeed_ast2600_pcie_map_ranges(struct aspeed_pcie *pcie,
806*9aa0cb68SJacky Chou 					  u64 pci_addr)
807*9aa0cb68SJacky Chou {
808*9aa0cb68SJacky Chou 	u32 pci_addr_lo = pci_addr & GENMASK(31, 0);
809*9aa0cb68SJacky Chou 	u32 pci_addr_hi = (pci_addr >> 32) & GENMASK(31, 0);
810*9aa0cb68SJacky Chou 
811*9aa0cb68SJacky Chou 	pci_addr_lo >>= 16;
812*9aa0cb68SJacky Chou 	writel(ASPEED_AHB_REMAP_LO_ADDR(pci_addr_lo) |
813*9aa0cb68SJacky Chou 	       ASPEED_AHB_MASK_LO_ADDR(0xe00),
814*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0);
815*9aa0cb68SJacky Chou 	writel(ASPEED_AHB_REMAP_HI_ADDR(pci_addr_hi),
816*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1);
817*9aa0cb68SJacky Chou 	writel(ASPEED_AHB_MASK_HI_ADDR(~0),
818*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2);
819*9aa0cb68SJacky Chou }
820*9aa0cb68SJacky Chou 
821*9aa0cb68SJacky Chou static int aspeed_ast2600_setup(struct platform_device *pdev)
822*9aa0cb68SJacky Chou {
823*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
824*9aa0cb68SJacky Chou 	struct device *dev = pcie->dev;
825*9aa0cb68SJacky Chou 
826*9aa0cb68SJacky Chou 	pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node,
827*9aa0cb68SJacky Chou 						     "aspeed,ahbc");
828*9aa0cb68SJacky Chou 	if (IS_ERR(pcie->ahbc))
829*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(pcie->ahbc),
830*9aa0cb68SJacky Chou 				     "failed to map ahbc base\n");
831*9aa0cb68SJacky Chou 
832*9aa0cb68SJacky Chou 	aspeed_host_reset(pcie);
833*9aa0cb68SJacky Chou 
834*9aa0cb68SJacky Chou 	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK_KEY);
835*9aa0cb68SJacky Chou 	regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING,
836*9aa0cb68SJacky Chou 			   ASPEED_PCIE_RC_MEMORY_EN, ASPEED_PCIE_RC_MEMORY_EN);
837*9aa0cb68SJacky Chou 	regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK);
838*9aa0cb68SJacky Chou 
839*9aa0cb68SJacky Chou 	writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL);
840*9aa0cb68SJacky Chou 
841*9aa0cb68SJacky Chou 	writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR |
842*9aa0cb68SJacky Chou 	       ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN |
843*9aa0cb68SJacky Chou 	       ASPEED_PCIE_WAIT_RX_TLP_CLR | ASPEED_PCIE_RC_RX_ENABLE |
844*9aa0cb68SJacky Chou 	       ASPEED_PCIE_RC_ENABLE,
845*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_DEV_CTRL);
846*9aa0cb68SJacky Chou 
847*9aa0cb68SJacky Chou 	writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg + ASPEED_H2X_DEV_TX_TAG);
848*9aa0cb68SJacky Chou 
849*9aa0cb68SJacky Chou 	pcie->host->ops = &aspeed_ast2600_pcie_ops;
850*9aa0cb68SJacky Chou 	pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops;
851*9aa0cb68SJacky Chou 
852*9aa0cb68SJacky Chou 	return 0;
853*9aa0cb68SJacky Chou }
854*9aa0cb68SJacky Chou 
855*9aa0cb68SJacky Chou static void aspeed_ast2700_pcie_map_ranges(struct aspeed_pcie *pcie,
856*9aa0cb68SJacky Chou 					  u64 pci_addr)
857*9aa0cb68SJacky Chou {
858*9aa0cb68SJacky Chou 	writel(ASPEED_REMAP_PCI_ADDR_31_12(pci_addr),
859*9aa0cb68SJacky Chou 		pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO);
860*9aa0cb68SJacky Chou 	writel(ASPEED_REMAP_PCI_ADDR_63_32(pci_addr),
861*9aa0cb68SJacky Chou 		pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI);
862*9aa0cb68SJacky Chou }
863*9aa0cb68SJacky Chou 
864*9aa0cb68SJacky Chou static int aspeed_ast2700_setup(struct platform_device *pdev)
865*9aa0cb68SJacky Chou {
866*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie = platform_get_drvdata(pdev);
867*9aa0cb68SJacky Chou 	struct device *dev = pcie->dev;
868*9aa0cb68SJacky Chou 
869*9aa0cb68SJacky Chou 	pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node,
870*9aa0cb68SJacky Chou 						    "aspeed,pciecfg");
871*9aa0cb68SJacky Chou 	if (IS_ERR(pcie->cfg))
872*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(pcie->cfg),
873*9aa0cb68SJacky Chou 				     "failed to map pciecfg base\n");
874*9aa0cb68SJacky Chou 
875*9aa0cb68SJacky Chou 	regmap_update_bits(pcie->cfg, ASPEED_SCU_60,
876*9aa0cb68SJacky Chou 			   ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN |
877*9aa0cb68SJacky Chou 			   ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN |
878*9aa0cb68SJacky Chou 			   ASPEED_RC_UPSTREAM_MEM_EN,
879*9aa0cb68SJacky Chou 			   ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN |
880*9aa0cb68SJacky Chou 			   ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN |
881*9aa0cb68SJacky Chou 			   ASPEED_RC_UPSTREAM_MEM_EN);
882*9aa0cb68SJacky Chou 	regmap_write(pcie->cfg, ASPEED_SCU_64,
883*9aa0cb68SJacky Chou 		     ASPEED_RC0_DECODE_DMA_BASE(0) |
884*9aa0cb68SJacky Chou 		     ASPEED_RC0_DECODE_DMA_LIMIT(0xff) |
885*9aa0cb68SJacky Chou 		     ASPEED_RC1_DECODE_DMA_BASE(0) |
886*9aa0cb68SJacky Chou 		     ASPEED_RC1_DECODE_DMA_LIMIT(0xff));
887*9aa0cb68SJacky Chou 	regmap_write(pcie->cfg, ASPEED_SCU_70, ASPEED_DISABLE_EP_FUNC);
888*9aa0cb68SJacky Chou 
889*9aa0cb68SJacky Chou 	aspeed_host_reset(pcie);
890*9aa0cb68SJacky Chou 
891*9aa0cb68SJacky Chou 	writel(0, pcie->reg + ASPEED_H2X_CTRL);
892*9aa0cb68SJacky Chou 	writel(ASPEED_H2X_BRIDGE_EN | ASPEED_H2X_BRIDGE_DIRECT_EN,
893*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_CTRL);
894*9aa0cb68SJacky Chou 
895*9aa0cb68SJacky Chou 	/* Prepare for 64-bit BAR pref */
896*9aa0cb68SJacky Chou 	writel(ASPEED_REMAP_PREF_ADDR_63_32(0x3),
897*9aa0cb68SJacky Chou 	       pcie->reg + ASPEED_H2X_REMAP_PREF_ADDR);
898*9aa0cb68SJacky Chou 
899*9aa0cb68SJacky Chou 	pcie->host->ops = &aspeed_ast2700_pcie_ops;
900*9aa0cb68SJacky Chou 	pcie->host->child_ops = &aspeed_ast2700_pcie_child_ops;
901*9aa0cb68SJacky Chou 	pcie->clear_msi_twice = true;
902*9aa0cb68SJacky Chou 
903*9aa0cb68SJacky Chou 	return 0;
904*9aa0cb68SJacky Chou }
905*9aa0cb68SJacky Chou 
906*9aa0cb68SJacky Chou static void aspeed_pcie_reset_release(void *d)
907*9aa0cb68SJacky Chou {
908*9aa0cb68SJacky Chou 	struct reset_control *perst = d;
909*9aa0cb68SJacky Chou 
910*9aa0cb68SJacky Chou 	if (!perst)
911*9aa0cb68SJacky Chou 		return;
912*9aa0cb68SJacky Chou 
913*9aa0cb68SJacky Chou 	reset_control_put(perst);
914*9aa0cb68SJacky Chou }
915*9aa0cb68SJacky Chou 
916*9aa0cb68SJacky Chou static int aspeed_pcie_parse_port(struct aspeed_pcie *pcie,
917*9aa0cb68SJacky Chou 				  struct device_node *node,
918*9aa0cb68SJacky Chou 				  int slot)
919*9aa0cb68SJacky Chou {
920*9aa0cb68SJacky Chou 	struct aspeed_pcie_port *port;
921*9aa0cb68SJacky Chou 	struct device *dev = pcie->dev;
922*9aa0cb68SJacky Chou 	int ret;
923*9aa0cb68SJacky Chou 
924*9aa0cb68SJacky Chou 	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
925*9aa0cb68SJacky Chou 	if (!port)
926*9aa0cb68SJacky Chou 		return -ENOMEM;
927*9aa0cb68SJacky Chou 
928*9aa0cb68SJacky Chou 	port->clk = devm_get_clk_from_child(dev, node, NULL);
929*9aa0cb68SJacky Chou 	if (IS_ERR(port->clk))
930*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(port->clk),
931*9aa0cb68SJacky Chou 				     "failed to get pcie%d clock\n", slot);
932*9aa0cb68SJacky Chou 
933*9aa0cb68SJacky Chou 	port->phy = devm_of_phy_get(dev, node, NULL);
934*9aa0cb68SJacky Chou 	if (IS_ERR(port->phy))
935*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(port->phy),
936*9aa0cb68SJacky Chou 				     "failed to get phy pcie%d\n", slot);
937*9aa0cb68SJacky Chou 
938*9aa0cb68SJacky Chou 	port->perst = of_reset_control_get_exclusive(node, "perst");
939*9aa0cb68SJacky Chou 	if (IS_ERR(port->perst))
940*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(port->perst),
941*9aa0cb68SJacky Chou 				     "failed to get pcie%d reset control\n",
942*9aa0cb68SJacky Chou 				     slot);
943*9aa0cb68SJacky Chou 	ret = devm_add_action_or_reset(dev, aspeed_pcie_reset_release,
944*9aa0cb68SJacky Chou 				       port->perst);
945*9aa0cb68SJacky Chou 	if (ret)
946*9aa0cb68SJacky Chou 		return ret;
947*9aa0cb68SJacky Chou 	reset_control_assert(port->perst);
948*9aa0cb68SJacky Chou 
949*9aa0cb68SJacky Chou 	port->slot = slot;
950*9aa0cb68SJacky Chou 	port->pcie = pcie;
951*9aa0cb68SJacky Chou 
952*9aa0cb68SJacky Chou 	INIT_LIST_HEAD(&port->list);
953*9aa0cb68SJacky Chou 	list_add_tail(&port->list, &pcie->ports);
954*9aa0cb68SJacky Chou 
955*9aa0cb68SJacky Chou 	ret = aspeed_pcie_port_init(port);
956*9aa0cb68SJacky Chou 	if (ret)
957*9aa0cb68SJacky Chou 		return ret;
958*9aa0cb68SJacky Chou 
959*9aa0cb68SJacky Chou 	return 0;
960*9aa0cb68SJacky Chou }
961*9aa0cb68SJacky Chou 
962*9aa0cb68SJacky Chou static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie)
963*9aa0cb68SJacky Chou {
964*9aa0cb68SJacky Chou 	struct device *dev = pcie->dev;
965*9aa0cb68SJacky Chou 	struct device_node *node = dev->of_node;
966*9aa0cb68SJacky Chou 	int ret;
967*9aa0cb68SJacky Chou 
968*9aa0cb68SJacky Chou 	for_each_available_child_of_node_scoped(node, child) {
969*9aa0cb68SJacky Chou 		int slot;
970*9aa0cb68SJacky Chou 		const char *type;
971*9aa0cb68SJacky Chou 
972*9aa0cb68SJacky Chou 		ret = of_property_read_string(child, "device_type", &type);
973*9aa0cb68SJacky Chou 		if (ret || strcmp(type, "pci"))
974*9aa0cb68SJacky Chou 			continue;
975*9aa0cb68SJacky Chou 
976*9aa0cb68SJacky Chou 		ret = of_pci_get_devfn(child);
977*9aa0cb68SJacky Chou 		if (ret < 0)
978*9aa0cb68SJacky Chou 			return dev_err_probe(dev, ret,
979*9aa0cb68SJacky Chou 					     "failed to parse devfn\n");
980*9aa0cb68SJacky Chou 
981*9aa0cb68SJacky Chou 		slot = PCI_SLOT(ret);
982*9aa0cb68SJacky Chou 
983*9aa0cb68SJacky Chou 		ret = aspeed_pcie_parse_port(pcie, child, slot);
984*9aa0cb68SJacky Chou 		if (ret)
985*9aa0cb68SJacky Chou 			return ret;
986*9aa0cb68SJacky Chou 	}
987*9aa0cb68SJacky Chou 
988*9aa0cb68SJacky Chou 	if (list_empty(&pcie->ports))
989*9aa0cb68SJacky Chou 		return dev_err_probe(dev, -ENODEV,
990*9aa0cb68SJacky Chou 				     "No PCIe port found in DT\n");
991*9aa0cb68SJacky Chou 
992*9aa0cb68SJacky Chou 	return 0;
993*9aa0cb68SJacky Chou }
994*9aa0cb68SJacky Chou 
995*9aa0cb68SJacky Chou static int aspeed_pcie_probe(struct platform_device *pdev)
996*9aa0cb68SJacky Chou {
997*9aa0cb68SJacky Chou 	struct device *dev = &pdev->dev;
998*9aa0cb68SJacky Chou 	struct pci_host_bridge *host;
999*9aa0cb68SJacky Chou 	struct aspeed_pcie *pcie;
1000*9aa0cb68SJacky Chou 	struct resource_entry *entry;
1001*9aa0cb68SJacky Chou 	const struct aspeed_pcie_rc_platform *md;
1002*9aa0cb68SJacky Chou 	int irq, ret;
1003*9aa0cb68SJacky Chou 
1004*9aa0cb68SJacky Chou 	md = of_device_get_match_data(dev);
1005*9aa0cb68SJacky Chou 	if (!md)
1006*9aa0cb68SJacky Chou 		return -ENODEV;
1007*9aa0cb68SJacky Chou 
1008*9aa0cb68SJacky Chou 	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
1009*9aa0cb68SJacky Chou 	if (!host)
1010*9aa0cb68SJacky Chou 		return -ENOMEM;
1011*9aa0cb68SJacky Chou 
1012*9aa0cb68SJacky Chou 	pcie = pci_host_bridge_priv(host);
1013*9aa0cb68SJacky Chou 	pcie->dev = dev;
1014*9aa0cb68SJacky Chou 	pcie->tx_tag = 0;
1015*9aa0cb68SJacky Chou 	platform_set_drvdata(pdev, pcie);
1016*9aa0cb68SJacky Chou 
1017*9aa0cb68SJacky Chou 	pcie->platform = md;
1018*9aa0cb68SJacky Chou 	pcie->host = host;
1019*9aa0cb68SJacky Chou 	INIT_LIST_HEAD(&pcie->ports);
1020*9aa0cb68SJacky Chou 
1021*9aa0cb68SJacky Chou 	/* Get root bus num for cfg command to decide tlp type 0 or type 1 */
1022*9aa0cb68SJacky Chou 	entry = resource_list_first_type(&host->windows, IORESOURCE_BUS);
1023*9aa0cb68SJacky Chou 	if (entry)
1024*9aa0cb68SJacky Chou 		pcie->root_bus_nr = entry->res->start;
1025*9aa0cb68SJacky Chou 
1026*9aa0cb68SJacky Chou 	pcie->reg = devm_platform_ioremap_resource(pdev, 0);
1027*9aa0cb68SJacky Chou 	if (IS_ERR(pcie->reg))
1028*9aa0cb68SJacky Chou 		return PTR_ERR(pcie->reg);
1029*9aa0cb68SJacky Chou 
1030*9aa0cb68SJacky Chou 	pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x");
1031*9aa0cb68SJacky Chou 	if (IS_ERR(pcie->h2xrst))
1032*9aa0cb68SJacky Chou 		return dev_err_probe(dev, PTR_ERR(pcie->h2xrst),
1033*9aa0cb68SJacky Chou 				     "failed to get h2x reset\n");
1034*9aa0cb68SJacky Chou 
1035*9aa0cb68SJacky Chou 	ret = devm_mutex_init(dev, &pcie->lock);
1036*9aa0cb68SJacky Chou 	if (ret)
1037*9aa0cb68SJacky Chou 		return dev_err_probe(dev, ret, "failed to init mutex\n");
1038*9aa0cb68SJacky Chou 
1039*9aa0cb68SJacky Chou 	ret = pcie->platform->setup(pdev);
1040*9aa0cb68SJacky Chou 	if (ret)
1041*9aa0cb68SJacky Chou 		return dev_err_probe(dev, ret, "failed to setup PCIe RC\n");
1042*9aa0cb68SJacky Chou 
1043*9aa0cb68SJacky Chou 	aspeed_pcie_map_ranges(pcie);
1044*9aa0cb68SJacky Chou 
1045*9aa0cb68SJacky Chou 	ret = aspeed_pcie_parse_dt(pcie);
1046*9aa0cb68SJacky Chou 	if (ret)
1047*9aa0cb68SJacky Chou 		return ret;
1048*9aa0cb68SJacky Chou 
1049*9aa0cb68SJacky Chou 	host->sysdata = pcie;
1050*9aa0cb68SJacky Chou 
1051*9aa0cb68SJacky Chou 	ret = aspeed_pcie_init_irq_domain(pcie);
1052*9aa0cb68SJacky Chou 	if (ret)
1053*9aa0cb68SJacky Chou 		return ret;
1054*9aa0cb68SJacky Chou 
1055*9aa0cb68SJacky Chou 	irq = platform_get_irq(pdev, 0);
1056*9aa0cb68SJacky Chou 	if (irq < 0)
1057*9aa0cb68SJacky Chou 		return irq;
1058*9aa0cb68SJacky Chou 
1059*9aa0cb68SJacky Chou 	ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie);
1060*9aa0cb68SJacky Chou 	if (ret)
1061*9aa0cb68SJacky Chou 		return ret;
1062*9aa0cb68SJacky Chou 
1063*9aa0cb68SJacky Chou 	ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED,
1064*9aa0cb68SJacky Chou 			       dev_name(dev), pcie);
1065*9aa0cb68SJacky Chou 	if (ret)
1066*9aa0cb68SJacky Chou 		return ret;
1067*9aa0cb68SJacky Chou 
1068*9aa0cb68SJacky Chou 	return pci_host_probe(host);
1069*9aa0cb68SJacky Chou }
1070*9aa0cb68SJacky Chou 
1071*9aa0cb68SJacky Chou static const struct aspeed_pcie_rc_platform pcie_rc_ast2600 = {
1072*9aa0cb68SJacky Chou 	.setup = aspeed_ast2600_setup,
1073*9aa0cb68SJacky Chou 	.pcie_map_ranges = aspeed_ast2600_pcie_map_ranges,
1074*9aa0cb68SJacky Chou 	.reg_intx_en = 0xc4,
1075*9aa0cb68SJacky Chou 	.reg_intx_sts = 0xc8,
1076*9aa0cb68SJacky Chou 	.reg_msi_en = 0xe0,
1077*9aa0cb68SJacky Chou 	.reg_msi_sts = 0xe8,
1078*9aa0cb68SJacky Chou 	.msi_address = 0x1e77005c,
1079*9aa0cb68SJacky Chou };
1080*9aa0cb68SJacky Chou 
1081*9aa0cb68SJacky Chou static const struct aspeed_pcie_rc_platform pcie_rc_ast2700 = {
1082*9aa0cb68SJacky Chou 	.setup = aspeed_ast2700_setup,
1083*9aa0cb68SJacky Chou 	.pcie_map_ranges = aspeed_ast2700_pcie_map_ranges,
1084*9aa0cb68SJacky Chou 	.reg_intx_en = 0x40,
1085*9aa0cb68SJacky Chou 	.reg_intx_sts = 0x48,
1086*9aa0cb68SJacky Chou 	.reg_msi_en = 0x50,
1087*9aa0cb68SJacky Chou 	.reg_msi_sts = 0x58,
1088*9aa0cb68SJacky Chou 	.msi_address = 0x000000f0,
1089*9aa0cb68SJacky Chou };
1090*9aa0cb68SJacky Chou 
1091*9aa0cb68SJacky Chou static const struct of_device_id aspeed_pcie_of_match[] = {
1092*9aa0cb68SJacky Chou 	{ .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 },
1093*9aa0cb68SJacky Chou 	{ .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 },
1094*9aa0cb68SJacky Chou 	{}
1095*9aa0cb68SJacky Chou };
1096*9aa0cb68SJacky Chou 
1097*9aa0cb68SJacky Chou static struct platform_driver aspeed_pcie_driver = {
1098*9aa0cb68SJacky Chou 	.driver = {
1099*9aa0cb68SJacky Chou 		.name = "aspeed-pcie",
1100*9aa0cb68SJacky Chou 		.of_match_table = aspeed_pcie_of_match,
1101*9aa0cb68SJacky Chou 		.suppress_bind_attrs = true,
1102*9aa0cb68SJacky Chou 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1103*9aa0cb68SJacky Chou 	},
1104*9aa0cb68SJacky Chou 	.probe = aspeed_pcie_probe,
1105*9aa0cb68SJacky Chou };
1106*9aa0cb68SJacky Chou 
1107*9aa0cb68SJacky Chou builtin_platform_driver(aspeed_pcie_driver);
1108*9aa0cb68SJacky Chou 
1109*9aa0cb68SJacky Chou MODULE_AUTHOR("Jacky Chou <jacky_chou@aspeedtech.com>");
1110*9aa0cb68SJacky Chou MODULE_DESCRIPTION("ASPEED PCIe Root Complex");
1111*9aa0cb68SJacky Chou MODULE_LICENSE("GPL");
1112