xref: /rk3399_rockchip-uboot/drivers/pci/pcie_dw_rockchip.c (revision 7ece1cfe673e49ea2243b5cf03217ed979d5ff6c)
1bc58f211SShawn Lin // SPDX-License-Identifier: GPL-2.0+
2bc58f211SShawn Lin /*
3bc58f211SShawn Lin  * Rockchip DesignWare based PCIe host controller driver
4bc58f211SShawn Lin  *
5bc58f211SShawn Lin  * Copyright (c) 2021 Rockchip, Inc.
6bc58f211SShawn Lin  */
7bc58f211SShawn Lin 
8bc58f211SShawn Lin #include <common.h>
9bc58f211SShawn Lin #include <clk.h>
10bc58f211SShawn Lin #include <dm.h>
11bc58f211SShawn Lin #include <generic-phy.h>
12bc58f211SShawn Lin #include <pci.h>
13bc58f211SShawn Lin #include <power-domain.h>
14bc58f211SShawn Lin #include <power/regulator.h>
15bc58f211SShawn Lin #include <reset.h>
16bc58f211SShawn Lin #include <syscon.h>
17bc58f211SShawn Lin #include <asm/io.h>
18bc58f211SShawn Lin #include <asm-generic/gpio.h>
19bc58f211SShawn Lin #include <asm/arch-rockchip/clock.h>
20b8495bb7SShawn Lin #include <linux/bitfield.h>
21bc58f211SShawn Lin #include <linux/iopoll.h>
22fbc8ca74SJon Lin #include <linux/ioport.h>
23b8495bb7SShawn Lin #include <linux/log2.h>
24bc58f211SShawn Lin 
25bc58f211SShawn Lin DECLARE_GLOBAL_DATA_PTR;
26bc58f211SShawn Lin 
270e16653bSJon Lin #define RK_PCIE_DBG			0
280e16653bSJon Lin 
290e16653bSJon Lin #define __pcie_dev_print_emit(fmt, ...) \
300e16653bSJon Lin ({ \
310e16653bSJon Lin 	printf(fmt, ##__VA_ARGS__); \
320e16653bSJon Lin })
330e16653bSJon Lin 
340e16653bSJon Lin #ifdef dev_err
350e16653bSJon Lin #undef dev_err
360e16653bSJon Lin #define dev_err(dev, fmt, ...) \
370e16653bSJon Lin ({ \
380e16653bSJon Lin 	if (dev) \
390e16653bSJon Lin 		__pcie_dev_print_emit("%s: " fmt, dev->name, \
400e16653bSJon Lin 				##__VA_ARGS__); \
410e16653bSJon Lin })
420e16653bSJon Lin #endif
430e16653bSJon Lin 
440e16653bSJon Lin #ifdef dev_info
450e16653bSJon Lin #undef dev_info
460e16653bSJon Lin #define dev_info dev_err
470e16653bSJon Lin #endif
480e16653bSJon Lin 
490e16653bSJon Lin #ifdef DEBUG
500e16653bSJon Lin #define dev_dbg dev_err
510e16653bSJon Lin #else
520e16653bSJon Lin #define dev_dbg(dev, fmt, ...)					\
530e16653bSJon Lin ({								\
540e16653bSJon Lin 	if (0)							\
550e16653bSJon Lin 		__dev_printk(7, dev, fmt, ##__VA_ARGS__);	\
560e16653bSJon Lin })
570e16653bSJon Lin #endif
580e16653bSJon Lin 
59bc58f211SShawn Lin struct rk_pcie {
60bc58f211SShawn Lin 	struct udevice	*dev;
61bc58f211SShawn Lin 	struct udevice  *vpcie3v3;
62bc58f211SShawn Lin 	void		*dbi_base;
63bc58f211SShawn Lin 	void		*apb_base;
64bc58f211SShawn Lin 	void		*cfg_base;
65bc58f211SShawn Lin 	fdt_size_t	cfg_size;
66bc58f211SShawn Lin 	struct phy	phy;
67bc58f211SShawn Lin 	struct clk_bulk	clks;
68bc58f211SShawn Lin 	int		first_busno;
69bc58f211SShawn Lin 	struct reset_ctl_bulk	rsts;
70bc58f211SShawn Lin 	struct gpio_desc	rst_gpio;
71bc58f211SShawn Lin 	struct pci_region	io;
72bc58f211SShawn Lin 	struct pci_region	mem;
737ff76e75SShawn Lin 	struct pci_region	mem64;
74c2482762SShawn Lin 	bool		is_bifurcation;
75769b1920SShawn Lin 	u32 rasdes_off;
76abcec002SJon Lin 	u32 gen;
77b8495bb7SShawn Lin 	u32 lanes;
78bc58f211SShawn Lin };
79bc58f211SShawn Lin 
80bc58f211SShawn Lin enum {
81bc58f211SShawn Lin 	PCIBIOS_SUCCESSFUL = 0x0000,
82bc58f211SShawn Lin 	PCIBIOS_UNSUPPORTED = -ENODEV,
83bc58f211SShawn Lin 	PCIBIOS_NODEV = -ENODEV,
84bc58f211SShawn Lin };
85bc58f211SShawn Lin 
86bc58f211SShawn Lin #define msleep(a)		udelay((a) * 1000)
87fec7a75eSShawn Lin #define MAX_LINKUP_RETRIES		2
88bc58f211SShawn Lin 
89bc58f211SShawn Lin /* Parameters for the waiting for iATU enabled routine */
90bc58f211SShawn Lin #define PCIE_CLIENT_GENERAL_DEBUG	0x104
91fbafd477SShawn Lin #define PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN 0x154
92bc58f211SShawn Lin #define PCIE_CLIENT_HOT_RESET_CTRL	0x180
93bc58f211SShawn Lin #define PCIE_LTSSM_ENABLE_ENHANCE	BIT(4)
94bc58f211SShawn Lin #define PCIE_CLIENT_LTSSM_STATUS	0x300
95bc58f211SShawn Lin #define SMLH_LINKUP			BIT(16)
96bc58f211SShawn Lin #define RDLH_LINKUP			BIT(17)
97bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_MODE_CON	0x310
98bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
99bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
100bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
101bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
102bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_STATUS	0x350
103bc58f211SShawn Lin #define PCIE_CLIENT_DBG_TRANSITION_DATA	0xffff0000
104bc58f211SShawn Lin #define PCIE_CLIENT_DBF_EN		0xffff0003
105bc58f211SShawn Lin 
106bc58f211SShawn Lin /* PCI DBICS registers */
107bc58f211SShawn Lin #define PCIE_LINK_STATUS_REG		0x80
108bc58f211SShawn Lin #define PCIE_LINK_STATUS_SPEED_OFF	16
109bc58f211SShawn Lin #define PCIE_LINK_STATUS_SPEED_MASK	(0xf << PCIE_LINK_STATUS_SPEED_OFF)
110bc58f211SShawn Lin #define PCIE_LINK_STATUS_WIDTH_OFF	20
111bc58f211SShawn Lin #define PCIE_LINK_STATUS_WIDTH_MASK	(0xf << PCIE_LINK_STATUS_WIDTH_OFF)
112bc58f211SShawn Lin 
113bc58f211SShawn Lin #define PCIE_LINK_CAPABILITY		0x7c
114bc58f211SShawn Lin #define PCIE_LINK_CTL_2			0xa0
115bc58f211SShawn Lin #define TARGET_LINK_SPEED_MASK		0xf
116bc58f211SShawn Lin #define LINK_SPEED_GEN_1		0x1
117bc58f211SShawn Lin #define LINK_SPEED_GEN_2		0x2
118bc58f211SShawn Lin #define LINK_SPEED_GEN_3		0x3
119bc58f211SShawn Lin 
120b8495bb7SShawn Lin #define PCIE_PORT_LINK_CONTROL          0x710
121b8495bb7SShawn Lin #define PORT_LINK_FAST_LINK_MODE        BIT(7)
122bc58f211SShawn Lin #define PCIE_MISC_CONTROL_1_OFF		0x8bc
123bc58f211SShawn Lin #define PCIE_DBI_RO_WR_EN		BIT(0)
124bc58f211SShawn Lin 
125bc58f211SShawn Lin #define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80c
126bc58f211SShawn Lin #define PORT_LOGIC_SPEED_CHANGE		BIT(17)
127b8495bb7SShawn Lin #define PORT_LINK_MODE_MASK             GENMASK(21, 16)
128b8495bb7SShawn Lin #define PORT_LINK_MODE(n)               FIELD_PREP(PORT_LINK_MODE_MASK, n)
129b8495bb7SShawn Lin #define PORT_LINK_MODE_1_LANES          PORT_LINK_MODE(0x1)
130b8495bb7SShawn Lin #define PORT_LINK_MODE_2_LANES          PORT_LINK_MODE(0x3)
131b8495bb7SShawn Lin #define PORT_LINK_MODE_4_LANES          PORT_LINK_MODE(0x7)
132b8495bb7SShawn Lin #define PORT_LINK_MODE_8_LANES          PORT_LINK_MODE(0xf)
133b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH_MASK      GENMASK(12, 8)
134b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH(n)        FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
135b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH_1_LANES   PORT_LOGIC_LINK_WIDTH(0x1)
136b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH_2_LANES   PORT_LOGIC_LINK_WIDTH(0x2)
137b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH_4_LANES   PORT_LOGIC_LINK_WIDTH(0x4)
138b8495bb7SShawn Lin #define PORT_LOGIC_LINK_WIDTH_8_LANES   PORT_LOGIC_LINK_WIDTH(0x8)
139b8495bb7SShawn Lin 
140bc58f211SShawn Lin 
141bc58f211SShawn Lin /*
142bc58f211SShawn Lin  * iATU Unroll-specific register definitions
143bc58f211SShawn Lin  * From 4.80 core version the address translation will be made by unroll.
144bc58f211SShawn Lin  * The registers are offset from atu_base
145bc58f211SShawn Lin  */
146bc58f211SShawn Lin #define PCIE_ATU_UNR_REGION_CTRL1	0x00
147bc58f211SShawn Lin #define PCIE_ATU_UNR_REGION_CTRL2	0x04
148bc58f211SShawn Lin #define PCIE_ATU_UNR_LOWER_BASE		0x08
149bc58f211SShawn Lin #define PCIE_ATU_UNR_UPPER_BASE		0x0c
150bc58f211SShawn Lin #define PCIE_ATU_UNR_LIMIT		0x10
151bc58f211SShawn Lin #define PCIE_ATU_UNR_LOWER_TARGET	0x14
152bc58f211SShawn Lin #define PCIE_ATU_UNR_UPPER_TARGET	0x18
153bc58f211SShawn Lin 
1547ff76e75SShawn Lin #define PCIE_ATU_REGION_INDEX2		(0x2 << 0)
155bc58f211SShawn Lin #define PCIE_ATU_REGION_INDEX1		(0x1 << 0)
156bc58f211SShawn Lin #define PCIE_ATU_REGION_INDEX0		(0x0 << 0)
157bc58f211SShawn Lin #define PCIE_ATU_TYPE_MEM		(0x0 << 0)
158bc58f211SShawn Lin #define PCIE_ATU_TYPE_IO		(0x2 << 0)
159bc58f211SShawn Lin #define PCIE_ATU_TYPE_CFG0		(0x4 << 0)
160bc58f211SShawn Lin #define PCIE_ATU_TYPE_CFG1		(0x5 << 0)
161bc58f211SShawn Lin #define PCIE_ATU_ENABLE			(0x1 << 31)
162bc58f211SShawn Lin #define PCIE_ATU_BAR_MODE_ENABLE	(0x1 << 30)
163bc58f211SShawn Lin #define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
164bc58f211SShawn Lin #define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
165bc58f211SShawn Lin #define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
166bc58f211SShawn Lin 
167bc58f211SShawn Lin /* Register address builder */
168bc58f211SShawn Lin #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region)        \
169bc58f211SShawn Lin 	((0x3 << 20) | ((region) << 9))
170bc58f211SShawn Lin #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
171bc58f211SShawn Lin 	((0x3 << 20) | ((region) << 9) | (0x1 << 8))
172bc58f211SShawn Lin 
173bc58f211SShawn Lin /* Parameters for the waiting for iATU enabled routine */
174bc58f211SShawn Lin #define LINK_WAIT_MAX_IATU_RETRIES	5
175bc58f211SShawn Lin #define LINK_WAIT_IATU			10000
176bc58f211SShawn Lin 
1771f452320SJon Lin #define PCIE_TYPE0_HDR_DBI2_OFFSET      0x100000
1781f452320SJon Lin 
rk_pcie_read(void __iomem * addr,int size,u32 * val)179bc58f211SShawn Lin static int rk_pcie_read(void __iomem *addr, int size, u32 *val)
180bc58f211SShawn Lin {
181bc58f211SShawn Lin 	if ((uintptr_t)addr & (size - 1)) {
182bc58f211SShawn Lin 		*val = 0;
183bc58f211SShawn Lin 		return PCIBIOS_UNSUPPORTED;
184bc58f211SShawn Lin 	}
185bc58f211SShawn Lin 
186bc58f211SShawn Lin 	if (size == 4) {
187bc58f211SShawn Lin 		*val = readl(addr);
188bc58f211SShawn Lin 	} else if (size == 2) {
189bc58f211SShawn Lin 		*val = readw(addr);
190bc58f211SShawn Lin 	} else if (size == 1) {
191bc58f211SShawn Lin 		*val = readb(addr);
192bc58f211SShawn Lin 	} else {
193bc58f211SShawn Lin 		*val = 0;
194bc58f211SShawn Lin 		return PCIBIOS_NODEV;
195bc58f211SShawn Lin 	}
196bc58f211SShawn Lin 
197bc58f211SShawn Lin 	return PCIBIOS_SUCCESSFUL;
198bc58f211SShawn Lin }
199bc58f211SShawn Lin 
rk_pcie_write(void __iomem * addr,int size,u32 val)200bc58f211SShawn Lin static int rk_pcie_write(void __iomem *addr, int size, u32 val)
201bc58f211SShawn Lin {
202bc58f211SShawn Lin 	if ((uintptr_t)addr & (size - 1))
203bc58f211SShawn Lin 		return PCIBIOS_UNSUPPORTED;
204bc58f211SShawn Lin 
205bc58f211SShawn Lin 	if (size == 4)
206bc58f211SShawn Lin 		writel(val, addr);
207bc58f211SShawn Lin 	else if (size == 2)
208bc58f211SShawn Lin 		writew(val, addr);
209bc58f211SShawn Lin 	else if (size == 1)
210bc58f211SShawn Lin 		writeb(val, addr);
211bc58f211SShawn Lin 	else
212bc58f211SShawn Lin 		return PCIBIOS_NODEV;
213bc58f211SShawn Lin 
214bc58f211SShawn Lin 	return PCIBIOS_SUCCESSFUL;
215bc58f211SShawn Lin }
216bc58f211SShawn Lin 
__rk_pcie_read_apb(struct rk_pcie * rk_pcie,void __iomem * base,u32 reg,size_t size)217bc58f211SShawn Lin static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
218bc58f211SShawn Lin 			      u32 reg, size_t size)
219bc58f211SShawn Lin {
220bc58f211SShawn Lin 	int ret;
221bc58f211SShawn Lin 	u32 val;
222bc58f211SShawn Lin 
223bc58f211SShawn Lin 	ret = rk_pcie_read(base + reg, size, &val);
224bc58f211SShawn Lin 	if (ret)
2250e16653bSJon Lin 		dev_err(rk_pcie->dev, "Read APB address failed\n");
226bc58f211SShawn Lin 
227bc58f211SShawn Lin 	return val;
228bc58f211SShawn Lin }
229bc58f211SShawn Lin 
__rk_pcie_write_apb(struct rk_pcie * rk_pcie,void __iomem * base,u32 reg,size_t size,u32 val)230bc58f211SShawn Lin static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
231bc58f211SShawn Lin 				u32 reg, size_t size, u32 val)
232bc58f211SShawn Lin {
233bc58f211SShawn Lin 	int ret;
234bc58f211SShawn Lin 
235bc58f211SShawn Lin 	ret = rk_pcie_write(base + reg, size, val);
236bc58f211SShawn Lin 	if (ret)
2370e16653bSJon Lin 		dev_err(rk_pcie->dev, "Write APB address failed\n");
238bc58f211SShawn Lin }
239bc58f211SShawn Lin 
rk_pcie_readl_apb(struct rk_pcie * rk_pcie,u32 reg)240bc58f211SShawn Lin static inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg)
241bc58f211SShawn Lin {
242bc58f211SShawn Lin 	return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4);
243bc58f211SShawn Lin }
244bc58f211SShawn Lin 
rk_pcie_writel_apb(struct rk_pcie * rk_pcie,u32 reg,u32 val)245bc58f211SShawn Lin static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
246bc58f211SShawn Lin 				      u32 val)
247bc58f211SShawn Lin {
248bc58f211SShawn Lin 	__rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
249bc58f211SShawn Lin }
250bc58f211SShawn Lin 
rk_pci_find_ext_capability(struct rk_pcie * rk_pcie,int cap)251*7ece1cfeSJon Lin static int rk_pci_find_ext_capability(struct rk_pcie *rk_pcie, int cap)
252*7ece1cfeSJon Lin {
253*7ece1cfeSJon Lin 	u32 header;
254*7ece1cfeSJon Lin 	int ttl;
255*7ece1cfeSJon Lin 	int start = 0;
256*7ece1cfeSJon Lin 	int pos = PCI_CFG_SPACE_SIZE;
257*7ece1cfeSJon Lin 
258*7ece1cfeSJon Lin 	/* minimum 8 bytes per capability */
259*7ece1cfeSJon Lin 	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
260*7ece1cfeSJon Lin 
261*7ece1cfeSJon Lin 	header = readl(rk_pcie->dbi_base + pos);
262*7ece1cfeSJon Lin 
263*7ece1cfeSJon Lin 	/*
264*7ece1cfeSJon Lin 	 * If we have no capabilities, this is indicated by cap ID,
265*7ece1cfeSJon Lin 	 * cap version and next pointer all being 0.
266*7ece1cfeSJon Lin 	 */
267*7ece1cfeSJon Lin 	if (header == 0)
268*7ece1cfeSJon Lin 		return 0;
269*7ece1cfeSJon Lin 
270*7ece1cfeSJon Lin 	while (ttl-- > 0) {
271*7ece1cfeSJon Lin 		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
272*7ece1cfeSJon Lin 			return pos;
273*7ece1cfeSJon Lin 
274*7ece1cfeSJon Lin 		pos = PCI_EXT_CAP_NEXT(header);
275*7ece1cfeSJon Lin 		if (pos < PCI_CFG_SPACE_SIZE)
276*7ece1cfeSJon Lin 			break;
277*7ece1cfeSJon Lin 
278*7ece1cfeSJon Lin 		header = readl(rk_pcie->dbi_base + pos);
279*7ece1cfeSJon Lin 		if (!header)
280*7ece1cfeSJon Lin 			break;
281*7ece1cfeSJon Lin 	}
282*7ece1cfeSJon Lin 
283*7ece1cfeSJon Lin 	return 0;
284*7ece1cfeSJon Lin }
285*7ece1cfeSJon Lin 
rk_pcie_get_link_speed(struct rk_pcie * rk_pcie)286bc58f211SShawn Lin static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie)
287bc58f211SShawn Lin {
288bc58f211SShawn Lin 	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
289bc58f211SShawn Lin 		PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
290bc58f211SShawn Lin }
291bc58f211SShawn Lin 
rk_pcie_get_link_width(struct rk_pcie * rk_pcie)292bc58f211SShawn Lin static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie)
293bc58f211SShawn Lin {
294bc58f211SShawn Lin 	return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
295bc58f211SShawn Lin 		PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
296bc58f211SShawn Lin }
297bc58f211SShawn Lin 
rk_pcie_writel_ob_unroll(struct rk_pcie * rk_pcie,u32 index,u32 reg,u32 val)298bc58f211SShawn Lin static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index,
299bc58f211SShawn Lin 				     u32 reg, u32 val)
300bc58f211SShawn Lin {
301bc58f211SShawn Lin 	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
302bc58f211SShawn Lin 	void __iomem *base = rk_pcie->dbi_base;
303bc58f211SShawn Lin 
304bc58f211SShawn Lin 	writel(val, base + offset + reg);
305bc58f211SShawn Lin }
306bc58f211SShawn Lin 
rk_pcie_readl_ob_unroll(struct rk_pcie * rk_pcie,u32 index,u32 reg)307bc58f211SShawn Lin static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg)
308bc58f211SShawn Lin {
309bc58f211SShawn Lin 	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
310bc58f211SShawn Lin 	void __iomem *base = rk_pcie->dbi_base;
311bc58f211SShawn Lin 
312bc58f211SShawn Lin 	return readl(base + offset + reg);
313bc58f211SShawn Lin }
314bc58f211SShawn Lin 
rk_pcie_dbi_write_enable(struct rk_pcie * rk_pcie,bool en)315bc58f211SShawn Lin static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en)
316bc58f211SShawn Lin {
317bc58f211SShawn Lin 	u32 val;
318bc58f211SShawn Lin 
319bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
320bc58f211SShawn Lin 
321bc58f211SShawn Lin 	if (en)
322bc58f211SShawn Lin 		val |= PCIE_DBI_RO_WR_EN;
323bc58f211SShawn Lin 	else
324bc58f211SShawn Lin 		val &= ~PCIE_DBI_RO_WR_EN;
325bc58f211SShawn Lin 	writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
326bc58f211SShawn Lin }
327bc58f211SShawn Lin 
rk_pcie_setup_host(struct rk_pcie * rk_pcie)328bc58f211SShawn Lin static void rk_pcie_setup_host(struct rk_pcie *rk_pcie)
329bc58f211SShawn Lin {
330bc58f211SShawn Lin 	u32 val;
331bc58f211SShawn Lin 
332bc58f211SShawn Lin 	rk_pcie_dbi_write_enable(rk_pcie, true);
333bc58f211SShawn Lin 
334bc58f211SShawn Lin 	/* setup RC BARs */
335bc58f211SShawn Lin 	writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
336bc58f211SShawn Lin 	       rk_pcie->dbi_base + PCI_BASE_ADDRESS_0);
337bc58f211SShawn Lin 	writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1);
338bc58f211SShawn Lin 
339bc58f211SShawn Lin 	/* setup interrupt pins */
340bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCI_INTERRUPT_LINE);
341bc58f211SShawn Lin 	val &= 0xffff00ff;
342bc58f211SShawn Lin 	val |= 0x00000100;
343bc58f211SShawn Lin 	writel(val, rk_pcie->dbi_base + PCI_INTERRUPT_LINE);
344bc58f211SShawn Lin 
345bc58f211SShawn Lin 	/* setup bus numbers */
346bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCI_PRIMARY_BUS);
347bc58f211SShawn Lin 	val &= 0xff000000;
348bc58f211SShawn Lin 	val |= 0x00ff0100;
349bc58f211SShawn Lin 	writel(val, rk_pcie->dbi_base + PCI_PRIMARY_BUS);
350bc58f211SShawn Lin 
351bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCI_PRIMARY_BUS);
352bc58f211SShawn Lin 
353bc58f211SShawn Lin 	/* setup command register */
354bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCI_COMMAND);
355bc58f211SShawn Lin 	val &= 0xffff0000;
356bc58f211SShawn Lin 	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
357bc58f211SShawn Lin 		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
358bc58f211SShawn Lin 	writel(val, rk_pcie->dbi_base + PCI_COMMAND);
359bc58f211SShawn Lin 
360bc58f211SShawn Lin 	/* program correct class for RC */
361bc58f211SShawn Lin 	writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE);
362bc58f211SShawn Lin 	/* Better disable write permission right after the update */
363bc58f211SShawn Lin 
364bc58f211SShawn Lin 	val = readl(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
365bc58f211SShawn Lin 	val |= PORT_LOGIC_SPEED_CHANGE;
366bc58f211SShawn Lin 	writel(val, rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
367bc58f211SShawn Lin 
3681f452320SJon Lin 	/* Disable BAR0 BAR1 */
3691f452320SJon Lin 	writel(0, rk_pcie->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + 0 * 4);
3701f452320SJon Lin 	writel(0, rk_pcie->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + 1 * 4);
3711f452320SJon Lin 
372bc58f211SShawn Lin 	rk_pcie_dbi_write_enable(rk_pcie, false);
373bc58f211SShawn Lin }
374bc58f211SShawn Lin 
rk_pcie_configure(struct rk_pcie * pci,u32 cap_speed,u32 cap_lanes)375b8495bb7SShawn Lin static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed, u32 cap_lanes)
376bc58f211SShawn Lin {
377bc58f211SShawn Lin 	u32 val;
378bc58f211SShawn Lin 
379bc58f211SShawn Lin 	rk_pcie_dbi_write_enable(pci, true);
380bc58f211SShawn Lin 
381bc58f211SShawn Lin 	val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY);
382bc58f211SShawn Lin 	val &= ~TARGET_LINK_SPEED_MASK;
383bc58f211SShawn Lin 	val |= cap_speed;
384bc58f211SShawn Lin 	writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY);
385bc58f211SShawn Lin 
386bc58f211SShawn Lin 	val = readl(pci->dbi_base + PCIE_LINK_CTL_2);
387bc58f211SShawn Lin 	val &= ~TARGET_LINK_SPEED_MASK;
388bc58f211SShawn Lin 	val |= cap_speed;
389bc58f211SShawn Lin 	writel(val, pci->dbi_base + PCIE_LINK_CTL_2);
390bc58f211SShawn Lin 
391b8495bb7SShawn Lin 	val = readl(pci->dbi_base + PCIE_PORT_LINK_CONTROL);
392b8495bb7SShawn Lin 
393b8495bb7SShawn Lin         /* Set the number of lanes */
394b8495bb7SShawn Lin         val &= ~PORT_LINK_FAST_LINK_MODE;
395b8495bb7SShawn Lin         val &= ~PORT_LINK_MODE_MASK;
396b8495bb7SShawn Lin 	switch (cap_lanes) {
397b8495bb7SShawn Lin 	case 1:
398b8495bb7SShawn Lin 		val |= PORT_LINK_MODE_1_LANES;
399b8495bb7SShawn Lin 		break;
400b8495bb7SShawn Lin 	case 2:
401b8495bb7SShawn Lin 		val |= PORT_LINK_MODE_2_LANES;
402b8495bb7SShawn Lin 		break;
403b8495bb7SShawn Lin 	case 4:
404b8495bb7SShawn Lin 		val |= PORT_LINK_MODE_4_LANES;
405b8495bb7SShawn Lin 		break;
406b8495bb7SShawn Lin 	case 8:
407b8495bb7SShawn Lin 		val |= PORT_LINK_MODE_8_LANES;
408b8495bb7SShawn Lin 		break;
409b8495bb7SShawn Lin 	default:
410b8495bb7SShawn Lin 		dev_err(pci->dev, "cap_lanes %u: invalid value\n", cap_lanes);
411b8495bb7SShawn Lin 		return;
412b8495bb7SShawn Lin 	}
413b8495bb7SShawn Lin 	writel(val, pci->dbi_base + PCIE_PORT_LINK_CONTROL);
414b8495bb7SShawn Lin 
415b8495bb7SShawn Lin 	/* Set link width speed control register */
416b8495bb7SShawn Lin 	val = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
417b8495bb7SShawn Lin 	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
418b8495bb7SShawn Lin 	switch (cap_lanes) {
419b8495bb7SShawn Lin 	case 1:
420b8495bb7SShawn Lin 		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
421b8495bb7SShawn Lin 		break;
422b8495bb7SShawn Lin 	case 2:
423b8495bb7SShawn Lin 		val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
424b8495bb7SShawn Lin 		break;
425b8495bb7SShawn Lin 	case 4:
426b8495bb7SShawn Lin 		val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
427b8495bb7SShawn Lin 		break;
428b8495bb7SShawn Lin 	case 8:
429b8495bb7SShawn Lin 		val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
430b8495bb7SShawn Lin 		break;
431b8495bb7SShawn Lin 	}
432b8495bb7SShawn Lin 	writel(val, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
433b8495bb7SShawn Lin 
434bc58f211SShawn Lin 	rk_pcie_dbi_write_enable(pci, false);
435bc58f211SShawn Lin }
436bc58f211SShawn Lin 
rk_pcie_prog_outbound_atu_unroll(struct rk_pcie * pci,int index,int type,u64 cpu_addr,u64 pci_addr,u32 size)437bc58f211SShawn Lin static void rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index,
438bc58f211SShawn Lin 					     int type, u64 cpu_addr,
439bc58f211SShawn Lin 					     u64 pci_addr, u32 size)
440bc58f211SShawn Lin {
441bc58f211SShawn Lin 	u32 retries, val;
442bc58f211SShawn Lin 
443bc58f211SShawn Lin 	dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
444bc58f211SShawn Lin 		index, type, cpu_addr, pci_addr, size);
445bc58f211SShawn Lin 
446bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
447bc58f211SShawn Lin 				 lower_32_bits(cpu_addr));
448bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
449bc58f211SShawn Lin 				 upper_32_bits(cpu_addr));
450bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
451bc58f211SShawn Lin 				 lower_32_bits(cpu_addr + size - 1));
452bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
453bc58f211SShawn Lin 				 lower_32_bits(pci_addr));
454bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
455bc58f211SShawn Lin 				 upper_32_bits(pci_addr));
456bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
457bc58f211SShawn Lin 				 type);
458bc58f211SShawn Lin 	rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
459bc58f211SShawn Lin 				 PCIE_ATU_ENABLE);
460bc58f211SShawn Lin 
461bc58f211SShawn Lin 	/*
462bc58f211SShawn Lin 	 * Make sure ATU enable takes effect before any subsequent config
463bc58f211SShawn Lin 	 * and I/O accesses.
464bc58f211SShawn Lin 	 */
465bc58f211SShawn Lin 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
466bc58f211SShawn Lin 		val = rk_pcie_readl_ob_unroll(pci, index,
467bc58f211SShawn Lin 					      PCIE_ATU_UNR_REGION_CTRL2);
468bc58f211SShawn Lin 		if (val & PCIE_ATU_ENABLE)
469bc58f211SShawn Lin 			return;
470bc58f211SShawn Lin 
471bc58f211SShawn Lin 		udelay(LINK_WAIT_IATU);
472bc58f211SShawn Lin 	}
473bc58f211SShawn Lin 	dev_err(pci->dev, "outbound iATU is not being enabled\n");
474bc58f211SShawn Lin }
475bc58f211SShawn Lin 
rk_pcie_addr_valid(pci_dev_t d,int first_busno)476bc58f211SShawn Lin static int rk_pcie_addr_valid(pci_dev_t d, int first_busno)
477bc58f211SShawn Lin {
478bc58f211SShawn Lin 	if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
479bc58f211SShawn Lin 		return 0;
480bc58f211SShawn Lin 	if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
481bc58f211SShawn Lin 		return 0;
482bc58f211SShawn Lin 
483bc58f211SShawn Lin 	return 1;
484bc58f211SShawn Lin }
485bc58f211SShawn Lin 
set_cfg_address(struct rk_pcie * pcie,pci_dev_t d,uint where)486bc58f211SShawn Lin static uintptr_t set_cfg_address(struct rk_pcie *pcie,
487bc58f211SShawn Lin 				 pci_dev_t d, uint where)
488bc58f211SShawn Lin {
489bc58f211SShawn Lin 	int bus = PCI_BUS(d) - pcie->first_busno;
490bc58f211SShawn Lin 	uintptr_t va_address;
491bc58f211SShawn Lin 	u32 atu_type;
492bc58f211SShawn Lin 
493bc58f211SShawn Lin 	/* Use dbi_base for own configuration read and write */
494bc58f211SShawn Lin 	if (!bus) {
495bc58f211SShawn Lin 		va_address = (uintptr_t)pcie->dbi_base;
496bc58f211SShawn Lin 		goto out;
497bc58f211SShawn Lin 	}
498bc58f211SShawn Lin 
499bc58f211SShawn Lin 	if (bus == 1)
500bc58f211SShawn Lin 		/*
501bc58f211SShawn Lin 		 * For local bus whose primary bus number is root bridge,
502bc58f211SShawn Lin 		 * change TLP Type field to 4.
503bc58f211SShawn Lin 		 */
504bc58f211SShawn Lin 		atu_type = PCIE_ATU_TYPE_CFG0;
505bc58f211SShawn Lin 	else
506bc58f211SShawn Lin 		/* Otherwise, change TLP Type field to 5. */
507bc58f211SShawn Lin 		atu_type = PCIE_ATU_TYPE_CFG1;
508bc58f211SShawn Lin 
509bc58f211SShawn Lin 	/*
510bc58f211SShawn Lin 	 * Not accessing root port configuration space?
511bc58f211SShawn Lin 	 * Region #0 is used for Outbound CFG space access.
512bc58f211SShawn Lin 	 * Direction = Outbound
513bc58f211SShawn Lin 	 * Region Index = 0
514bc58f211SShawn Lin 	 */
515bc58f211SShawn Lin 	d = PCI_MASK_BUS(d);
516bc58f211SShawn Lin 	d = PCI_ADD_BUS(bus, d);
517bc58f211SShawn Lin 	rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
518bc58f211SShawn Lin 					 atu_type, (u64)pcie->cfg_base,
519bc58f211SShawn Lin 					 d << 8, pcie->cfg_size);
520bc58f211SShawn Lin 
521bc58f211SShawn Lin 	va_address = (uintptr_t)pcie->cfg_base;
522bc58f211SShawn Lin 
523bc58f211SShawn Lin out:
524bc58f211SShawn Lin 	va_address += where & ~0x3;
525bc58f211SShawn Lin 
526bc58f211SShawn Lin 	return va_address;
527bc58f211SShawn Lin }
528bc58f211SShawn Lin 
rockchip_pcie_rd_conf(struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)529bc58f211SShawn Lin static int rockchip_pcie_rd_conf(struct udevice *bus, pci_dev_t bdf,
530bc58f211SShawn Lin 				 uint offset, ulong *valuep,
531bc58f211SShawn Lin 				 enum pci_size_t size)
532bc58f211SShawn Lin {
533bc58f211SShawn Lin 	struct rk_pcie *pcie = dev_get_priv(bus);
534bc58f211SShawn Lin 	uintptr_t va_address;
535bc58f211SShawn Lin 	ulong value;
536bc58f211SShawn Lin 
537bc58f211SShawn Lin 	debug("PCIE CFG read: bdf=%2x:%2x:%2x\n",
538bc58f211SShawn Lin 	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
539bc58f211SShawn Lin 
540bc58f211SShawn Lin 	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
541bc58f211SShawn Lin 		debug("- out of range\n");
542bc58f211SShawn Lin 		*valuep = pci_get_ff(size);
543bc58f211SShawn Lin 		return 0;
544bc58f211SShawn Lin 	}
545bc58f211SShawn Lin 
546bc58f211SShawn Lin 	va_address = set_cfg_address(pcie, bdf, offset);
547bc58f211SShawn Lin 
548bc58f211SShawn Lin 	value = readl(va_address);
549bc58f211SShawn Lin 
550bc58f211SShawn Lin 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
551bc58f211SShawn Lin 	*valuep = pci_conv_32_to_size(value, offset, size);
552bc58f211SShawn Lin 
553bc58f211SShawn Lin 	rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
554bc58f211SShawn Lin 					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
555bc58f211SShawn Lin 					 pcie->io.bus_start, pcie->io.size);
556bc58f211SShawn Lin 
557bc58f211SShawn Lin 	return 0;
558bc58f211SShawn Lin }
559bc58f211SShawn Lin 
rockchip_pcie_wr_conf(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)560bc58f211SShawn Lin static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf,
561bc58f211SShawn Lin 				 uint offset, ulong value,
562bc58f211SShawn Lin 				 enum pci_size_t size)
563bc58f211SShawn Lin {
564bc58f211SShawn Lin 	struct rk_pcie *pcie = dev_get_priv(bus);
565bc58f211SShawn Lin 	uintptr_t va_address;
566bc58f211SShawn Lin 	ulong old;
567bc58f211SShawn Lin 
568bc58f211SShawn Lin 	debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n",
569bc58f211SShawn Lin 	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
570bc58f211SShawn Lin 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
571bc58f211SShawn Lin 	if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
572bc58f211SShawn Lin 		debug("- out of range\n");
573bc58f211SShawn Lin 		return 0;
574bc58f211SShawn Lin 	}
575bc58f211SShawn Lin 
576bc58f211SShawn Lin 	va_address = set_cfg_address(pcie, bdf, offset);
577bc58f211SShawn Lin 
578bc58f211SShawn Lin 	old = readl(va_address);
579bc58f211SShawn Lin 	value = pci_conv_size_to_32(old, value, offset, size);
580bc58f211SShawn Lin 	writel(value, va_address);
581bc58f211SShawn Lin 
582bc58f211SShawn Lin 	rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
583bc58f211SShawn Lin 					 PCIE_ATU_TYPE_IO, pcie->io.phys_start,
584bc58f211SShawn Lin 					 pcie->io.bus_start, pcie->io.size);
585bc58f211SShawn Lin 
586bc58f211SShawn Lin 	return 0;
587bc58f211SShawn Lin }
588bc58f211SShawn Lin 
rk_pcie_enable_debug(struct rk_pcie * rk_pcie)589bc58f211SShawn Lin static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
590bc58f211SShawn Lin {
591bc58f211SShawn Lin #if RK_PCIE_DBG
592bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0,
593bc58f211SShawn Lin 			   PCIE_CLIENT_DBG_TRANSITION_DATA);
594bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1,
595bc58f211SShawn Lin 			   PCIE_CLIENT_DBG_TRANSITION_DATA);
596bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0,
597bc58f211SShawn Lin 			   PCIE_CLIENT_DBG_TRANSITION_DATA);
598bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1,
599bc58f211SShawn Lin 			   PCIE_CLIENT_DBG_TRANSITION_DATA);
600bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON,
601bc58f211SShawn Lin 			   PCIE_CLIENT_DBF_EN);
602bc58f211SShawn Lin #endif
603bc58f211SShawn Lin }
604bc58f211SShawn Lin 
rk_pcie_debug_dump(struct rk_pcie * rk_pcie)605bc58f211SShawn Lin static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie)
606bc58f211SShawn Lin {
607bc58f211SShawn Lin #if RK_PCIE_DBG
608bc58f211SShawn Lin 	u32 loop;
609bc58f211SShawn Lin 
6100e16653bSJon Lin 	dev_err(rk_pcie->dev, "ltssm = 0x%x\n",
611bc58f211SShawn Lin 		 rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
612bc58f211SShawn Lin 	for (loop = 0; loop < 64; loop++)
6130e16653bSJon Lin 		dev_err(rk_pcie->dev, "fifo_status = 0x%x\n",
614bc58f211SShawn Lin 			 rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS));
615bc58f211SShawn Lin #endif
616bc58f211SShawn Lin }
617bc58f211SShawn Lin 
rk_pcie_link_status_clear(struct rk_pcie * rk_pcie)618bc58f211SShawn Lin static inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie)
619bc58f211SShawn Lin {
620bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0);
621bc58f211SShawn Lin }
622bc58f211SShawn Lin 
rk_pcie_disable_ltssm(struct rk_pcie * rk_pcie)623bc58f211SShawn Lin static inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie)
624bc58f211SShawn Lin {
625bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008);
626bc58f211SShawn Lin }
627bc58f211SShawn Lin 
rk_pcie_enable_ltssm(struct rk_pcie * rk_pcie)628bc58f211SShawn Lin static inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie)
629bc58f211SShawn Lin {
630bc58f211SShawn Lin 	rk_pcie_writel_apb(rk_pcie, 0x0, 0xc000c);
631bc58f211SShawn Lin }
632bc58f211SShawn Lin 
is_link_up(struct rk_pcie * priv)633bc58f211SShawn Lin static int is_link_up(struct rk_pcie *priv)
634bc58f211SShawn Lin {
635bc58f211SShawn Lin 	u32 val;
636bc58f211SShawn Lin 
637bc58f211SShawn Lin 	val = rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS);
638bc58f211SShawn Lin 	if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000 &&
639bc58f211SShawn Lin 	    (val & GENMASK(5, 0)) == 0x11)
640bc58f211SShawn Lin 		return 1;
641bc58f211SShawn Lin 
642bc58f211SShawn Lin 	return 0;
643bc58f211SShawn Lin }
644bc58f211SShawn Lin 
rk_pcie_link_up(struct rk_pcie * priv,u32 cap_speed,u32 cap_lanes)645b8495bb7SShawn Lin static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed, u32 cap_lanes)
646bc58f211SShawn Lin {
647bc58f211SShawn Lin 	int retries;
648bc58f211SShawn Lin 
649bc58f211SShawn Lin 	if (is_link_up(priv)) {
650bc58f211SShawn Lin 		printf("PCI Link already up before configuration!\n");
651bc58f211SShawn Lin 		return 1;
652bc58f211SShawn Lin 	}
653bc58f211SShawn Lin 
654bc58f211SShawn Lin 	/* DW pre link configurations */
655b8495bb7SShawn Lin 	rk_pcie_configure(priv, cap_speed, cap_lanes);
656bc58f211SShawn Lin 
65792d35878SJon Lin 	/* Release the device */
6586d508927SJon Lin 	if (dm_gpio_is_valid(&priv->rst_gpio)) {
6596d508927SJon Lin 		/*
6606d508927SJon Lin 		 * T_PVPERL (Power stable to PERST# inactive) should be a minimum of 100ms.
6616d508927SJon Lin 		 * We add a 200ms by default for sake of hoping everthings
6626d508927SJon Lin 		 * work fine.
6636d508927SJon Lin 		 */
6646d508927SJon Lin 		msleep(200);
665bc58f211SShawn Lin 		dm_gpio_set_value(&priv->rst_gpio, 1);
6666d508927SJon Lin 		/*
6676d508927SJon Lin 		 * Add this 20ms delay because we observe link is always up stably after it and
6686d508927SJon Lin 		 * could help us save 20ms for scanning devices.
6696d508927SJon Lin 		 */
6706d508927SJon Lin 		msleep(20);
6716d508927SJon Lin 	}
672bc58f211SShawn Lin 
673bc58f211SShawn Lin 	rk_pcie_disable_ltssm(priv);
674bc58f211SShawn Lin 	rk_pcie_link_status_clear(priv);
675bc58f211SShawn Lin 	rk_pcie_enable_debug(priv);
676bc58f211SShawn Lin 
677bc58f211SShawn Lin 	/* Enable LTSSM */
678bc58f211SShawn Lin 	rk_pcie_enable_ltssm(priv);
679bc58f211SShawn Lin 
680beef0f23SShawn Lin 	for (retries = 0; retries < 50; retries++) {
681bc58f211SShawn Lin 		if (is_link_up(priv)) {
682bc58f211SShawn Lin 			dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n",
683bc58f211SShawn Lin 				 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
684bc58f211SShawn Lin 			rk_pcie_debug_dump(priv);
685ff2f1e41SShawn Lin 			/* Link maybe in Gen switch recovery but we need to wait more 1s */
686ff2f1e41SShawn Lin 			msleep(1000);
687bc58f211SShawn Lin 			return 0;
688bc58f211SShawn Lin 		}
689bc58f211SShawn Lin 
690bc58f211SShawn Lin 		dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n",
691bc58f211SShawn Lin 			 rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
692bc58f211SShawn Lin 		rk_pcie_debug_dump(priv);
69392d35878SJon Lin 		msleep(10);
694bc58f211SShawn Lin 	}
695bc58f211SShawn Lin 
696bc58f211SShawn Lin 	dev_err(priv->dev, "PCIe-%d Link Fail\n", priv->dev->seq);
697b2a4eeb5SShawn Lin 	rk_pcie_disable_ltssm(priv);
698fec7a75eSShawn Lin 	if (dm_gpio_is_valid(&priv->rst_gpio))
699fec7a75eSShawn Lin 		dm_gpio_set_value(&priv->rst_gpio, 0);
700fec7a75eSShawn Lin 
701bc58f211SShawn Lin 	return -EINVAL;
702bc58f211SShawn Lin }
703bc58f211SShawn Lin 
rockchip_pcie_init_port(struct udevice * dev)704bc58f211SShawn Lin static int rockchip_pcie_init_port(struct udevice *dev)
705bc58f211SShawn Lin {
706fec7a75eSShawn Lin 	int ret, retries;
707bc58f211SShawn Lin 	u32 val;
708bc58f211SShawn Lin 	struct rk_pcie *priv = dev_get_priv(dev);
709c2482762SShawn Lin 	union phy_configure_opts phy_cfg;
710bc58f211SShawn Lin 
71192d35878SJon Lin 	/* Rest the device */
71292d35878SJon Lin 	if (dm_gpio_is_valid(&priv->rst_gpio))
71392d35878SJon Lin 		dm_gpio_set_value(&priv->rst_gpio, 0);
71492d35878SJon Lin 
715bc58f211SShawn Lin 	/* Set power and maybe external ref clk input */
716bc58f211SShawn Lin 	if (priv->vpcie3v3) {
71732aabf13SJon Lin 		ret = regulator_set_enable(priv->vpcie3v3, true);
718bc58f211SShawn Lin 		if (ret) {
719bc58f211SShawn Lin 			dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n",
720bc58f211SShawn Lin 				ret);
721bc58f211SShawn Lin 			return ret;
722bc58f211SShawn Lin 		}
723bc58f211SShawn Lin 	}
724bc58f211SShawn Lin 
725c2482762SShawn Lin 	if (priv->is_bifurcation) {
726c2482762SShawn Lin 		phy_cfg.pcie.is_bifurcation = true;
727c2482762SShawn Lin 		ret = generic_phy_configure(&priv->phy, &phy_cfg);
728c2482762SShawn Lin 		if (ret)
729c2482762SShawn Lin 			dev_err(dev, "failed to set bifurcation for phy (ret=%d)\n", ret);
730c2482762SShawn Lin 	}
731c2482762SShawn Lin 
732bc58f211SShawn Lin 	ret = generic_phy_init(&priv->phy);
733bc58f211SShawn Lin 	if (ret) {
734bc58f211SShawn Lin 		dev_err(dev, "failed to init phy (ret=%d)\n", ret);
735b2a4eeb5SShawn Lin 		goto err_disable_3v3;
736bc58f211SShawn Lin 	}
737bc58f211SShawn Lin 
738bc58f211SShawn Lin 	ret = generic_phy_power_on(&priv->phy);
739bc58f211SShawn Lin 	if (ret) {
740bc58f211SShawn Lin 		dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
741bc58f211SShawn Lin 		goto err_exit_phy;
742bc58f211SShawn Lin 	}
743bc58f211SShawn Lin 
744bc58f211SShawn Lin 	ret = reset_deassert_bulk(&priv->rsts);
745bc58f211SShawn Lin 	if (ret) {
746bc58f211SShawn Lin 		dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
747bc58f211SShawn Lin 		goto err_power_off_phy;
748bc58f211SShawn Lin 	}
749bc58f211SShawn Lin 
750bc58f211SShawn Lin 	ret = clk_enable_bulk(&priv->clks);
751bc58f211SShawn Lin 	if (ret) {
752bc58f211SShawn Lin 		dev_err(dev, "failed to enable clks (ret=%d)\n", ret);
753bc58f211SShawn Lin 		goto err_deassert_bulk;
754bc58f211SShawn Lin 	}
755bc58f211SShawn Lin 
756bc58f211SShawn Lin 	/* LTSSM EN ctrl mode */
757bc58f211SShawn Lin 	val = rk_pcie_readl_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL);
758bc58f211SShawn Lin 	val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16);
759bc58f211SShawn Lin 	rk_pcie_writel_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL, val);
760bc58f211SShawn Lin 
761bc58f211SShawn Lin 	/* Set RC mode */
762bc58f211SShawn Lin 	rk_pcie_writel_apb(priv, 0x0, 0xf00040);
763bc58f211SShawn Lin 	rk_pcie_setup_host(priv);
764bc58f211SShawn Lin 
765fec7a75eSShawn Lin 	for (retries = MAX_LINKUP_RETRIES; retries > 0; retries--) {
766b8495bb7SShawn Lin 		ret = rk_pcie_link_up(priv, priv->gen, priv->lanes);
767fec7a75eSShawn Lin 		if (ret >= 0)
768fec7a75eSShawn Lin 			return 0;
769fec7a75eSShawn Lin 		if(priv->vpcie3v3) {
770fec7a75eSShawn Lin 			regulator_set_enable(priv->vpcie3v3, false);
771fec7a75eSShawn Lin 			msleep(200);
772fec7a75eSShawn Lin 			regulator_set_enable(priv->vpcie3v3, true);
773fec7a75eSShawn Lin 		}
774fec7a75eSShawn Lin 	}
775fec7a75eSShawn Lin 
776fec7a75eSShawn Lin 	if (retries <= 0)
777bc58f211SShawn Lin 		goto err_link_up;
778bc58f211SShawn Lin 
779bc58f211SShawn Lin 	return 0;
780bc58f211SShawn Lin err_link_up:
781bc58f211SShawn Lin 	clk_disable_bulk(&priv->clks);
782bc58f211SShawn Lin err_deassert_bulk:
783bc58f211SShawn Lin 	reset_assert_bulk(&priv->rsts);
784bc58f211SShawn Lin err_power_off_phy:
78568abe0efSShawn Lin 	if (!priv->is_bifurcation)
786bc58f211SShawn Lin 		generic_phy_power_off(&priv->phy);
787bc58f211SShawn Lin err_exit_phy:
78868abe0efSShawn Lin 	if (!priv->is_bifurcation)
789bc58f211SShawn Lin 		generic_phy_exit(&priv->phy);
790b2a4eeb5SShawn Lin err_disable_3v3:
79168abe0efSShawn Lin 	if(priv->vpcie3v3 && !priv->is_bifurcation)
792b2a4eeb5SShawn Lin 		regulator_set_enable(priv->vpcie3v3, false);
793bc58f211SShawn Lin 	return ret;
794bc58f211SShawn Lin }
795bc58f211SShawn Lin 
rockchip_pcie_parse_dt(struct udevice * dev)796bc58f211SShawn Lin static int rockchip_pcie_parse_dt(struct udevice *dev)
797bc58f211SShawn Lin {
798bc58f211SShawn Lin 	struct rk_pcie *priv = dev_get_priv(dev);
799b8495bb7SShawn Lin 	u32 max_link_speed, num_lanes;
800bc58f211SShawn Lin 	int ret;
801fbc8ca74SJon Lin 	struct resource res;
802bc58f211SShawn Lin 
803fbc8ca74SJon Lin 	ret = dev_read_resource_byname(dev, "pcie-dbi", &res);
804fbc8ca74SJon Lin 	if (ret)
805bc58f211SShawn Lin 		return -ENODEV;
806fbc8ca74SJon Lin 	priv->dbi_base = (void *)(res.start);
807bc58f211SShawn Lin 	dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base);
808bc58f211SShawn Lin 
809fbc8ca74SJon Lin 	ret = dev_read_resource_byname(dev, "pcie-apb", &res);
810fbc8ca74SJon Lin 	if (ret)
811bc58f211SShawn Lin 		return -ENODEV;
812fbc8ca74SJon Lin 	priv->apb_base = (void *)(res.start);
813bc58f211SShawn Lin 	dev_dbg(dev, "APB address is 0x%p\n", priv->apb_base);
814bc58f211SShawn Lin 
815bc58f211SShawn Lin 	ret = gpio_request_by_name(dev, "reset-gpios", 0,
816bc58f211SShawn Lin 				   &priv->rst_gpio, GPIOD_IS_OUT);
817bc58f211SShawn Lin 	if (ret) {
818bc58f211SShawn Lin 		dev_err(dev, "failed to find reset-gpios property\n");
819bc58f211SShawn Lin 		return ret;
820bc58f211SShawn Lin 	}
821bc58f211SShawn Lin 
822bc58f211SShawn Lin 	ret = reset_get_bulk(dev, &priv->rsts);
823bc58f211SShawn Lin 	if (ret) {
824bc58f211SShawn Lin 		dev_err(dev, "Can't get reset: %d\n", ret);
825bc58f211SShawn Lin 		return ret;
826bc58f211SShawn Lin 	}
827bc58f211SShawn Lin 
828bc58f211SShawn Lin 	ret = clk_get_bulk(dev, &priv->clks);
829bc58f211SShawn Lin 	if (ret) {
830bc58f211SShawn Lin 		dev_err(dev, "Can't get clock: %d\n", ret);
831bc58f211SShawn Lin 		return ret;
832bc58f211SShawn Lin 	}
833bc58f211SShawn Lin 
834bc58f211SShawn Lin 	ret = device_get_supply_regulator(dev, "vpcie3v3-supply",
835bc58f211SShawn Lin 					  &priv->vpcie3v3);
836bc58f211SShawn Lin 	if (ret && ret != -ENOENT) {
837bc58f211SShawn Lin 		dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret);
838bc58f211SShawn Lin 		return ret;
839bc58f211SShawn Lin 	}
840bc58f211SShawn Lin 
841bc58f211SShawn Lin 	ret = generic_phy_get_by_index(dev, 0, &priv->phy);
842bc58f211SShawn Lin 	if (ret) {
843bc58f211SShawn Lin 		dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
844bc58f211SShawn Lin 		return ret;
845bc58f211SShawn Lin 	}
846bc58f211SShawn Lin 
847c2482762SShawn Lin 	if (dev_read_bool(dev, "rockchip,bifurcation"))
848c2482762SShawn Lin 		priv->is_bifurcation = true;
849c2482762SShawn Lin 
850abcec002SJon Lin 	ret = ofnode_read_u32(dev->node, "max-link-speed", &max_link_speed);
851abcec002SJon Lin 	if (ret < 0 || max_link_speed > 4)
852abcec002SJon Lin 		priv->gen = 0;
853abcec002SJon Lin 	else
854abcec002SJon Lin 		priv->gen = max_link_speed;
855abcec002SJon Lin 
856b8495bb7SShawn Lin 	ret = ofnode_read_u32(dev->node, "num-lanes", &num_lanes);
857b8495bb7SShawn Lin 	if (ret >= 0 && ilog2(num_lanes) >= 0 && ilog2(num_lanes) <= 3)
858b8495bb7SShawn Lin 		priv->lanes = num_lanes;
859b8495bb7SShawn Lin 
860bc58f211SShawn Lin 	return 0;
861bc58f211SShawn Lin }
862bc58f211SShawn Lin 
rockchip_pcie_probe(struct udevice * dev)863bc58f211SShawn Lin static int rockchip_pcie_probe(struct udevice *dev)
864bc58f211SShawn Lin {
865bc58f211SShawn Lin 	struct rk_pcie *priv = dev_get_priv(dev);
866bc58f211SShawn Lin 	struct udevice *ctlr = pci_get_controller(dev);
867bc58f211SShawn Lin 	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
868bc58f211SShawn Lin 	int ret;
869bc58f211SShawn Lin 
870bc58f211SShawn Lin 	priv->first_busno = dev->seq;
871bc58f211SShawn Lin 	priv->dev = dev;
872bc58f211SShawn Lin 
873bc58f211SShawn Lin 	ret = rockchip_pcie_parse_dt(dev);
874bc58f211SShawn Lin 	if (ret)
875bc58f211SShawn Lin 		return ret;
876bc58f211SShawn Lin 
877bc58f211SShawn Lin 	ret = rockchip_pcie_init_port(dev);
878bc58f211SShawn Lin 	if (ret)
879b2a4eeb5SShawn Lin 		goto free_rst;
880bc58f211SShawn Lin 
881bc58f211SShawn Lin 	dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
882bc58f211SShawn Lin 		 dev->seq, rk_pcie_get_link_speed(priv),
883bc58f211SShawn Lin 		 rk_pcie_get_link_width(priv),
884bc58f211SShawn Lin 		 hose->first_busno);
885bc58f211SShawn Lin 
886bc58f211SShawn Lin 	for (ret = 0; ret < hose->region_count; ret++) {
887bc58f211SShawn Lin 		if (hose->regions[ret].flags == PCI_REGION_IO) {
888bc58f211SShawn Lin 			priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */
889bc58f211SShawn Lin 			priv->io.bus_start  = hose->regions[ret].bus_start;  /* IO_bus_addr */
890bc58f211SShawn Lin 			priv->io.size       = hose->regions[ret].size;      /* IO size */
891bc58f211SShawn Lin 		} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
8927ff76e75SShawn Lin 			if (upper_32_bits(hose->regions[ret].bus_start)) {/* MEM64 base */
8937ff76e75SShawn Lin 				priv->mem64.phys_start = hose->regions[ret].phys_start;
8947ff76e75SShawn Lin 				priv->mem64.bus_start  = hose->regions[ret].bus_start;
8957ff76e75SShawn Lin 				priv->mem64.size       = hose->regions[ret].size;
8967ff76e75SShawn Lin 			} else { /* MEM32 base */
8977ff76e75SShawn Lin 				priv->mem.phys_start = hose->regions[ret].phys_start;
8987ff76e75SShawn Lin 				priv->mem.bus_start  = hose->regions[ret].bus_start;
8997ff76e75SShawn Lin 				priv->mem.size	     = hose->regions[ret].size;
9007ff76e75SShawn Lin 			}
901bc58f211SShawn Lin 		} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
902bc58f211SShawn Lin 			priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size);
903bc58f211SShawn Lin 			priv->cfg_size = priv->io.size;
9047ff76e75SShawn Lin 		} else if (hose->regions[ret].flags == PCI_REGION_PREFETCH) {
9057ff76e75SShawn Lin 			dev_err(dev, "don't support prefetchable memory, please fix your dtb.\n");
906bc58f211SShawn Lin 		} else {
9077ff76e75SShawn Lin 			dev_err(dev, "invalid flags type\n");
908bc58f211SShawn Lin 		}
909bc58f211SShawn Lin 	}
910bc58f211SShawn Lin 
9117ff76e75SShawn Lin #ifdef CONFIG_SYS_PCI_64BIT
9127ff76e75SShawn Lin 	dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
9137ff76e75SShawn Lin 		priv->cfg_base, priv->cfg_base + priv->cfg_size,
9147ff76e75SShawn Lin 		priv->cfg_size);
9157ff76e75SShawn Lin 
9167ff76e75SShawn Lin 	dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%llx]\n",
9177ff76e75SShawn Lin 		priv->io.phys_start, priv->io.phys_start + priv->io.size,
9187ff76e75SShawn Lin 		priv->io.size);
9197ff76e75SShawn Lin 
9207ff76e75SShawn Lin 	dev_dbg(dev, "IO bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
9217ff76e75SShawn Lin 		priv->io.bus_start, priv->io.bus_start + priv->io.size,
9227ff76e75SShawn Lin 		priv->io.size);
9237ff76e75SShawn Lin 
9247ff76e75SShawn Lin 	dev_dbg(dev, "MEM32 space: [0x%llx - 0x%llx, size 0x%llx]\n",
9257ff76e75SShawn Lin 		priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
9267ff76e75SShawn Lin 		priv->mem.size);
9277ff76e75SShawn Lin 
9287ff76e75SShawn Lin 	dev_dbg(dev, "MEM32 bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
9297ff76e75SShawn Lin 		priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
9307ff76e75SShawn Lin 		priv->mem.size);
9317ff76e75SShawn Lin 
9327ff76e75SShawn Lin 	dev_dbg(dev, "MEM64 space: [0x%llx - 0x%llx, size 0x%llx]\n",
9337ff76e75SShawn Lin 		priv->mem64.phys_start, priv->mem64.phys_start + priv->mem64.size,
9347ff76e75SShawn Lin 		priv->mem64.size);
9357ff76e75SShawn Lin 
9367ff76e75SShawn Lin 	dev_dbg(dev, "MEM64 bus:   [0x%llx - 0x%llx, size 0x%llx]\n",
9377ff76e75SShawn Lin 		priv->mem64.bus_start, priv->mem64.bus_start + priv->mem64.size,
9387ff76e75SShawn Lin 		priv->mem64.size);
9397ff76e75SShawn Lin 
9407ff76e75SShawn Lin 	rk_pcie_prog_outbound_atu_unroll(priv, PCIE_ATU_REGION_INDEX2,
9417ff76e75SShawn Lin 					 PCIE_ATU_TYPE_MEM,
9427ff76e75SShawn Lin 					 priv->mem64.phys_start,
9437ff76e75SShawn Lin 					 priv->mem64.bus_start, priv->mem64.size);
9447ff76e75SShawn Lin #else
945bc58f211SShawn Lin 	dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
946bc58f211SShawn Lin 		priv->cfg_base, priv->cfg_base + priv->cfg_size,
947bc58f211SShawn Lin 		priv->cfg_size);
948bc58f211SShawn Lin 
949bc58f211SShawn Lin 	dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%x]\n",
950bc58f211SShawn Lin 		priv->io.phys_start, priv->io.phys_start + priv->io.size,
951bc58f211SShawn Lin 		priv->io.size);
952bc58f211SShawn Lin 
953bc58f211SShawn Lin 	dev_dbg(dev, "IO bus:   [0x%x - 0x%x, size 0x%x]\n",
954bc58f211SShawn Lin 		priv->io.bus_start, priv->io.bus_start + priv->io.size,
955bc58f211SShawn Lin 		priv->io.size);
956bc58f211SShawn Lin 
9577ff76e75SShawn Lin 	dev_dbg(dev, "MEM32 space: [0x%llx - 0x%llx, size 0x%x]\n",
958bc58f211SShawn Lin 		priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
959bc58f211SShawn Lin 		priv->mem.size);
960bc58f211SShawn Lin 
9617ff76e75SShawn Lin 	dev_dbg(dev, "MEM32 bus:   [0x%x - 0x%x, size 0x%x]\n",
962bc58f211SShawn Lin 		priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
963bc58f211SShawn Lin 		priv->mem.size);
964bc58f211SShawn Lin 
9657ff76e75SShawn Lin #endif
966bc58f211SShawn Lin 	rk_pcie_prog_outbound_atu_unroll(priv, PCIE_ATU_REGION_INDEX0,
967bc58f211SShawn Lin 					 PCIE_ATU_TYPE_MEM,
968bc58f211SShawn Lin 					 priv->mem.phys_start,
969bc58f211SShawn Lin 					 priv->mem.bus_start, priv->mem.size);
9707ff76e75SShawn Lin 
971*7ece1cfeSJon Lin 	priv->rasdes_off = rk_pci_find_ext_capability(priv, PCI_EXT_CAP_ID_VNDR);
972769b1920SShawn Lin 	if (priv->rasdes_off) {
973fbafd477SShawn Lin 		/* Enable RC's err dump */
974769b1920SShawn Lin 		writel(0x1c, priv->dbi_base + priv->rasdes_off + 8);
975769b1920SShawn Lin 		writel(0x3, priv->dbi_base + priv->rasdes_off + 8);
976769b1920SShawn Lin 	}
977fbafd477SShawn Lin 
978bc58f211SShawn Lin 	return 0;
979b2a4eeb5SShawn Lin free_rst:
980b2a4eeb5SShawn Lin 	dm_gpio_free(dev, &priv->rst_gpio);
981b2a4eeb5SShawn Lin 	return ret;
982bc58f211SShawn Lin }
983bc58f211SShawn Lin 
984fbafd477SShawn Lin #define RAS_DES_EVENT(ss, v) \
985fbafd477SShawn Lin do { \
986fbafd477SShawn Lin 	writel(v, priv->dbi_base + cap_base + 8); \
987fbafd477SShawn Lin 	printf(ss "0x%x\n", readl(priv->dbi_base + cap_base + 0xc)); \
988fbafd477SShawn Lin } while (0)
989fbafd477SShawn Lin 
rockchip_pcie_err_dump(struct udevice * bus)990fbafd477SShawn Lin static int rockchip_pcie_err_dump(struct udevice *bus)
991fbafd477SShawn Lin {
992fbafd477SShawn Lin 	struct rk_pcie *priv = dev_get_priv(bus);
993fbafd477SShawn Lin 	u32 val = rk_pcie_readl_apb(priv, PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN);
994fbafd477SShawn Lin 	int cap_base;
995fbafd477SShawn Lin 	char *pm;
996fbafd477SShawn Lin 
997fbafd477SShawn Lin 	if (val & BIT(6))
998fbafd477SShawn Lin 		pm = "In training";
999fbafd477SShawn Lin 	else if (val & BIT(5))
1000fbafd477SShawn Lin 		pm = "L1.2";
1001fbafd477SShawn Lin 	else if (val & BIT(4))
1002fbafd477SShawn Lin 		pm = "L1.1";
1003fbafd477SShawn Lin 	else if (val & BIT(3))
1004fbafd477SShawn Lin 		pm = "L1";
1005fbafd477SShawn Lin 	else if (val & BIT(2))
1006fbafd477SShawn Lin 		pm = "L0";
1007fbafd477SShawn Lin 	else if (val & 0x3)
1008fbafd477SShawn Lin 		pm = (val == 0x3) ? "L0s" : (val & BIT(1) ? "RX L0s" : "TX L0s");
1009fbafd477SShawn Lin 	else
1010fbafd477SShawn Lin 		pm = "Invalid";
1011fbafd477SShawn Lin 
1012fbafd477SShawn Lin 	printf("Common event signal status: %s\n", pm);
1013fbafd477SShawn Lin 
1014769b1920SShawn Lin 	cap_base = priv->rasdes_off;
1015769b1920SShawn Lin 	if (!priv->rasdes_off)
1016769b1920SShawn Lin 		return 0;
1017fbafd477SShawn Lin 
1018fbafd477SShawn Lin 	RAS_DES_EVENT("EBUF Overflow: ", 0);
1019fbafd477SShawn Lin 	RAS_DES_EVENT("EBUF Under-run: ", 0x0010000);
1020fbafd477SShawn Lin 	RAS_DES_EVENT("Decode Error: ", 0x0020000);
1021fbafd477SShawn Lin 	RAS_DES_EVENT("Running Disparity Error: ", 0x0030000);
1022fbafd477SShawn Lin 	RAS_DES_EVENT("SKP OS Parity Error: ", 0x0040000);
1023fbafd477SShawn Lin 	RAS_DES_EVENT("SYNC Header Error: ", 0x0050000);
1024fbafd477SShawn Lin 	RAS_DES_EVENT("CTL SKP OS Parity Error: ", 0x0060000);
1025fbafd477SShawn Lin 	RAS_DES_EVENT("Detect EI Infer: ", 0x1050000);
1026fbafd477SShawn Lin 	RAS_DES_EVENT("Receiver Error: ", 0x1060000);
1027fbafd477SShawn Lin 	RAS_DES_EVENT("Rx Recovery Request: ", 0x1070000);
1028fbafd477SShawn Lin 	RAS_DES_EVENT("N_FTS Timeout: ", 0x1080000);
1029fbafd477SShawn Lin 	RAS_DES_EVENT("Framing Error: ", 0x1090000);
1030fbafd477SShawn Lin 	RAS_DES_EVENT("Deskew Error: ", 0x10a0000);
1031fbafd477SShawn Lin 	RAS_DES_EVENT("BAD TLP: ", 0x2000000);
1032fbafd477SShawn Lin 	RAS_DES_EVENT("LCRC Error: ", 0x2010000);
1033fbafd477SShawn Lin 	RAS_DES_EVENT("BAD DLLP: ", 0x2020000);
1034fbafd477SShawn Lin 	RAS_DES_EVENT("Replay Number Rollover: ", 0x2030000);
1035fbafd477SShawn Lin 	RAS_DES_EVENT("Replay Timeout: ", 0x2040000);
1036fbafd477SShawn Lin 	RAS_DES_EVENT("Rx Nak DLLP: ", 0x2050000);
1037fbafd477SShawn Lin 	RAS_DES_EVENT("Tx Nak DLLP: ", 0x2060000);
1038fbafd477SShawn Lin 	RAS_DES_EVENT("Retry TLP: ", 0x2070000);
1039fbafd477SShawn Lin 	RAS_DES_EVENT("FC Timeout: ", 0x3000000);
1040fbafd477SShawn Lin 	RAS_DES_EVENT("Poisoned TLP: ", 0x3010000);
1041fbafd477SShawn Lin 	RAS_DES_EVENT("ECRC Error: ", 0x3020000);
1042fbafd477SShawn Lin 	RAS_DES_EVENT("Unsupported Request: ", 0x3030000);
1043fbafd477SShawn Lin 	RAS_DES_EVENT("Completer Abort: ", 0x3040000);
1044fbafd477SShawn Lin 	RAS_DES_EVENT("Completion Timeout: ", 0x3050000);
1045fbafd477SShawn Lin 
1046fbafd477SShawn Lin 	return 0;
1047fbafd477SShawn Lin }
1048fbafd477SShawn Lin 
1049bc58f211SShawn Lin static const struct dm_pci_ops rockchip_pcie_ops = {
1050bc58f211SShawn Lin 	.read_config	= rockchip_pcie_rd_conf,
1051bc58f211SShawn Lin 	.write_config	= rockchip_pcie_wr_conf,
1052fbafd477SShawn Lin 	.vendor_aer_dump = rockchip_pcie_err_dump,
1053bc58f211SShawn Lin };
1054bc58f211SShawn Lin 
1055bc58f211SShawn Lin static const struct udevice_id rockchip_pcie_ids[] = {
1056793cb46eSJon Lin 	{ .compatible = "rockchip,rk3528-pcie" },
1057e751b113SJon Lin 	{ .compatible = "rockchip,rk3562-pcie" },
1058bc58f211SShawn Lin 	{ .compatible = "rockchip,rk3568-pcie" },
105943ede60cSJon Lin 	{ .compatible = "rockchip,rk3588-pcie" },
106053314ce8SJon Lin 	{ .compatible = "rockchip,rk3576-pcie" },
1061bc58f211SShawn Lin 	{ }
1062bc58f211SShawn Lin };
1063bc58f211SShawn Lin 
1064bc58f211SShawn Lin U_BOOT_DRIVER(rockchip_pcie) = {
1065bc58f211SShawn Lin 	.name			= "pcie_dw_rockchip",
1066bc58f211SShawn Lin 	.id			= UCLASS_PCI,
1067bc58f211SShawn Lin 	.of_match		= rockchip_pcie_ids,
1068bc58f211SShawn Lin 	.ops			= &rockchip_pcie_ops,
1069bc58f211SShawn Lin 	.probe			= rockchip_pcie_probe,
1070bc58f211SShawn Lin 	.priv_auto_alloc_size	= sizeof(struct rk_pcie),
1071bc58f211SShawn Lin };
1072