xref: /openbmc/linux/drivers/pci/controller/pci-tegra.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
16e0832faSShawn Lin // SPDX-License-Identifier: GPL-2.0+
26e0832faSShawn Lin /*
36e0832faSShawn Lin  * PCIe host controller driver for Tegra SoCs
46e0832faSShawn Lin  *
56e0832faSShawn Lin  * Copyright (c) 2010, CompuLab, Ltd.
66e0832faSShawn Lin  * Author: Mike Rapoport <mike@compulab.co.il>
76e0832faSShawn Lin  *
86e0832faSShawn Lin  * Based on NVIDIA PCIe driver
96e0832faSShawn Lin  * Copyright (c) 2008-2009, NVIDIA Corporation.
106e0832faSShawn Lin  *
116e0832faSShawn Lin  * Bits taken from arch/arm/mach-dove/pcie.c
126e0832faSShawn Lin  *
136e0832faSShawn Lin  * Author: Thierry Reding <treding@nvidia.com>
146e0832faSShawn Lin  */
156e0832faSShawn Lin 
166e0832faSShawn Lin #include <linux/clk.h>
176e0832faSShawn Lin #include <linux/debugfs.h>
186e0832faSShawn Lin #include <linux/delay.h>
196e0832faSShawn Lin #include <linux/export.h>
20dbdcc22cSManikanta Maddireddy #include <linux/gpio/consumer.h>
216e0832faSShawn Lin #include <linux/interrupt.h>
226e0832faSShawn Lin #include <linux/iopoll.h>
236e0832faSShawn Lin #include <linux/irq.h>
242c99e55fSMarc Zyngier #include <linux/irqchip/chained_irq.h>
256e0832faSShawn Lin #include <linux/irqdomain.h>
266e0832faSShawn Lin #include <linux/kernel.h>
276e0832faSShawn Lin #include <linux/init.h>
286e0832faSShawn Lin #include <linux/module.h>
296e0832faSShawn Lin #include <linux/msi.h>
306e0832faSShawn Lin #include <linux/of_address.h>
316e0832faSShawn Lin #include <linux/of_pci.h>
326e0832faSShawn Lin #include <linux/of_platform.h>
336e0832faSShawn Lin #include <linux/pci.h>
346e0832faSShawn Lin #include <linux/phy/phy.h>
352d8c7361SManikanta Maddireddy #include <linux/pinctrl/consumer.h>
366e0832faSShawn Lin #include <linux/platform_device.h>
376e0832faSShawn Lin #include <linux/reset.h>
386e0832faSShawn Lin #include <linux/sizes.h>
396e0832faSShawn Lin #include <linux/slab.h>
406e0832faSShawn Lin #include <linux/vmalloc.h>
416e0832faSShawn Lin #include <linux/regulator/consumer.h>
426e0832faSShawn Lin 
436e0832faSShawn Lin #include <soc/tegra/cpuidle.h>
446e0832faSShawn Lin #include <soc/tegra/pmc.h>
456e0832faSShawn Lin 
466e0832faSShawn Lin #include "../pci.h"
476e0832faSShawn Lin 
486e0832faSShawn Lin #define INT_PCI_MSI_NR (8 * 32)
496e0832faSShawn Lin 
506e0832faSShawn Lin /* register definitions */
516e0832faSShawn Lin 
526e0832faSShawn Lin #define AFI_AXI_BAR0_SZ	0x00
536e0832faSShawn Lin #define AFI_AXI_BAR1_SZ	0x04
546e0832faSShawn Lin #define AFI_AXI_BAR2_SZ	0x08
556e0832faSShawn Lin #define AFI_AXI_BAR3_SZ	0x0c
566e0832faSShawn Lin #define AFI_AXI_BAR4_SZ	0x10
576e0832faSShawn Lin #define AFI_AXI_BAR5_SZ	0x14
586e0832faSShawn Lin 
596e0832faSShawn Lin #define AFI_AXI_BAR0_START	0x18
606e0832faSShawn Lin #define AFI_AXI_BAR1_START	0x1c
616e0832faSShawn Lin #define AFI_AXI_BAR2_START	0x20
626e0832faSShawn Lin #define AFI_AXI_BAR3_START	0x24
636e0832faSShawn Lin #define AFI_AXI_BAR4_START	0x28
646e0832faSShawn Lin #define AFI_AXI_BAR5_START	0x2c
656e0832faSShawn Lin 
666e0832faSShawn Lin #define AFI_FPCI_BAR0	0x30
676e0832faSShawn Lin #define AFI_FPCI_BAR1	0x34
686e0832faSShawn Lin #define AFI_FPCI_BAR2	0x38
696e0832faSShawn Lin #define AFI_FPCI_BAR3	0x3c
706e0832faSShawn Lin #define AFI_FPCI_BAR4	0x40
716e0832faSShawn Lin #define AFI_FPCI_BAR5	0x44
726e0832faSShawn Lin 
736e0832faSShawn Lin #define AFI_CACHE_BAR0_SZ	0x48
746e0832faSShawn Lin #define AFI_CACHE_BAR0_ST	0x4c
756e0832faSShawn Lin #define AFI_CACHE_BAR1_SZ	0x50
766e0832faSShawn Lin #define AFI_CACHE_BAR1_ST	0x54
776e0832faSShawn Lin 
786e0832faSShawn Lin #define AFI_MSI_BAR_SZ		0x60
796e0832faSShawn Lin #define AFI_MSI_FPCI_BAR_ST	0x64
806e0832faSShawn Lin #define AFI_MSI_AXI_BAR_ST	0x68
816e0832faSShawn Lin 
822c99e55fSMarc Zyngier #define AFI_MSI_VEC(x)		(0x6c + ((x) * 4))
832c99e55fSMarc Zyngier #define AFI_MSI_EN_VEC(x)	(0x8c + ((x) * 4))
846e0832faSShawn Lin 
856e0832faSShawn Lin #define AFI_CONFIGURATION		0xac
866e0832faSShawn Lin #define  AFI_CONFIGURATION_EN_FPCI		(1 << 0)
8792bd94f1SManikanta Maddireddy #define  AFI_CONFIGURATION_CLKEN_OVERRIDE	(1 << 31)
886e0832faSShawn Lin 
896e0832faSShawn Lin #define AFI_FPCI_ERROR_MASKS	0xb0
906e0832faSShawn Lin 
916e0832faSShawn Lin #define AFI_INTR_MASK		0xb4
926e0832faSShawn Lin #define  AFI_INTR_MASK_INT_MASK	(1 << 0)
936e0832faSShawn Lin #define  AFI_INTR_MASK_MSI_MASK	(1 << 8)
946e0832faSShawn Lin 
956e0832faSShawn Lin #define AFI_INTR_CODE			0xb8
966e0832faSShawn Lin #define  AFI_INTR_CODE_MASK		0xf
976e0832faSShawn Lin #define  AFI_INTR_INI_SLAVE_ERROR	1
986e0832faSShawn Lin #define  AFI_INTR_INI_DECODE_ERROR	2
996e0832faSShawn Lin #define  AFI_INTR_TARGET_ABORT		3
1006e0832faSShawn Lin #define  AFI_INTR_MASTER_ABORT		4
1016e0832faSShawn Lin #define  AFI_INTR_INVALID_WRITE		5
1026e0832faSShawn Lin #define  AFI_INTR_LEGACY		6
1036e0832faSShawn Lin #define  AFI_INTR_FPCI_DECODE_ERROR	7
1046e0832faSShawn Lin #define  AFI_INTR_AXI_DECODE_ERROR	8
1056e0832faSShawn Lin #define  AFI_INTR_FPCI_TIMEOUT		9
1066e0832faSShawn Lin #define  AFI_INTR_PE_PRSNT_SENSE	10
1076e0832faSShawn Lin #define  AFI_INTR_PE_CLKREQ_SENSE	11
1086e0832faSShawn Lin #define  AFI_INTR_CLKCLAMP_SENSE	12
1096e0832faSShawn Lin #define  AFI_INTR_RDY4PD_SENSE		13
1106e0832faSShawn Lin #define  AFI_INTR_P2P_ERROR		14
1116e0832faSShawn Lin 
1126e0832faSShawn Lin #define AFI_INTR_SIGNATURE	0xbc
1136e0832faSShawn Lin #define AFI_UPPER_FPCI_ADDRESS	0xc0
1146e0832faSShawn Lin #define AFI_SM_INTR_ENABLE	0xc4
1156e0832faSShawn Lin #define  AFI_SM_INTR_INTA_ASSERT	(1 << 0)
1166e0832faSShawn Lin #define  AFI_SM_INTR_INTB_ASSERT	(1 << 1)
1176e0832faSShawn Lin #define  AFI_SM_INTR_INTC_ASSERT	(1 << 2)
1186e0832faSShawn Lin #define  AFI_SM_INTR_INTD_ASSERT	(1 << 3)
1196e0832faSShawn Lin #define  AFI_SM_INTR_INTA_DEASSERT	(1 << 4)
1206e0832faSShawn Lin #define  AFI_SM_INTR_INTB_DEASSERT	(1 << 5)
1216e0832faSShawn Lin #define  AFI_SM_INTR_INTC_DEASSERT	(1 << 6)
1226e0832faSShawn Lin #define  AFI_SM_INTR_INTD_DEASSERT	(1 << 7)
1236e0832faSShawn Lin 
1246e0832faSShawn Lin #define AFI_AFI_INTR_ENABLE		0xc8
1256e0832faSShawn Lin #define  AFI_INTR_EN_INI_SLVERR		(1 << 0)
1266e0832faSShawn Lin #define  AFI_INTR_EN_INI_DECERR		(1 << 1)
1276e0832faSShawn Lin #define  AFI_INTR_EN_TGT_SLVERR		(1 << 2)
1286e0832faSShawn Lin #define  AFI_INTR_EN_TGT_DECERR		(1 << 3)
1296e0832faSShawn Lin #define  AFI_INTR_EN_TGT_WRERR		(1 << 4)
1306e0832faSShawn Lin #define  AFI_INTR_EN_DFPCI_DECERR	(1 << 5)
1316e0832faSShawn Lin #define  AFI_INTR_EN_AXI_DECERR		(1 << 6)
1326e0832faSShawn Lin #define  AFI_INTR_EN_FPCI_TIMEOUT	(1 << 7)
1336e0832faSShawn Lin #define  AFI_INTR_EN_PRSNT_SENSE	(1 << 8)
1346e0832faSShawn Lin 
1356e0832faSShawn Lin #define AFI_PCIE_PME		0xf0
1366e0832faSShawn Lin 
1376e0832faSShawn Lin #define AFI_PCIE_CONFIG					0x0f8
1386e0832faSShawn Lin #define  AFI_PCIE_CONFIG_PCIE_DISABLE(x)		(1 << ((x) + 1))
1396e0832faSShawn Lin #define  AFI_PCIE_CONFIG_PCIE_DISABLE_ALL		0xe
1406e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
1416e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
1426e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
1436e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1	(0x0 << 20)
1446e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401	(0x0 << 20)
1456e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
1466e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222	(0x1 << 20)
1476e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1	(0x1 << 20)
1486e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211	(0x1 << 20)
1496e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411	(0x2 << 20)
1506e0832faSShawn Lin #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111	(0x2 << 20)
151eef4a350SManikanta Maddireddy #define  AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(x)		(1 << ((x) + 29))
152eef4a350SManikanta Maddireddy #define  AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL		(0x7 << 29)
1536e0832faSShawn Lin 
1546e0832faSShawn Lin #define AFI_FUSE			0x104
1556e0832faSShawn Lin #define  AFI_FUSE_PCIE_T0_GEN2_DIS	(1 << 2)
1566e0832faSShawn Lin 
1576e0832faSShawn Lin #define AFI_PEX0_CTRL			0x110
1586e0832faSShawn Lin #define AFI_PEX1_CTRL			0x118
1596e0832faSShawn Lin #define  AFI_PEX_CTRL_RST		(1 << 0)
1606e0832faSShawn Lin #define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
1616e0832faSShawn Lin #define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
1626e0832faSShawn Lin #define  AFI_PEX_CTRL_OVERRIDE_EN	(1 << 4)
1636e0832faSShawn Lin 
1646e0832faSShawn Lin #define AFI_PLLE_CONTROL		0x160
1656e0832faSShawn Lin #define  AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
1666e0832faSShawn Lin #define  AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
1676e0832faSShawn Lin 
1686e0832faSShawn Lin #define AFI_PEXBIAS_CTRL_0		0x168
1696e0832faSShawn Lin 
1702513a4eeSManikanta Maddireddy #define RP_ECTL_2_R1	0x00000e84
1712513a4eeSManikanta Maddireddy #define  RP_ECTL_2_R1_RX_CTLE_1C_MASK		0xffff
1722513a4eeSManikanta Maddireddy 
1732513a4eeSManikanta Maddireddy #define RP_ECTL_4_R1	0x00000e8c
1742513a4eeSManikanta Maddireddy #define  RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK	(0xffff << 16)
1752513a4eeSManikanta Maddireddy #define  RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT	16
1762513a4eeSManikanta Maddireddy 
1772513a4eeSManikanta Maddireddy #define RP_ECTL_5_R1	0x00000e90
1782513a4eeSManikanta Maddireddy #define  RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK	0xffffffff
1792513a4eeSManikanta Maddireddy 
1802513a4eeSManikanta Maddireddy #define RP_ECTL_6_R1	0x00000e94
1812513a4eeSManikanta Maddireddy #define  RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK	0xffffffff
1822513a4eeSManikanta Maddireddy 
1832513a4eeSManikanta Maddireddy #define RP_ECTL_2_R2	0x00000ea4
1842513a4eeSManikanta Maddireddy #define  RP_ECTL_2_R2_RX_CTLE_1C_MASK	0xffff
1852513a4eeSManikanta Maddireddy 
1862513a4eeSManikanta Maddireddy #define RP_ECTL_4_R2	0x00000eac
1872513a4eeSManikanta Maddireddy #define  RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK	(0xffff << 16)
1882513a4eeSManikanta Maddireddy #define  RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT	16
1892513a4eeSManikanta Maddireddy 
1902513a4eeSManikanta Maddireddy #define RP_ECTL_5_R2	0x00000eb0
1912513a4eeSManikanta Maddireddy #define  RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK	0xffffffff
1922513a4eeSManikanta Maddireddy 
1932513a4eeSManikanta Maddireddy #define RP_ECTL_6_R2	0x00000eb4
1942513a4eeSManikanta Maddireddy #define  RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK	0xffffffff
1952513a4eeSManikanta Maddireddy 
1966e0832faSShawn Lin #define RP_VEND_XP	0x00000f00
1976e0832faSShawn Lin #define  RP_VEND_XP_DL_UP			(1 << 30)
1987763cc24SManikanta Maddireddy #define  RP_VEND_XP_OPPORTUNISTIC_ACK		(1 << 27)
1997763cc24SManikanta Maddireddy #define  RP_VEND_XP_OPPORTUNISTIC_UPDATEFC	(1 << 28)
200191cd6fbSManikanta Maddireddy #define  RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK	(0xff << 18)
2016e0832faSShawn Lin 
202b2634cd0SManikanta Maddireddy #define RP_VEND_CTL0	0x00000f44
203b2634cd0SManikanta Maddireddy #define  RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK	(0xf << 12)
204b2634cd0SManikanta Maddireddy #define  RP_VEND_CTL0_DSK_RST_PULSE_WIDTH	(0x9 << 12)
205b2634cd0SManikanta Maddireddy 
206c635a815SManikanta Maddireddy #define RP_VEND_CTL1	0x00000f48
207c635a815SManikanta Maddireddy #define  RP_VEND_CTL1_ERPT	(1 << 13)
208c635a815SManikanta Maddireddy 
20952db2fd8SManikanta Maddireddy #define RP_VEND_XP_BIST	0x00000f4c
21052db2fd8SManikanta Maddireddy #define  RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE	(1 << 28)
21152db2fd8SManikanta Maddireddy 
2126e0832faSShawn Lin #define RP_VEND_CTL2 0x00000fa8
2136e0832faSShawn Lin #define  RP_VEND_CTL2_PCA_ENABLE (1 << 7)
2146e0832faSShawn Lin 
2156e0832faSShawn Lin #define RP_PRIV_MISC	0x00000fe0
2166e0832faSShawn Lin #define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT		(0xe << 0)
2176e0832faSShawn Lin #define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT		(0xf << 0)
218f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK	(0x7f << 16)
219f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD		(0xf << 16)
220f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE		(1 << 23)
221f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK	(0x7f << 24)
222f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD		(0xf << 24)
223f1178099SManikanta Maddireddy #define  RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE		(1 << 31)
2246e0832faSShawn Lin 
2256e0832faSShawn Lin #define RP_LINK_CONTROL_STATUS			0x00000090
2266e0832faSShawn Lin #define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
2276e0832faSShawn Lin #define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
2286e0832faSShawn Lin 
229538123a2SManikanta Maddireddy #define RP_LINK_CONTROL_STATUS_2		0x000000b0
230538123a2SManikanta Maddireddy 
2316e0832faSShawn Lin #define PADS_CTL_SEL		0x0000009c
2326e0832faSShawn Lin 
2336e0832faSShawn Lin #define PADS_CTL		0x000000a0
2346e0832faSShawn Lin #define  PADS_CTL_IDDQ_1L	(1 << 0)
2356e0832faSShawn Lin #define  PADS_CTL_TX_DATA_EN_1L	(1 << 6)
2366e0832faSShawn Lin #define  PADS_CTL_RX_DATA_EN_1L	(1 << 10)
2376e0832faSShawn Lin 
2386e0832faSShawn Lin #define PADS_PLL_CTL_TEGRA20			0x000000b8
2396e0832faSShawn Lin #define PADS_PLL_CTL_TEGRA30			0x000000b4
2406e0832faSShawn Lin #define  PADS_PLL_CTL_RST_B4SM			(1 << 1)
2416e0832faSShawn Lin #define  PADS_PLL_CTL_LOCKDET			(1 << 8)
2426e0832faSShawn Lin #define  PADS_PLL_CTL_REFCLK_MASK		(0x3 << 16)
2436e0832faSShawn Lin #define  PADS_PLL_CTL_REFCLK_INTERNAL_CML	(0 << 16)
2446e0832faSShawn Lin #define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS	(1 << 16)
2456e0832faSShawn Lin #define  PADS_PLL_CTL_REFCLK_EXTERNAL		(2 << 16)
2466e0832faSShawn Lin #define  PADS_PLL_CTL_TXCLKREF_MASK		(0x1 << 20)
2476e0832faSShawn Lin #define  PADS_PLL_CTL_TXCLKREF_DIV10		(0 << 20)
2486e0832faSShawn Lin #define  PADS_PLL_CTL_TXCLKREF_DIV5		(1 << 20)
2496e0832faSShawn Lin #define  PADS_PLL_CTL_TXCLKREF_BUF_EN		(1 << 22)
2506e0832faSShawn Lin 
2516e0832faSShawn Lin #define PADS_REFCLK_CFG0			0x000000c8
2526e0832faSShawn Lin #define PADS_REFCLK_CFG1			0x000000cc
2536e0832faSShawn Lin #define PADS_REFCLK_BIAS			0x000000d0
2546e0832faSShawn Lin 
2556e0832faSShawn Lin /*
2566e0832faSShawn Lin  * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
2576e0832faSShawn Lin  * entries, one entry per PCIe port. These field definitions and desired
2586e0832faSShawn Lin  * values aren't in the TRM, but do come from NVIDIA.
2596e0832faSShawn Lin  */
2606e0832faSShawn Lin #define PADS_REFCLK_CFG_TERM_SHIFT		2  /* 6:2 */
2616e0832faSShawn Lin #define PADS_REFCLK_CFG_E_TERM_SHIFT		7
2626e0832faSShawn Lin #define PADS_REFCLK_CFG_PREDI_SHIFT		8  /* 11:8 */
2636e0832faSShawn Lin #define PADS_REFCLK_CFG_DRVI_SHIFT		12 /* 15:12 */
2646e0832faSShawn Lin 
2656e0832faSShawn Lin #define PME_ACK_TIMEOUT 10000
266538123a2SManikanta Maddireddy #define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
2676e0832faSShawn Lin 
2686e0832faSShawn Lin struct tegra_msi {
2696e0832faSShawn Lin 	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
2706e0832faSShawn Lin 	struct irq_domain *domain;
2712c99e55fSMarc Zyngier 	struct mutex map_lock;
2722c99e55fSMarc Zyngier 	spinlock_t mask_lock;
27321e2079fSVidya Sagar 	void *virt;
27421e2079fSVidya Sagar 	dma_addr_t phys;
2756e0832faSShawn Lin 	int irq;
2766e0832faSShawn Lin };
2776e0832faSShawn Lin 
2786e0832faSShawn Lin /* used to differentiate between Tegra SoC generations */
2796e0832faSShawn Lin struct tegra_pcie_port_soc {
2806e0832faSShawn Lin 	struct {
2816e0832faSShawn Lin 		u8 turnoff_bit;
2826e0832faSShawn Lin 		u8 ack_bit;
2836e0832faSShawn Lin 	} pme;
2846e0832faSShawn Lin };
2856e0832faSShawn Lin 
2866e0832faSShawn Lin struct tegra_pcie_soc {
2876e0832faSShawn Lin 	unsigned int num_ports;
2886e0832faSShawn Lin 	const struct tegra_pcie_port_soc *ports;
2896e0832faSShawn Lin 	unsigned int msi_base_shift;
290adb2653bSManikanta Maddireddy 	unsigned long afi_pex2_ctrl;
2916e0832faSShawn Lin 	u32 pads_pll_ctl;
2926e0832faSShawn Lin 	u32 tx_ref_sel;
2936e0832faSShawn Lin 	u32 pads_refclk_cfg0;
2946e0832faSShawn Lin 	u32 pads_refclk_cfg1;
295191cd6fbSManikanta Maddireddy 	u32 update_fc_threshold;
2966e0832faSShawn Lin 	bool has_pex_clkreq_en;
2976e0832faSShawn Lin 	bool has_pex_bias_ctrl;
2986e0832faSShawn Lin 	bool has_intr_prsnt_sense;
2996e0832faSShawn Lin 	bool has_cml_clk;
3006e0832faSShawn Lin 	bool has_gen2;
3016e0832faSShawn Lin 	bool force_pca_enable;
3026e0832faSShawn Lin 	bool program_uphy;
303f1178099SManikanta Maddireddy 	bool update_clamp_threshold;
304b2634cd0SManikanta Maddireddy 	bool program_deskew_time;
3059f570b6cSManikanta Maddireddy 	bool update_fc_timer;
306b5b4717eSManikanta Maddireddy 	bool has_cache_bars;
3072513a4eeSManikanta Maddireddy 	struct {
3082513a4eeSManikanta Maddireddy 		struct {
3092513a4eeSManikanta Maddireddy 			u32 rp_ectl_2_r1;
3102513a4eeSManikanta Maddireddy 			u32 rp_ectl_4_r1;
3112513a4eeSManikanta Maddireddy 			u32 rp_ectl_5_r1;
3122513a4eeSManikanta Maddireddy 			u32 rp_ectl_6_r1;
3132513a4eeSManikanta Maddireddy 			u32 rp_ectl_2_r2;
3142513a4eeSManikanta Maddireddy 			u32 rp_ectl_4_r2;
3152513a4eeSManikanta Maddireddy 			u32 rp_ectl_5_r2;
3162513a4eeSManikanta Maddireddy 			u32 rp_ectl_6_r2;
3172513a4eeSManikanta Maddireddy 		} regs;
3182513a4eeSManikanta Maddireddy 		bool enable;
3192513a4eeSManikanta Maddireddy 	} ectl;
3206e0832faSShawn Lin };
3216e0832faSShawn Lin 
3226e0832faSShawn Lin struct tegra_pcie {
3236e0832faSShawn Lin 	struct device *dev;
3246e0832faSShawn Lin 
3256e0832faSShawn Lin 	void __iomem *pads;
3266e0832faSShawn Lin 	void __iomem *afi;
3276e0832faSShawn Lin 	void __iomem *cfg;
3286e0832faSShawn Lin 	int irq;
3296e0832faSShawn Lin 
3306e0832faSShawn Lin 	struct resource cs;
3316e0832faSShawn Lin 
3326e0832faSShawn Lin 	struct clk *pex_clk;
3336e0832faSShawn Lin 	struct clk *afi_clk;
3346e0832faSShawn Lin 	struct clk *pll_e;
3356e0832faSShawn Lin 	struct clk *cml_clk;
3366e0832faSShawn Lin 
3376e0832faSShawn Lin 	struct reset_control *pex_rst;
3386e0832faSShawn Lin 	struct reset_control *afi_rst;
3396e0832faSShawn Lin 	struct reset_control *pcie_xrst;
3406e0832faSShawn Lin 
3416e0832faSShawn Lin 	bool legacy_phy;
3426e0832faSShawn Lin 	struct phy *phy;
3436e0832faSShawn Lin 
3446e0832faSShawn Lin 	struct tegra_msi msi;
3456e0832faSShawn Lin 
3466e0832faSShawn Lin 	struct list_head ports;
3476e0832faSShawn Lin 	u32 xbar_config;
3486e0832faSShawn Lin 
3496e0832faSShawn Lin 	struct regulator_bulk_data *supplies;
3506e0832faSShawn Lin 	unsigned int num_supplies;
3516e0832faSShawn Lin 
3526e0832faSShawn Lin 	const struct tegra_pcie_soc *soc;
3536e0832faSShawn Lin 	struct dentry *debugfs;
3546e0832faSShawn Lin };
3556e0832faSShawn Lin 
msi_to_pcie(struct tegra_msi * msi)3562c99e55fSMarc Zyngier static inline struct tegra_pcie *msi_to_pcie(struct tegra_msi *msi)
3572c99e55fSMarc Zyngier {
3582c99e55fSMarc Zyngier 	return container_of(msi, struct tegra_pcie, msi);
3592c99e55fSMarc Zyngier }
3602c99e55fSMarc Zyngier 
3616e0832faSShawn Lin struct tegra_pcie_port {
3626e0832faSShawn Lin 	struct tegra_pcie *pcie;
3636e0832faSShawn Lin 	struct device_node *np;
3646e0832faSShawn Lin 	struct list_head list;
3656e0832faSShawn Lin 	struct resource regs;
3666e0832faSShawn Lin 	void __iomem *base;
3676e0832faSShawn Lin 	unsigned int index;
3686e0832faSShawn Lin 	unsigned int lanes;
3696e0832faSShawn Lin 
3706e0832faSShawn Lin 	struct phy **phys;
371dbdcc22cSManikanta Maddireddy 
372dbdcc22cSManikanta Maddireddy 	struct gpio_desc *reset_gpio;
3736e0832faSShawn Lin };
3746e0832faSShawn Lin 
afi_writel(struct tegra_pcie * pcie,u32 value,unsigned long offset)3756e0832faSShawn Lin static inline void afi_writel(struct tegra_pcie *pcie, u32 value,
3766e0832faSShawn Lin 			      unsigned long offset)
3776e0832faSShawn Lin {
3786e0832faSShawn Lin 	writel(value, pcie->afi + offset);
3796e0832faSShawn Lin }
3806e0832faSShawn Lin 
afi_readl(struct tegra_pcie * pcie,unsigned long offset)3816e0832faSShawn Lin static inline u32 afi_readl(struct tegra_pcie *pcie, unsigned long offset)
3826e0832faSShawn Lin {
3836e0832faSShawn Lin 	return readl(pcie->afi + offset);
3846e0832faSShawn Lin }
3856e0832faSShawn Lin 
pads_writel(struct tegra_pcie * pcie,u32 value,unsigned long offset)3866e0832faSShawn Lin static inline void pads_writel(struct tegra_pcie *pcie, u32 value,
3876e0832faSShawn Lin 			       unsigned long offset)
3886e0832faSShawn Lin {
3896e0832faSShawn Lin 	writel(value, pcie->pads + offset);
3906e0832faSShawn Lin }
3916e0832faSShawn Lin 
pads_readl(struct tegra_pcie * pcie,unsigned long offset)3926e0832faSShawn Lin static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
3936e0832faSShawn Lin {
3946e0832faSShawn Lin 	return readl(pcie->pads + offset);
3956e0832faSShawn Lin }
3966e0832faSShawn Lin 
3976e0832faSShawn Lin /*
3986e0832faSShawn Lin  * The configuration space mapping on Tegra is somewhat similar to the ECAM
3996e0832faSShawn Lin  * defined by PCIe. However it deviates a bit in how the 4 bits for extended
4006e0832faSShawn Lin  * register accesses are mapped:
4016e0832faSShawn Lin  *
4026e0832faSShawn Lin  *    [27:24] extended register number
4036e0832faSShawn Lin  *    [23:16] bus number
4046e0832faSShawn Lin  *    [15:11] device number
4056e0832faSShawn Lin  *    [10: 8] function number
4066e0832faSShawn Lin  *    [ 7: 0] register number
4076e0832faSShawn Lin  *
4086e0832faSShawn Lin  * Mapping the whole extended configuration space would require 256 MiB of
4096e0832faSShawn Lin  * virtual address space, only a small part of which will actually be used.
4106e0832faSShawn Lin  *
4116e0832faSShawn Lin  * To work around this, a 4 KiB region is used to generate the required
4126e0832faSShawn Lin  * configuration transaction with relevant B:D:F and register offset values.
4136e0832faSShawn Lin  * This is achieved by dynamically programming base address and size of
4146e0832faSShawn Lin  * AFI_AXI_BAR used for end point config space mapping to make sure that the
4156e0832faSShawn Lin  * address (access to which generates correct config transaction) falls in
4166e0832faSShawn Lin  * this 4 KiB region.
4176e0832faSShawn Lin  */
tegra_pcie_conf_offset(u8 bus,unsigned int devfn,unsigned int where)418897a66d2SJon Hunter static unsigned int tegra_pcie_conf_offset(u8 bus, unsigned int devfn,
419897a66d2SJon Hunter 					   unsigned int where)
420897a66d2SJon Hunter {
421897a66d2SJon Hunter 	return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) |
422897a66d2SJon Hunter 	       (PCI_FUNC(devfn) << 8) | (where & 0xff);
423897a66d2SJon Hunter }
424897a66d2SJon Hunter 
tegra_pcie_map_bus(struct pci_bus * bus,unsigned int devfn,int where)4256e0832faSShawn Lin static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
4266e0832faSShawn Lin 					unsigned int devfn,
4276e0832faSShawn Lin 					int where)
4286e0832faSShawn Lin {
4296e0832faSShawn Lin 	struct tegra_pcie *pcie = bus->sysdata;
4306e0832faSShawn Lin 	void __iomem *addr = NULL;
4316e0832faSShawn Lin 
4326e0832faSShawn Lin 	if (bus->number == 0) {
4336e0832faSShawn Lin 		unsigned int slot = PCI_SLOT(devfn);
4346e0832faSShawn Lin 		struct tegra_pcie_port *port;
4356e0832faSShawn Lin 
4366e0832faSShawn Lin 		list_for_each_entry(port, &pcie->ports, list) {
4376e0832faSShawn Lin 			if (port->index + 1 == slot) {
4386e0832faSShawn Lin 				addr = port->base + (where & ~3);
4396e0832faSShawn Lin 				break;
4406e0832faSShawn Lin 			}
4416e0832faSShawn Lin 		}
4426e0832faSShawn Lin 	} else {
4436e0832faSShawn Lin 		unsigned int offset;
4446e0832faSShawn Lin 		u32 base;
4456e0832faSShawn Lin 
446897a66d2SJon Hunter 		offset = tegra_pcie_conf_offset(bus->number, devfn, where);
4476e0832faSShawn Lin 
4486e0832faSShawn Lin 		/* move 4 KiB window to offset within the FPCI region */
4496e0832faSShawn Lin 		base = 0xfe100000 + ((offset & ~(SZ_4K - 1)) >> 8);
4506e0832faSShawn Lin 		afi_writel(pcie, base, AFI_FPCI_BAR0);
4516e0832faSShawn Lin 
4526e0832faSShawn Lin 		/* move to correct offset within the 4 KiB page */
4536e0832faSShawn Lin 		addr = pcie->cfg + (offset & (SZ_4K - 1));
4546e0832faSShawn Lin 	}
4556e0832faSShawn Lin 
4566e0832faSShawn Lin 	return addr;
4576e0832faSShawn Lin }
4586e0832faSShawn Lin 
tegra_pcie_config_read(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)4596e0832faSShawn Lin static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
4606e0832faSShawn Lin 				  int where, int size, u32 *value)
4616e0832faSShawn Lin {
4626e0832faSShawn Lin 	if (bus->number == 0)
4636e0832faSShawn Lin 		return pci_generic_config_read32(bus, devfn, where, size,
4646e0832faSShawn Lin 						 value);
4656e0832faSShawn Lin 
4666e0832faSShawn Lin 	return pci_generic_config_read(bus, devfn, where, size, value);
4676e0832faSShawn Lin }
4686e0832faSShawn Lin 
tegra_pcie_config_write(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)4696e0832faSShawn Lin static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
4706e0832faSShawn Lin 				   int where, int size, u32 value)
4716e0832faSShawn Lin {
4726e0832faSShawn Lin 	if (bus->number == 0)
4736e0832faSShawn Lin 		return pci_generic_config_write32(bus, devfn, where, size,
4746e0832faSShawn Lin 						  value);
4756e0832faSShawn Lin 
4766e0832faSShawn Lin 	return pci_generic_config_write(bus, devfn, where, size, value);
4776e0832faSShawn Lin }
4786e0832faSShawn Lin 
4796e0832faSShawn Lin static struct pci_ops tegra_pcie_ops = {
4806e0832faSShawn Lin 	.map_bus = tegra_pcie_map_bus,
4816e0832faSShawn Lin 	.read = tegra_pcie_config_read,
4826e0832faSShawn Lin 	.write = tegra_pcie_config_write,
4836e0832faSShawn Lin };
4846e0832faSShawn Lin 
tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port * port)4856e0832faSShawn Lin static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
4866e0832faSShawn Lin {
487adb2653bSManikanta Maddireddy 	const struct tegra_pcie_soc *soc = port->pcie->soc;
4886e0832faSShawn Lin 	unsigned long ret = 0;
4896e0832faSShawn Lin 
4906e0832faSShawn Lin 	switch (port->index) {
4916e0832faSShawn Lin 	case 0:
4926e0832faSShawn Lin 		ret = AFI_PEX0_CTRL;
4936e0832faSShawn Lin 		break;
4946e0832faSShawn Lin 
4956e0832faSShawn Lin 	case 1:
4966e0832faSShawn Lin 		ret = AFI_PEX1_CTRL;
4976e0832faSShawn Lin 		break;
4986e0832faSShawn Lin 
4996e0832faSShawn Lin 	case 2:
500adb2653bSManikanta Maddireddy 		ret = soc->afi_pex2_ctrl;
5016e0832faSShawn Lin 		break;
5026e0832faSShawn Lin 	}
5036e0832faSShawn Lin 
5046e0832faSShawn Lin 	return ret;
5056e0832faSShawn Lin }
5066e0832faSShawn Lin 
tegra_pcie_port_reset(struct tegra_pcie_port * port)5076e0832faSShawn Lin static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
5086e0832faSShawn Lin {
5096e0832faSShawn Lin 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
5106e0832faSShawn Lin 	unsigned long value;
5116e0832faSShawn Lin 
5126e0832faSShawn Lin 	/* pulse reset signal */
513dbdcc22cSManikanta Maddireddy 	if (port->reset_gpio) {
514dbdcc22cSManikanta Maddireddy 		gpiod_set_value(port->reset_gpio, 1);
515dbdcc22cSManikanta Maddireddy 	} else {
5166e0832faSShawn Lin 		value = afi_readl(port->pcie, ctrl);
5176e0832faSShawn Lin 		value &= ~AFI_PEX_CTRL_RST;
5186e0832faSShawn Lin 		afi_writel(port->pcie, value, ctrl);
519dbdcc22cSManikanta Maddireddy 	}
5206e0832faSShawn Lin 
5216e0832faSShawn Lin 	usleep_range(1000, 2000);
5226e0832faSShawn Lin 
523dbdcc22cSManikanta Maddireddy 	if (port->reset_gpio) {
524dbdcc22cSManikanta Maddireddy 		gpiod_set_value(port->reset_gpio, 0);
525dbdcc22cSManikanta Maddireddy 	} else {
5266e0832faSShawn Lin 		value = afi_readl(port->pcie, ctrl);
5276e0832faSShawn Lin 		value |= AFI_PEX_CTRL_RST;
5286e0832faSShawn Lin 		afi_writel(port->pcie, value, ctrl);
5296e0832faSShawn Lin 	}
530dbdcc22cSManikanta Maddireddy }
5316e0832faSShawn Lin 
tegra_pcie_enable_rp_features(struct tegra_pcie_port * port)532c635a815SManikanta Maddireddy static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
533c635a815SManikanta Maddireddy {
534f1178099SManikanta Maddireddy 	const struct tegra_pcie_soc *soc = port->pcie->soc;
535c635a815SManikanta Maddireddy 	u32 value;
536c635a815SManikanta Maddireddy 
537c635a815SManikanta Maddireddy 	/* Enable AER capability */
538c635a815SManikanta Maddireddy 	value = readl(port->base + RP_VEND_CTL1);
539c635a815SManikanta Maddireddy 	value |= RP_VEND_CTL1_ERPT;
540c635a815SManikanta Maddireddy 	writel(value, port->base + RP_VEND_CTL1);
5417763cc24SManikanta Maddireddy 
5427763cc24SManikanta Maddireddy 	/* Optimal settings to enhance bandwidth */
5437763cc24SManikanta Maddireddy 	value = readl(port->base + RP_VEND_XP);
5447763cc24SManikanta Maddireddy 	value |= RP_VEND_XP_OPPORTUNISTIC_ACK;
5457763cc24SManikanta Maddireddy 	value |= RP_VEND_XP_OPPORTUNISTIC_UPDATEFC;
5467763cc24SManikanta Maddireddy 	writel(value, port->base + RP_VEND_XP);
54752db2fd8SManikanta Maddireddy 
54852db2fd8SManikanta Maddireddy 	/*
54952db2fd8SManikanta Maddireddy 	 * LTSSM will wait for DLLP to finish before entering L1 or L2,
55052db2fd8SManikanta Maddireddy 	 * to avoid truncation of PM messages which results in receiver errors
55152db2fd8SManikanta Maddireddy 	 */
55252db2fd8SManikanta Maddireddy 	value = readl(port->base + RP_VEND_XP_BIST);
55352db2fd8SManikanta Maddireddy 	value |= RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE;
55452db2fd8SManikanta Maddireddy 	writel(value, port->base + RP_VEND_XP_BIST);
555f1178099SManikanta Maddireddy 
556f1178099SManikanta Maddireddy 	value = readl(port->base + RP_PRIV_MISC);
557f1178099SManikanta Maddireddy 	value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE;
558f1178099SManikanta Maddireddy 	value |= RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE;
559f1178099SManikanta Maddireddy 
560f1178099SManikanta Maddireddy 	if (soc->update_clamp_threshold) {
561f1178099SManikanta Maddireddy 		value &= ~(RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK |
562f1178099SManikanta Maddireddy 				RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK);
563f1178099SManikanta Maddireddy 		value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD |
564f1178099SManikanta Maddireddy 			RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD;
565f1178099SManikanta Maddireddy 	}
566f1178099SManikanta Maddireddy 
567f1178099SManikanta Maddireddy 	writel(value, port->base + RP_PRIV_MISC);
568c635a815SManikanta Maddireddy }
569c635a815SManikanta Maddireddy 
tegra_pcie_program_ectl_settings(struct tegra_pcie_port * port)5702513a4eeSManikanta Maddireddy static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
5712513a4eeSManikanta Maddireddy {
5722513a4eeSManikanta Maddireddy 	const struct tegra_pcie_soc *soc = port->pcie->soc;
5732513a4eeSManikanta Maddireddy 	u32 value;
5742513a4eeSManikanta Maddireddy 
5752513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_2_R1);
5762513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK;
5772513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_2_r1;
5782513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_2_R1);
5792513a4eeSManikanta Maddireddy 
5802513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_4_R1);
5812513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK;
5822513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_4_r1 <<
5832513a4eeSManikanta Maddireddy 				RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT;
5842513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_4_R1);
5852513a4eeSManikanta Maddireddy 
5862513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_5_R1);
5872513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK;
5882513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_5_r1;
5892513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_5_R1);
5902513a4eeSManikanta Maddireddy 
5912513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_6_R1);
5922513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK;
5932513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_6_r1;
5942513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_6_R1);
5952513a4eeSManikanta Maddireddy 
5962513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_2_R2);
5972513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK;
5982513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_2_r2;
5992513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_2_R2);
6002513a4eeSManikanta Maddireddy 
6012513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_4_R2);
6022513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK;
6032513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_4_r2 <<
6042513a4eeSManikanta Maddireddy 				RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT;
6052513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_4_R2);
6062513a4eeSManikanta Maddireddy 
6072513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_5_R2);
6082513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK;
6092513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_5_r2;
6102513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_5_R2);
6112513a4eeSManikanta Maddireddy 
6122513a4eeSManikanta Maddireddy 	value = readl(port->base + RP_ECTL_6_R2);
6132513a4eeSManikanta Maddireddy 	value &= ~RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK;
6142513a4eeSManikanta Maddireddy 	value |= soc->ectl.regs.rp_ectl_6_r2;
6152513a4eeSManikanta Maddireddy 	writel(value, port->base + RP_ECTL_6_R2);
6162513a4eeSManikanta Maddireddy }
6172513a4eeSManikanta Maddireddy 
tegra_pcie_apply_sw_fixup(struct tegra_pcie_port * port)618b2634cd0SManikanta Maddireddy static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
619b2634cd0SManikanta Maddireddy {
620b2634cd0SManikanta Maddireddy 	const struct tegra_pcie_soc *soc = port->pcie->soc;
621b2634cd0SManikanta Maddireddy 	u32 value;
622b2634cd0SManikanta Maddireddy 
623b2634cd0SManikanta Maddireddy 	/*
624b2634cd0SManikanta Maddireddy 	 * Sometimes link speed change from Gen2 to Gen1 fails due to
625b2634cd0SManikanta Maddireddy 	 * instability in deskew logic on lane-0. Increase the deskew
626b2634cd0SManikanta Maddireddy 	 * retry time to resolve this issue.
627b2634cd0SManikanta Maddireddy 	 */
628b2634cd0SManikanta Maddireddy 	if (soc->program_deskew_time) {
629b2634cd0SManikanta Maddireddy 		value = readl(port->base + RP_VEND_CTL0);
630b2634cd0SManikanta Maddireddy 		value &= ~RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK;
631b2634cd0SManikanta Maddireddy 		value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH;
632b2634cd0SManikanta Maddireddy 		writel(value, port->base + RP_VEND_CTL0);
633b2634cd0SManikanta Maddireddy 	}
634191cd6fbSManikanta Maddireddy 
6359f570b6cSManikanta Maddireddy 	if (soc->update_fc_timer) {
6369f570b6cSManikanta Maddireddy 		value = readl(port->base + RP_VEND_XP);
6379f570b6cSManikanta Maddireddy 		value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
6389f570b6cSManikanta Maddireddy 		value |= soc->update_fc_threshold;
6399f570b6cSManikanta Maddireddy 		writel(value, port->base + RP_VEND_XP);
6409f570b6cSManikanta Maddireddy 	}
641c23ae2aeSManikanta Maddireddy 
642c23ae2aeSManikanta Maddireddy 	/*
643c23ae2aeSManikanta Maddireddy 	 * PCIe link doesn't come up with few legacy PCIe endpoints if
644c23ae2aeSManikanta Maddireddy 	 * root port advertises both Gen-1 and Gen-2 speeds in Tegra.
645c23ae2aeSManikanta Maddireddy 	 * Hence, the strategy followed here is to initially advertise
646c23ae2aeSManikanta Maddireddy 	 * only Gen-1 and after link is up, retrain link to Gen-2 speed
647c23ae2aeSManikanta Maddireddy 	 */
648c23ae2aeSManikanta Maddireddy 	value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
649c23ae2aeSManikanta Maddireddy 	value &= ~PCI_EXP_LNKSTA_CLS;
650c23ae2aeSManikanta Maddireddy 	value |= PCI_EXP_LNKSTA_CLS_2_5GB;
651c23ae2aeSManikanta Maddireddy 	writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
652b2634cd0SManikanta Maddireddy }
653b2634cd0SManikanta Maddireddy 
tegra_pcie_port_enable(struct tegra_pcie_port * port)6546e0832faSShawn Lin static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
6556e0832faSShawn Lin {
6566e0832faSShawn Lin 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
6576e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = port->pcie->soc;
6586e0832faSShawn Lin 	unsigned long value;
6596e0832faSShawn Lin 
6606e0832faSShawn Lin 	/* enable reference clock */
6616e0832faSShawn Lin 	value = afi_readl(port->pcie, ctrl);
6626e0832faSShawn Lin 	value |= AFI_PEX_CTRL_REFCLK_EN;
6636e0832faSShawn Lin 
6646e0832faSShawn Lin 	if (soc->has_pex_clkreq_en)
6656e0832faSShawn Lin 		value |= AFI_PEX_CTRL_CLKREQ_EN;
6666e0832faSShawn Lin 
6676e0832faSShawn Lin 	value |= AFI_PEX_CTRL_OVERRIDE_EN;
6686e0832faSShawn Lin 
6696e0832faSShawn Lin 	afi_writel(port->pcie, value, ctrl);
6706e0832faSShawn Lin 
6716e0832faSShawn Lin 	tegra_pcie_port_reset(port);
6726e0832faSShawn Lin 
6736e0832faSShawn Lin 	if (soc->force_pca_enable) {
6746e0832faSShawn Lin 		value = readl(port->base + RP_VEND_CTL2);
6756e0832faSShawn Lin 		value |= RP_VEND_CTL2_PCA_ENABLE;
6766e0832faSShawn Lin 		writel(value, port->base + RP_VEND_CTL2);
6776e0832faSShawn Lin 	}
678c635a815SManikanta Maddireddy 
679c635a815SManikanta Maddireddy 	tegra_pcie_enable_rp_features(port);
6802513a4eeSManikanta Maddireddy 
6812513a4eeSManikanta Maddireddy 	if (soc->ectl.enable)
6822513a4eeSManikanta Maddireddy 		tegra_pcie_program_ectl_settings(port);
683b2634cd0SManikanta Maddireddy 
684b2634cd0SManikanta Maddireddy 	tegra_pcie_apply_sw_fixup(port);
6856e0832faSShawn Lin }
6866e0832faSShawn Lin 
tegra_pcie_port_disable(struct tegra_pcie_port * port)6876e0832faSShawn Lin static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
6886e0832faSShawn Lin {
6896e0832faSShawn Lin 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
6906e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = port->pcie->soc;
6916e0832faSShawn Lin 	unsigned long value;
6926e0832faSShawn Lin 
6936e0832faSShawn Lin 	/* assert port reset */
6946e0832faSShawn Lin 	value = afi_readl(port->pcie, ctrl);
6956e0832faSShawn Lin 	value &= ~AFI_PEX_CTRL_RST;
6966e0832faSShawn Lin 	afi_writel(port->pcie, value, ctrl);
6976e0832faSShawn Lin 
6986e0832faSShawn Lin 	/* disable reference clock */
6996e0832faSShawn Lin 	value = afi_readl(port->pcie, ctrl);
7006e0832faSShawn Lin 
7016e0832faSShawn Lin 	if (soc->has_pex_clkreq_en)
7026e0832faSShawn Lin 		value &= ~AFI_PEX_CTRL_CLKREQ_EN;
7036e0832faSShawn Lin 
7046e0832faSShawn Lin 	value &= ~AFI_PEX_CTRL_REFCLK_EN;
7056e0832faSShawn Lin 	afi_writel(port->pcie, value, ctrl);
706eef4a350SManikanta Maddireddy 
707eef4a350SManikanta Maddireddy 	/* disable PCIe port and set CLKREQ# as GPIO to allow PLLE power down */
708eef4a350SManikanta Maddireddy 	value = afi_readl(port->pcie, AFI_PCIE_CONFIG);
709eef4a350SManikanta Maddireddy 	value |= AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
710eef4a350SManikanta Maddireddy 	value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
711eef4a350SManikanta Maddireddy 	afi_writel(port->pcie, value, AFI_PCIE_CONFIG);
7126e0832faSShawn Lin }
7136e0832faSShawn Lin 
tegra_pcie_port_free(struct tegra_pcie_port * port)7146e0832faSShawn Lin static void tegra_pcie_port_free(struct tegra_pcie_port *port)
7156e0832faSShawn Lin {
7166e0832faSShawn Lin 	struct tegra_pcie *pcie = port->pcie;
7176e0832faSShawn Lin 	struct device *dev = pcie->dev;
7186e0832faSShawn Lin 
7196e0832faSShawn Lin 	devm_iounmap(dev, port->base);
7206e0832faSShawn Lin 	devm_release_mem_region(dev, port->regs.start,
7216e0832faSShawn Lin 				resource_size(&port->regs));
7226e0832faSShawn Lin 	list_del(&port->list);
7236e0832faSShawn Lin 	devm_kfree(dev, port);
7246e0832faSShawn Lin }
7256e0832faSShawn Lin 
7266e0832faSShawn Lin /* Tegra PCIE root complex wrongly reports device class */
tegra_pcie_fixup_class(struct pci_dev * dev)7276e0832faSShawn Lin static void tegra_pcie_fixup_class(struct pci_dev *dev)
7286e0832faSShawn Lin {
729904b10fbSPali Rohár 	dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
7306e0832faSShawn Lin }
7316e0832faSShawn Lin DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
7326e0832faSShawn Lin DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
7336e0832faSShawn Lin DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
7346e0832faSShawn Lin DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
7356e0832faSShawn Lin 
7367be142caSVidya Sagar /* Tegra20 and Tegra30 PCIE requires relaxed ordering */
tegra_pcie_relax_enable(struct pci_dev * dev)7376e0832faSShawn Lin static void tegra_pcie_relax_enable(struct pci_dev *dev)
7386e0832faSShawn Lin {
7396e0832faSShawn Lin 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
7406e0832faSShawn Lin }
7417be142caSVidya Sagar DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable);
7427be142caSVidya Sagar DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable);
7437be142caSVidya Sagar DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable);
7447be142caSVidya Sagar DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
7456e0832faSShawn Lin 
tegra_pcie_map_irq(const struct pci_dev * pdev,u8 slot,u8 pin)7466e0832faSShawn Lin static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
7476e0832faSShawn Lin {
7486e0832faSShawn Lin 	struct tegra_pcie *pcie = pdev->bus->sysdata;
7496e0832faSShawn Lin 	int irq;
7506e0832faSShawn Lin 
7516e0832faSShawn Lin 	tegra_cpuidle_pcie_irqs_in_use();
7526e0832faSShawn Lin 
7536e0832faSShawn Lin 	irq = of_irq_parse_and_map_pci(pdev, slot, pin);
7546e0832faSShawn Lin 	if (!irq)
7556e0832faSShawn Lin 		irq = pcie->irq;
7566e0832faSShawn Lin 
7576e0832faSShawn Lin 	return irq;
7586e0832faSShawn Lin }
7596e0832faSShawn Lin 
tegra_pcie_isr(int irq,void * arg)7606e0832faSShawn Lin static irqreturn_t tegra_pcie_isr(int irq, void *arg)
7616e0832faSShawn Lin {
762fd44e8efSChristophe JAILLET 	static const char * const err_msg[] = {
7636e0832faSShawn Lin 		"Unknown",
7646e0832faSShawn Lin 		"AXI slave error",
7656e0832faSShawn Lin 		"AXI decode error",
7666e0832faSShawn Lin 		"Target abort",
7676e0832faSShawn Lin 		"Master abort",
7686e0832faSShawn Lin 		"Invalid write",
7696e0832faSShawn Lin 		"Legacy interrupt",
7706e0832faSShawn Lin 		"Response decoding error",
7716e0832faSShawn Lin 		"AXI response decoding error",
7726e0832faSShawn Lin 		"Transaction timeout",
7736e0832faSShawn Lin 		"Slot present pin change",
7746e0832faSShawn Lin 		"Slot clock request change",
7756e0832faSShawn Lin 		"TMS clock ramp change",
7766e0832faSShawn Lin 		"TMS ready for power down",
7776e0832faSShawn Lin 		"Peer2Peer error",
7786e0832faSShawn Lin 	};
7796e0832faSShawn Lin 	struct tegra_pcie *pcie = arg;
7806e0832faSShawn Lin 	struct device *dev = pcie->dev;
7816e0832faSShawn Lin 	u32 code, signature;
7826e0832faSShawn Lin 
7836e0832faSShawn Lin 	code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
7846e0832faSShawn Lin 	signature = afi_readl(pcie, AFI_INTR_SIGNATURE);
7856e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_INTR_CODE);
7866e0832faSShawn Lin 
7876e0832faSShawn Lin 	if (code == AFI_INTR_LEGACY)
7886e0832faSShawn Lin 		return IRQ_NONE;
7896e0832faSShawn Lin 
7906e0832faSShawn Lin 	if (code >= ARRAY_SIZE(err_msg))
7916e0832faSShawn Lin 		code = 0;
7926e0832faSShawn Lin 
7936e0832faSShawn Lin 	/*
7946e0832faSShawn Lin 	 * do not pollute kernel log with master abort reports since they
7956e0832faSShawn Lin 	 * happen a lot during enumeration
7966e0832faSShawn Lin 	 */
797c894121dSManikanta Maddireddy 	if (code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_PE_PRSNT_SENSE)
7986e0832faSShawn Lin 		dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature);
7996e0832faSShawn Lin 	else
8006e0832faSShawn Lin 		dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature);
8016e0832faSShawn Lin 
8026e0832faSShawn Lin 	if (code == AFI_INTR_TARGET_ABORT || code == AFI_INTR_MASTER_ABORT ||
8036e0832faSShawn Lin 	    code == AFI_INTR_FPCI_DECODE_ERROR) {
8046e0832faSShawn Lin 		u32 fpci = afi_readl(pcie, AFI_UPPER_FPCI_ADDRESS) & 0xff;
8056e0832faSShawn Lin 		u64 address = (u64)fpci << 32 | (signature & 0xfffffffc);
8066e0832faSShawn Lin 
8076e0832faSShawn Lin 		if (code == AFI_INTR_MASTER_ABORT)
8086e0832faSShawn Lin 			dev_dbg(dev, "  FPCI address: %10llx\n", address);
8096e0832faSShawn Lin 		else
8106e0832faSShawn Lin 			dev_err(dev, "  FPCI address: %10llx\n", address);
8116e0832faSShawn Lin 	}
8126e0832faSShawn Lin 
8136e0832faSShawn Lin 	return IRQ_HANDLED;
8146e0832faSShawn Lin }
8156e0832faSShawn Lin 
8166e0832faSShawn Lin /*
8176e0832faSShawn Lin  * FPCI map is as follows:
8186e0832faSShawn Lin  * - 0xfdfc000000: I/O space
8196e0832faSShawn Lin  * - 0xfdfe000000: type 0 configuration space
8206e0832faSShawn Lin  * - 0xfdff000000: type 1 configuration space
8216e0832faSShawn Lin  * - 0xfe00000000: type 0 extended configuration space
8226e0832faSShawn Lin  * - 0xfe10000000: type 1 extended configuration space
8236e0832faSShawn Lin  */
tegra_pcie_setup_translations(struct tegra_pcie * pcie)8246e0832faSShawn Lin static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
8256e0832faSShawn Lin {
82694e99b19SRob Herring 	u32 size;
82794e99b19SRob Herring 	struct resource_entry *entry;
82894e99b19SRob Herring 	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
8296e0832faSShawn Lin 
8306e0832faSShawn Lin 	/* Bar 0: type 1 extended configuration space */
8316e0832faSShawn Lin 	size = resource_size(&pcie->cs);
8326e0832faSShawn Lin 	afi_writel(pcie, pcie->cs.start, AFI_AXI_BAR0_START);
8336e0832faSShawn Lin 	afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
8346e0832faSShawn Lin 
83594e99b19SRob Herring 	resource_list_for_each_entry(entry, &bridge->windows) {
83694e99b19SRob Herring 		u32 fpci_bar, axi_address;
83794e99b19SRob Herring 		struct resource *res = entry->res;
83894e99b19SRob Herring 
83994e99b19SRob Herring 		size = resource_size(res);
84094e99b19SRob Herring 
84194e99b19SRob Herring 		switch (resource_type(res)) {
84294e99b19SRob Herring 		case IORESOURCE_IO:
8436e0832faSShawn Lin 			/* Bar 1: downstream IO bar */
8446e0832faSShawn Lin 			fpci_bar = 0xfdfc0000;
84594e99b19SRob Herring 			axi_address = pci_pio_to_address(res->start);
8466e0832faSShawn Lin 			afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
8476e0832faSShawn Lin 			afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
8486e0832faSShawn Lin 			afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
84994e99b19SRob Herring 			break;
85094e99b19SRob Herring 		case IORESOURCE_MEM:
85194e99b19SRob Herring 			fpci_bar = (((res->start >> 12) & 0x0fffffff) << 4) | 0x1;
85294e99b19SRob Herring 			axi_address = res->start;
8536e0832faSShawn Lin 
85494e99b19SRob Herring 			if (res->flags & IORESOURCE_PREFETCH) {
8556e0832faSShawn Lin 				/* Bar 2: prefetchable memory BAR */
8566e0832faSShawn Lin 				afi_writel(pcie, axi_address, AFI_AXI_BAR2_START);
8576e0832faSShawn Lin 				afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
8586e0832faSShawn Lin 				afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2);
8596e0832faSShawn Lin 
86094e99b19SRob Herring 			} else {
8616e0832faSShawn Lin 				/* Bar 3: non prefetchable memory BAR */
8626e0832faSShawn Lin 				afi_writel(pcie, axi_address, AFI_AXI_BAR3_START);
8636e0832faSShawn Lin 				afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
8646e0832faSShawn Lin 				afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3);
86594e99b19SRob Herring 			}
86694e99b19SRob Herring 			break;
86794e99b19SRob Herring 		}
86894e99b19SRob Herring 	}
8696e0832faSShawn Lin 
8706e0832faSShawn Lin 	/* NULL out the remaining BARs as they are not used */
8716e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_AXI_BAR4_START);
8726e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
8736e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_FPCI_BAR4);
8746e0832faSShawn Lin 
8756e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_AXI_BAR5_START);
8766e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
8776e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_FPCI_BAR5);
8786e0832faSShawn Lin 
879b5b4717eSManikanta Maddireddy 	if (pcie->soc->has_cache_bars) {
8806e0832faSShawn Lin 		/* map all upstream transactions as uncached */
8816e0832faSShawn Lin 		afi_writel(pcie, 0, AFI_CACHE_BAR0_ST);
8826e0832faSShawn Lin 		afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
8836e0832faSShawn Lin 		afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
8846e0832faSShawn Lin 		afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
885b5b4717eSManikanta Maddireddy 	}
8866e0832faSShawn Lin 
8876e0832faSShawn Lin 	/* MSI translations are setup only when needed */
8886e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
8896e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
8906e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
8916e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
8926e0832faSShawn Lin }
8936e0832faSShawn Lin 
tegra_pcie_pll_wait(struct tegra_pcie * pcie,unsigned long timeout)8946e0832faSShawn Lin static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
8956e0832faSShawn Lin {
8966e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
8976e0832faSShawn Lin 	u32 value;
8986e0832faSShawn Lin 
8996e0832faSShawn Lin 	timeout = jiffies + msecs_to_jiffies(timeout);
9006e0832faSShawn Lin 
9016e0832faSShawn Lin 	while (time_before(jiffies, timeout)) {
9026e0832faSShawn Lin 		value = pads_readl(pcie, soc->pads_pll_ctl);
9036e0832faSShawn Lin 		if (value & PADS_PLL_CTL_LOCKDET)
9046e0832faSShawn Lin 			return 0;
9056e0832faSShawn Lin 	}
9066e0832faSShawn Lin 
9076e0832faSShawn Lin 	return -ETIMEDOUT;
9086e0832faSShawn Lin }
9096e0832faSShawn Lin 
tegra_pcie_phy_enable(struct tegra_pcie * pcie)9106e0832faSShawn Lin static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
9116e0832faSShawn Lin {
9126e0832faSShawn Lin 	struct device *dev = pcie->dev;
9136e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
9146e0832faSShawn Lin 	u32 value;
9156e0832faSShawn Lin 	int err;
9166e0832faSShawn Lin 
9176e0832faSShawn Lin 	/* initialize internal PHY, enable up to 16 PCIE lanes */
9186e0832faSShawn Lin 	pads_writel(pcie, 0x0, PADS_CTL_SEL);
9196e0832faSShawn Lin 
9206e0832faSShawn Lin 	/* override IDDQ to 1 on all 4 lanes */
9216e0832faSShawn Lin 	value = pads_readl(pcie, PADS_CTL);
9226e0832faSShawn Lin 	value |= PADS_CTL_IDDQ_1L;
9236e0832faSShawn Lin 	pads_writel(pcie, value, PADS_CTL);
9246e0832faSShawn Lin 
9256e0832faSShawn Lin 	/*
9266e0832faSShawn Lin 	 * Set up PHY PLL inputs select PLLE output as refclock,
9276e0832faSShawn Lin 	 * set TX ref sel to div10 (not div5).
9286e0832faSShawn Lin 	 */
9296e0832faSShawn Lin 	value = pads_readl(pcie, soc->pads_pll_ctl);
9306e0832faSShawn Lin 	value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
9316e0832faSShawn Lin 	value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
9326e0832faSShawn Lin 	pads_writel(pcie, value, soc->pads_pll_ctl);
9336e0832faSShawn Lin 
9346e0832faSShawn Lin 	/* reset PLL */
9356e0832faSShawn Lin 	value = pads_readl(pcie, soc->pads_pll_ctl);
9366e0832faSShawn Lin 	value &= ~PADS_PLL_CTL_RST_B4SM;
9376e0832faSShawn Lin 	pads_writel(pcie, value, soc->pads_pll_ctl);
9386e0832faSShawn Lin 
9396e0832faSShawn Lin 	usleep_range(20, 100);
9406e0832faSShawn Lin 
9416e0832faSShawn Lin 	/* take PLL out of reset  */
9426e0832faSShawn Lin 	value = pads_readl(pcie, soc->pads_pll_ctl);
9436e0832faSShawn Lin 	value |= PADS_PLL_CTL_RST_B4SM;
9446e0832faSShawn Lin 	pads_writel(pcie, value, soc->pads_pll_ctl);
9456e0832faSShawn Lin 
9466e0832faSShawn Lin 	/* wait for the PLL to lock */
9476e0832faSShawn Lin 	err = tegra_pcie_pll_wait(pcie, 500);
9486e0832faSShawn Lin 	if (err < 0) {
9496e0832faSShawn Lin 		dev_err(dev, "PLL failed to lock: %d\n", err);
9506e0832faSShawn Lin 		return err;
9516e0832faSShawn Lin 	}
9526e0832faSShawn Lin 
9536e0832faSShawn Lin 	/* turn off IDDQ override */
9546e0832faSShawn Lin 	value = pads_readl(pcie, PADS_CTL);
9556e0832faSShawn Lin 	value &= ~PADS_CTL_IDDQ_1L;
9566e0832faSShawn Lin 	pads_writel(pcie, value, PADS_CTL);
9576e0832faSShawn Lin 
9586e0832faSShawn Lin 	/* enable TX/RX data */
9596e0832faSShawn Lin 	value = pads_readl(pcie, PADS_CTL);
9606e0832faSShawn Lin 	value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
9616e0832faSShawn Lin 	pads_writel(pcie, value, PADS_CTL);
9626e0832faSShawn Lin 
9636e0832faSShawn Lin 	return 0;
9646e0832faSShawn Lin }
9656e0832faSShawn Lin 
tegra_pcie_phy_disable(struct tegra_pcie * pcie)9666e0832faSShawn Lin static int tegra_pcie_phy_disable(struct tegra_pcie *pcie)
9676e0832faSShawn Lin {
9686e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
9696e0832faSShawn Lin 	u32 value;
9706e0832faSShawn Lin 
9716e0832faSShawn Lin 	/* disable TX/RX data */
9726e0832faSShawn Lin 	value = pads_readl(pcie, PADS_CTL);
9736e0832faSShawn Lin 	value &= ~(PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
9746e0832faSShawn Lin 	pads_writel(pcie, value, PADS_CTL);
9756e0832faSShawn Lin 
9766e0832faSShawn Lin 	/* override IDDQ */
9776e0832faSShawn Lin 	value = pads_readl(pcie, PADS_CTL);
9786e0832faSShawn Lin 	value |= PADS_CTL_IDDQ_1L;
9796e0832faSShawn Lin 	pads_writel(pcie, value, PADS_CTL);
9806e0832faSShawn Lin 
9816e0832faSShawn Lin 	/* reset PLL */
9826e0832faSShawn Lin 	value = pads_readl(pcie, soc->pads_pll_ctl);
9836e0832faSShawn Lin 	value &= ~PADS_PLL_CTL_RST_B4SM;
9846e0832faSShawn Lin 	pads_writel(pcie, value, soc->pads_pll_ctl);
9856e0832faSShawn Lin 
9866e0832faSShawn Lin 	usleep_range(20, 100);
9876e0832faSShawn Lin 
9886e0832faSShawn Lin 	return 0;
9896e0832faSShawn Lin }
9906e0832faSShawn Lin 
tegra_pcie_port_phy_power_on(struct tegra_pcie_port * port)9916e0832faSShawn Lin static int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port)
9926e0832faSShawn Lin {
9936e0832faSShawn Lin 	struct device *dev = port->pcie->dev;
9946e0832faSShawn Lin 	unsigned int i;
9956e0832faSShawn Lin 	int err;
9966e0832faSShawn Lin 
9976e0832faSShawn Lin 	for (i = 0; i < port->lanes; i++) {
9986e0832faSShawn Lin 		err = phy_power_on(port->phys[i]);
9996e0832faSShawn Lin 		if (err < 0) {
10006e0832faSShawn Lin 			dev_err(dev, "failed to power on PHY#%u: %d\n", i, err);
10016e0832faSShawn Lin 			return err;
10026e0832faSShawn Lin 		}
10036e0832faSShawn Lin 	}
10046e0832faSShawn Lin 
10056e0832faSShawn Lin 	return 0;
10066e0832faSShawn Lin }
10076e0832faSShawn Lin 
tegra_pcie_port_phy_power_off(struct tegra_pcie_port * port)10086e0832faSShawn Lin static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
10096e0832faSShawn Lin {
10106e0832faSShawn Lin 	struct device *dev = port->pcie->dev;
10116e0832faSShawn Lin 	unsigned int i;
10126e0832faSShawn Lin 	int err;
10136e0832faSShawn Lin 
10146e0832faSShawn Lin 	for (i = 0; i < port->lanes; i++) {
10156e0832faSShawn Lin 		err = phy_power_off(port->phys[i]);
10166e0832faSShawn Lin 		if (err < 0) {
10176e0832faSShawn Lin 			dev_err(dev, "failed to power off PHY#%u: %d\n", i,
10186e0832faSShawn Lin 				err);
10196e0832faSShawn Lin 			return err;
10206e0832faSShawn Lin 		}
10216e0832faSShawn Lin 	}
10226e0832faSShawn Lin 
10236e0832faSShawn Lin 	return 0;
10246e0832faSShawn Lin }
10256e0832faSShawn Lin 
tegra_pcie_phy_power_on(struct tegra_pcie * pcie)10266e0832faSShawn Lin static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
10276e0832faSShawn Lin {
10286e0832faSShawn Lin 	struct device *dev = pcie->dev;
10296e0832faSShawn Lin 	struct tegra_pcie_port *port;
10306e0832faSShawn Lin 	int err;
10316e0832faSShawn Lin 
10326e0832faSShawn Lin 	if (pcie->legacy_phy) {
10336e0832faSShawn Lin 		if (pcie->phy)
10346e0832faSShawn Lin 			err = phy_power_on(pcie->phy);
10356e0832faSShawn Lin 		else
10366e0832faSShawn Lin 			err = tegra_pcie_phy_enable(pcie);
10376e0832faSShawn Lin 
10386e0832faSShawn Lin 		if (err < 0)
10396e0832faSShawn Lin 			dev_err(dev, "failed to power on PHY: %d\n", err);
10406e0832faSShawn Lin 
10416e0832faSShawn Lin 		return err;
10426e0832faSShawn Lin 	}
10436e0832faSShawn Lin 
10446e0832faSShawn Lin 	list_for_each_entry(port, &pcie->ports, list) {
10456e0832faSShawn Lin 		err = tegra_pcie_port_phy_power_on(port);
10466e0832faSShawn Lin 		if (err < 0) {
10476e0832faSShawn Lin 			dev_err(dev,
10486e0832faSShawn Lin 				"failed to power on PCIe port %u PHY: %d\n",
10496e0832faSShawn Lin 				port->index, err);
10506e0832faSShawn Lin 			return err;
10516e0832faSShawn Lin 		}
10526e0832faSShawn Lin 	}
10536e0832faSShawn Lin 
10546e0832faSShawn Lin 	return 0;
10556e0832faSShawn Lin }
10566e0832faSShawn Lin 
tegra_pcie_phy_power_off(struct tegra_pcie * pcie)10576e0832faSShawn Lin static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie)
10586e0832faSShawn Lin {
10596e0832faSShawn Lin 	struct device *dev = pcie->dev;
10606e0832faSShawn Lin 	struct tegra_pcie_port *port;
10616e0832faSShawn Lin 	int err;
10626e0832faSShawn Lin 
10636e0832faSShawn Lin 	if (pcie->legacy_phy) {
10646e0832faSShawn Lin 		if (pcie->phy)
10656e0832faSShawn Lin 			err = phy_power_off(pcie->phy);
10666e0832faSShawn Lin 		else
10676e0832faSShawn Lin 			err = tegra_pcie_phy_disable(pcie);
10686e0832faSShawn Lin 
10696e0832faSShawn Lin 		if (err < 0)
10706e0832faSShawn Lin 			dev_err(dev, "failed to power off PHY: %d\n", err);
10716e0832faSShawn Lin 
10726e0832faSShawn Lin 		return err;
10736e0832faSShawn Lin 	}
10746e0832faSShawn Lin 
10756e0832faSShawn Lin 	list_for_each_entry(port, &pcie->ports, list) {
10766e0832faSShawn Lin 		err = tegra_pcie_port_phy_power_off(port);
10776e0832faSShawn Lin 		if (err < 0) {
10786e0832faSShawn Lin 			dev_err(dev,
10796e0832faSShawn Lin 				"failed to power off PCIe port %u PHY: %d\n",
10806e0832faSShawn Lin 				port->index, err);
10816e0832faSShawn Lin 			return err;
10826e0832faSShawn Lin 		}
10836e0832faSShawn Lin 	}
10846e0832faSShawn Lin 
10856e0832faSShawn Lin 	return 0;
10866e0832faSShawn Lin }
10876e0832faSShawn Lin 
tegra_pcie_enable_controller(struct tegra_pcie * pcie)1088973d7499SManikanta Maddireddy static void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
10896e0832faSShawn Lin {
10906e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
10916e0832faSShawn Lin 	struct tegra_pcie_port *port;
10926e0832faSShawn Lin 	unsigned long value;
10936e0832faSShawn Lin 
10946e0832faSShawn Lin 	/* enable PLL power down */
10956e0832faSShawn Lin 	if (pcie->phy) {
10966e0832faSShawn Lin 		value = afi_readl(pcie, AFI_PLLE_CONTROL);
10976e0832faSShawn Lin 		value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
10986e0832faSShawn Lin 		value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
10996e0832faSShawn Lin 		afi_writel(pcie, value, AFI_PLLE_CONTROL);
11006e0832faSShawn Lin 	}
11016e0832faSShawn Lin 
11026e0832faSShawn Lin 	/* power down PCIe slot clock bias pad */
11036e0832faSShawn Lin 	if (soc->has_pex_bias_ctrl)
11046e0832faSShawn Lin 		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
11056e0832faSShawn Lin 
11066e0832faSShawn Lin 	/* configure mode and disable all ports */
11076e0832faSShawn Lin 	value = afi_readl(pcie, AFI_PCIE_CONFIG);
11086e0832faSShawn Lin 	value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
11096e0832faSShawn Lin 	value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
1110eef4a350SManikanta Maddireddy 	value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL;
11116e0832faSShawn Lin 
1112eef4a350SManikanta Maddireddy 	list_for_each_entry(port, &pcie->ports, list) {
11136e0832faSShawn Lin 		value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
1114eef4a350SManikanta Maddireddy 		value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
1115eef4a350SManikanta Maddireddy 	}
11166e0832faSShawn Lin 
11176e0832faSShawn Lin 	afi_writel(pcie, value, AFI_PCIE_CONFIG);
11186e0832faSShawn Lin 
11196e0832faSShawn Lin 	if (soc->has_gen2) {
11206e0832faSShawn Lin 		value = afi_readl(pcie, AFI_FUSE);
11216e0832faSShawn Lin 		value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
11226e0832faSShawn Lin 		afi_writel(pcie, value, AFI_FUSE);
11236e0832faSShawn Lin 	} else {
11246e0832faSShawn Lin 		value = afi_readl(pcie, AFI_FUSE);
11256e0832faSShawn Lin 		value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
11266e0832faSShawn Lin 		afi_writel(pcie, value, AFI_FUSE);
11276e0832faSShawn Lin 	}
11286e0832faSShawn Lin 
112992bd94f1SManikanta Maddireddy 	/* Disable AFI dynamic clock gating and enable PCIe */
11306e0832faSShawn Lin 	value = afi_readl(pcie, AFI_CONFIGURATION);
11316e0832faSShawn Lin 	value |= AFI_CONFIGURATION_EN_FPCI;
113292bd94f1SManikanta Maddireddy 	value |= AFI_CONFIGURATION_CLKEN_OVERRIDE;
11336e0832faSShawn Lin 	afi_writel(pcie, value, AFI_CONFIGURATION);
11346e0832faSShawn Lin 
11356e0832faSShawn Lin 	value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
11366e0832faSShawn Lin 		AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
11376e0832faSShawn Lin 		AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR;
11386e0832faSShawn Lin 
11396e0832faSShawn Lin 	if (soc->has_intr_prsnt_sense)
11406e0832faSShawn Lin 		value |= AFI_INTR_EN_PRSNT_SENSE;
11416e0832faSShawn Lin 
11426e0832faSShawn Lin 	afi_writel(pcie, value, AFI_AFI_INTR_ENABLE);
11436e0832faSShawn Lin 	afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE);
11446e0832faSShawn Lin 
11456e0832faSShawn Lin 	/* don't enable MSI for now, only when needed */
11466e0832faSShawn Lin 	afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
11476e0832faSShawn Lin 
11486e0832faSShawn Lin 	/* disable all exceptions */
11496e0832faSShawn Lin 	afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
11506e0832faSShawn Lin }
11516e0832faSShawn Lin 
tegra_pcie_power_off(struct tegra_pcie * pcie)11526e0832faSShawn Lin static void tegra_pcie_power_off(struct tegra_pcie *pcie)
11536e0832faSShawn Lin {
11546e0832faSShawn Lin 	struct device *dev = pcie->dev;
11556e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
11566e0832faSShawn Lin 	int err;
11576e0832faSShawn Lin 
11586e0832faSShawn Lin 	reset_control_assert(pcie->afi_rst);
11596e0832faSShawn Lin 
11606e0832faSShawn Lin 	clk_disable_unprepare(pcie->pll_e);
11616e0832faSShawn Lin 	if (soc->has_cml_clk)
11626e0832faSShawn Lin 		clk_disable_unprepare(pcie->cml_clk);
11636e0832faSShawn Lin 	clk_disable_unprepare(pcie->afi_clk);
11646e0832faSShawn Lin 
11656e0832faSShawn Lin 	if (!dev->pm_domain)
11666e0832faSShawn Lin 		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
11676e0832faSShawn Lin 
11686e0832faSShawn Lin 	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
11696e0832faSShawn Lin 	if (err < 0)
11706e0832faSShawn Lin 		dev_warn(dev, "failed to disable regulators: %d\n", err);
11716e0832faSShawn Lin }
11726e0832faSShawn Lin 
tegra_pcie_power_on(struct tegra_pcie * pcie)11736e0832faSShawn Lin static int tegra_pcie_power_on(struct tegra_pcie *pcie)
11746e0832faSShawn Lin {
11756e0832faSShawn Lin 	struct device *dev = pcie->dev;
11766e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
11776e0832faSShawn Lin 	int err;
11786e0832faSShawn Lin 
11796e0832faSShawn Lin 	reset_control_assert(pcie->pcie_xrst);
11806e0832faSShawn Lin 	reset_control_assert(pcie->afi_rst);
11816e0832faSShawn Lin 	reset_control_assert(pcie->pex_rst);
11826e0832faSShawn Lin 
11836e0832faSShawn Lin 	if (!dev->pm_domain)
11846e0832faSShawn Lin 		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
11856e0832faSShawn Lin 
11866e0832faSShawn Lin 	/* enable regulators */
11876e0832faSShawn Lin 	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
11886e0832faSShawn Lin 	if (err < 0)
11896e0832faSShawn Lin 		dev_err(dev, "failed to enable regulators: %d\n", err);
11906e0832faSShawn Lin 
1191d1f9113fSManikanta Maddireddy 	if (!dev->pm_domain) {
1192d1f9113fSManikanta Maddireddy 		err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE);
11936e0832faSShawn Lin 		if (err) {
1194d1f9113fSManikanta Maddireddy 			dev_err(dev, "failed to power ungate: %d\n", err);
11951056dda8SManikanta Maddireddy 			goto regulator_disable;
11966e0832faSShawn Lin 		}
1197d1f9113fSManikanta Maddireddy 		err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE);
11986e0832faSShawn Lin 		if (err) {
1199d1f9113fSManikanta Maddireddy 			dev_err(dev, "failed to remove clamp: %d\n", err);
1200d1f9113fSManikanta Maddireddy 			goto powergate;
12016e0832faSShawn Lin 		}
12026e0832faSShawn Lin 	}
12036e0832faSShawn Lin 
12046e0832faSShawn Lin 	err = clk_prepare_enable(pcie->afi_clk);
12056e0832faSShawn Lin 	if (err < 0) {
12066e0832faSShawn Lin 		dev_err(dev, "failed to enable AFI clock: %d\n", err);
12071056dda8SManikanta Maddireddy 		goto powergate;
12086e0832faSShawn Lin 	}
12096e0832faSShawn Lin 
12106e0832faSShawn Lin 	if (soc->has_cml_clk) {
12116e0832faSShawn Lin 		err = clk_prepare_enable(pcie->cml_clk);
12126e0832faSShawn Lin 		if (err < 0) {
12136e0832faSShawn Lin 			dev_err(dev, "failed to enable CML clock: %d\n", err);
12141056dda8SManikanta Maddireddy 			goto disable_afi_clk;
12156e0832faSShawn Lin 		}
12166e0832faSShawn Lin 	}
12176e0832faSShawn Lin 
12186e0832faSShawn Lin 	err = clk_prepare_enable(pcie->pll_e);
12196e0832faSShawn Lin 	if (err < 0) {
12206e0832faSShawn Lin 		dev_err(dev, "failed to enable PLLE clock: %d\n", err);
12211056dda8SManikanta Maddireddy 		goto disable_cml_clk;
12226e0832faSShawn Lin 	}
12236e0832faSShawn Lin 
1224d1f9113fSManikanta Maddireddy 	reset_control_deassert(pcie->afi_rst);
1225d1f9113fSManikanta Maddireddy 
12266e0832faSShawn Lin 	return 0;
12271056dda8SManikanta Maddireddy 
12281056dda8SManikanta Maddireddy disable_cml_clk:
12291056dda8SManikanta Maddireddy 	if (soc->has_cml_clk)
12301056dda8SManikanta Maddireddy 		clk_disable_unprepare(pcie->cml_clk);
12311056dda8SManikanta Maddireddy disable_afi_clk:
12321056dda8SManikanta Maddireddy 	clk_disable_unprepare(pcie->afi_clk);
12331056dda8SManikanta Maddireddy powergate:
12341056dda8SManikanta Maddireddy 	if (!dev->pm_domain)
12351056dda8SManikanta Maddireddy 		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
12361056dda8SManikanta Maddireddy regulator_disable:
12371056dda8SManikanta Maddireddy 	regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
12381056dda8SManikanta Maddireddy 
12391056dda8SManikanta Maddireddy 	return err;
12406e0832faSShawn Lin }
12416e0832faSShawn Lin 
tegra_pcie_apply_pad_settings(struct tegra_pcie * pcie)1242973d7499SManikanta Maddireddy static void tegra_pcie_apply_pad_settings(struct tegra_pcie *pcie)
1243973d7499SManikanta Maddireddy {
1244973d7499SManikanta Maddireddy 	const struct tegra_pcie_soc *soc = pcie->soc;
1245973d7499SManikanta Maddireddy 
1246973d7499SManikanta Maddireddy 	/* Configure the reference clock driver */
1247973d7499SManikanta Maddireddy 	pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
1248973d7499SManikanta Maddireddy 
1249973d7499SManikanta Maddireddy 	if (soc->num_ports > 2)
1250973d7499SManikanta Maddireddy 		pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
1251973d7499SManikanta Maddireddy }
1252973d7499SManikanta Maddireddy 
tegra_pcie_clocks_get(struct tegra_pcie * pcie)12536e0832faSShawn Lin static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
12546e0832faSShawn Lin {
12556e0832faSShawn Lin 	struct device *dev = pcie->dev;
12566e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
12576e0832faSShawn Lin 
12586e0832faSShawn Lin 	pcie->pex_clk = devm_clk_get(dev, "pex");
12596e0832faSShawn Lin 	if (IS_ERR(pcie->pex_clk))
12606e0832faSShawn Lin 		return PTR_ERR(pcie->pex_clk);
12616e0832faSShawn Lin 
12626e0832faSShawn Lin 	pcie->afi_clk = devm_clk_get(dev, "afi");
12636e0832faSShawn Lin 	if (IS_ERR(pcie->afi_clk))
12646e0832faSShawn Lin 		return PTR_ERR(pcie->afi_clk);
12656e0832faSShawn Lin 
12666e0832faSShawn Lin 	pcie->pll_e = devm_clk_get(dev, "pll_e");
12676e0832faSShawn Lin 	if (IS_ERR(pcie->pll_e))
12686e0832faSShawn Lin 		return PTR_ERR(pcie->pll_e);
12696e0832faSShawn Lin 
12706e0832faSShawn Lin 	if (soc->has_cml_clk) {
12716e0832faSShawn Lin 		pcie->cml_clk = devm_clk_get(dev, "cml");
12726e0832faSShawn Lin 		if (IS_ERR(pcie->cml_clk))
12736e0832faSShawn Lin 			return PTR_ERR(pcie->cml_clk);
12746e0832faSShawn Lin 	}
12756e0832faSShawn Lin 
12766e0832faSShawn Lin 	return 0;
12776e0832faSShawn Lin }
12786e0832faSShawn Lin 
tegra_pcie_resets_get(struct tegra_pcie * pcie)12796e0832faSShawn Lin static int tegra_pcie_resets_get(struct tegra_pcie *pcie)
12806e0832faSShawn Lin {
12816e0832faSShawn Lin 	struct device *dev = pcie->dev;
12826e0832faSShawn Lin 
12836e0832faSShawn Lin 	pcie->pex_rst = devm_reset_control_get_exclusive(dev, "pex");
12846e0832faSShawn Lin 	if (IS_ERR(pcie->pex_rst))
12856e0832faSShawn Lin 		return PTR_ERR(pcie->pex_rst);
12866e0832faSShawn Lin 
12876e0832faSShawn Lin 	pcie->afi_rst = devm_reset_control_get_exclusive(dev, "afi");
12886e0832faSShawn Lin 	if (IS_ERR(pcie->afi_rst))
12896e0832faSShawn Lin 		return PTR_ERR(pcie->afi_rst);
12906e0832faSShawn Lin 
12916e0832faSShawn Lin 	pcie->pcie_xrst = devm_reset_control_get_exclusive(dev, "pcie_x");
12926e0832faSShawn Lin 	if (IS_ERR(pcie->pcie_xrst))
12936e0832faSShawn Lin 		return PTR_ERR(pcie->pcie_xrst);
12946e0832faSShawn Lin 
12956e0832faSShawn Lin 	return 0;
12966e0832faSShawn Lin }
12976e0832faSShawn Lin 
tegra_pcie_phys_get_legacy(struct tegra_pcie * pcie)12986e0832faSShawn Lin static int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie)
12996e0832faSShawn Lin {
13006e0832faSShawn Lin 	struct device *dev = pcie->dev;
13016e0832faSShawn Lin 	int err;
13026e0832faSShawn Lin 
13036e0832faSShawn Lin 	pcie->phy = devm_phy_optional_get(dev, "pcie");
13046e0832faSShawn Lin 	if (IS_ERR(pcie->phy)) {
13056e0832faSShawn Lin 		err = PTR_ERR(pcie->phy);
13066e0832faSShawn Lin 		dev_err(dev, "failed to get PHY: %d\n", err);
13076e0832faSShawn Lin 		return err;
13086e0832faSShawn Lin 	}
13096e0832faSShawn Lin 
13106e0832faSShawn Lin 	err = phy_init(pcie->phy);
13116e0832faSShawn Lin 	if (err < 0) {
13126e0832faSShawn Lin 		dev_err(dev, "failed to initialize PHY: %d\n", err);
13136e0832faSShawn Lin 		return err;
13146e0832faSShawn Lin 	}
13156e0832faSShawn Lin 
13166e0832faSShawn Lin 	pcie->legacy_phy = true;
13176e0832faSShawn Lin 
13186e0832faSShawn Lin 	return 0;
13196e0832faSShawn Lin }
13206e0832faSShawn Lin 
devm_of_phy_optional_get_index(struct device * dev,struct device_node * np,const char * consumer,unsigned int index)13216e0832faSShawn Lin static struct phy *devm_of_phy_optional_get_index(struct device *dev,
13226e0832faSShawn Lin 						  struct device_node *np,
13236e0832faSShawn Lin 						  const char *consumer,
13246e0832faSShawn Lin 						  unsigned int index)
13256e0832faSShawn Lin {
13266e0832faSShawn Lin 	struct phy *phy;
13276e0832faSShawn Lin 	char *name;
13286e0832faSShawn Lin 
13296e0832faSShawn Lin 	name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index);
13306e0832faSShawn Lin 	if (!name)
13316e0832faSShawn Lin 		return ERR_PTR(-ENOMEM);
13326e0832faSShawn Lin 
1333a80becc5SGeert Uytterhoeven 	phy = devm_of_phy_optional_get(dev, np, name);
13346e0832faSShawn Lin 	kfree(name);
13356e0832faSShawn Lin 
13366e0832faSShawn Lin 	return phy;
13376e0832faSShawn Lin }
13386e0832faSShawn Lin 
tegra_pcie_port_get_phys(struct tegra_pcie_port * port)13396e0832faSShawn Lin static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port)
13406e0832faSShawn Lin {
13416e0832faSShawn Lin 	struct device *dev = port->pcie->dev;
13426e0832faSShawn Lin 	struct phy *phy;
13436e0832faSShawn Lin 	unsigned int i;
13446e0832faSShawn Lin 	int err;
13456e0832faSShawn Lin 
13466e0832faSShawn Lin 	port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL);
13476e0832faSShawn Lin 	if (!port->phys)
13486e0832faSShawn Lin 		return -ENOMEM;
13496e0832faSShawn Lin 
13506e0832faSShawn Lin 	for (i = 0; i < port->lanes; i++) {
13516e0832faSShawn Lin 		phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i);
13526e0832faSShawn Lin 		if (IS_ERR(phy)) {
13536e0832faSShawn Lin 			dev_err(dev, "failed to get PHY#%u: %ld\n", i,
13546e0832faSShawn Lin 				PTR_ERR(phy));
13556e0832faSShawn Lin 			return PTR_ERR(phy);
13566e0832faSShawn Lin 		}
13576e0832faSShawn Lin 
13586e0832faSShawn Lin 		err = phy_init(phy);
13596e0832faSShawn Lin 		if (err < 0) {
13606e0832faSShawn Lin 			dev_err(dev, "failed to initialize PHY#%u: %d\n", i,
13616e0832faSShawn Lin 				err);
13626e0832faSShawn Lin 			return err;
13636e0832faSShawn Lin 		}
13646e0832faSShawn Lin 
13656e0832faSShawn Lin 		port->phys[i] = phy;
13666e0832faSShawn Lin 	}
13676e0832faSShawn Lin 
13686e0832faSShawn Lin 	return 0;
13696e0832faSShawn Lin }
13706e0832faSShawn Lin 
tegra_pcie_phys_get(struct tegra_pcie * pcie)13716e0832faSShawn Lin static int tegra_pcie_phys_get(struct tegra_pcie *pcie)
13726e0832faSShawn Lin {
13736e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
13746e0832faSShawn Lin 	struct device_node *np = pcie->dev->of_node;
13756e0832faSShawn Lin 	struct tegra_pcie_port *port;
13766e0832faSShawn Lin 	int err;
13776e0832faSShawn Lin 
1378*9195ee1aSRob Herring 	if (!soc->has_gen2 || of_property_present(np, "phys"))
13796e0832faSShawn Lin 		return tegra_pcie_phys_get_legacy(pcie);
13806e0832faSShawn Lin 
13816e0832faSShawn Lin 	list_for_each_entry(port, &pcie->ports, list) {
13826e0832faSShawn Lin 		err = tegra_pcie_port_get_phys(port);
13836e0832faSShawn Lin 		if (err < 0)
13846e0832faSShawn Lin 			return err;
13856e0832faSShawn Lin 	}
13866e0832faSShawn Lin 
13876e0832faSShawn Lin 	return 0;
13886e0832faSShawn Lin }
13896e0832faSShawn Lin 
tegra_pcie_phys_put(struct tegra_pcie * pcie)13906e0832faSShawn Lin static void tegra_pcie_phys_put(struct tegra_pcie *pcie)
13916e0832faSShawn Lin {
13926e0832faSShawn Lin 	struct tegra_pcie_port *port;
13936e0832faSShawn Lin 	struct device *dev = pcie->dev;
13946e0832faSShawn Lin 	int err, i;
13956e0832faSShawn Lin 
13966e0832faSShawn Lin 	if (pcie->legacy_phy) {
13976e0832faSShawn Lin 		err = phy_exit(pcie->phy);
13986e0832faSShawn Lin 		if (err < 0)
13996e0832faSShawn Lin 			dev_err(dev, "failed to teardown PHY: %d\n", err);
14006e0832faSShawn Lin 		return;
14016e0832faSShawn Lin 	}
14026e0832faSShawn Lin 
14036e0832faSShawn Lin 	list_for_each_entry(port, &pcie->ports, list) {
14046e0832faSShawn Lin 		for (i = 0; i < port->lanes; i++) {
14056e0832faSShawn Lin 			err = phy_exit(port->phys[i]);
14066e0832faSShawn Lin 			if (err < 0)
14076e0832faSShawn Lin 				dev_err(dev, "failed to teardown PHY#%u: %d\n",
14086e0832faSShawn Lin 					i, err);
14096e0832faSShawn Lin 		}
14106e0832faSShawn Lin 	}
14116e0832faSShawn Lin }
14126e0832faSShawn Lin 
tegra_pcie_get_resources(struct tegra_pcie * pcie)14136e0832faSShawn Lin static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
14146e0832faSShawn Lin {
14156e0832faSShawn Lin 	struct device *dev = pcie->dev;
14166e0832faSShawn Lin 	struct platform_device *pdev = to_platform_device(dev);
1417e2dcd20bSDejin Zheng 	struct resource *res;
14186e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
14196e0832faSShawn Lin 	int err;
14206e0832faSShawn Lin 
14216e0832faSShawn Lin 	err = tegra_pcie_clocks_get(pcie);
14226e0832faSShawn Lin 	if (err) {
14236e0832faSShawn Lin 		dev_err(dev, "failed to get clocks: %d\n", err);
14246e0832faSShawn Lin 		return err;
14256e0832faSShawn Lin 	}
14266e0832faSShawn Lin 
14276e0832faSShawn Lin 	err = tegra_pcie_resets_get(pcie);
14286e0832faSShawn Lin 	if (err) {
14296e0832faSShawn Lin 		dev_err(dev, "failed to get resets: %d\n", err);
14306e0832faSShawn Lin 		return err;
14316e0832faSShawn Lin 	}
14326e0832faSShawn Lin 
14336e0832faSShawn Lin 	if (soc->program_uphy) {
14346e0832faSShawn Lin 		err = tegra_pcie_phys_get(pcie);
14356e0832faSShawn Lin 		if (err < 0) {
14366e0832faSShawn Lin 			dev_err(dev, "failed to get PHYs: %d\n", err);
14376e0832faSShawn Lin 			return err;
14386e0832faSShawn Lin 		}
14396e0832faSShawn Lin 	}
14406e0832faSShawn Lin 
1441e2dcd20bSDejin Zheng 	pcie->pads = devm_platform_ioremap_resource_byname(pdev, "pads");
14426e0832faSShawn Lin 	if (IS_ERR(pcie->pads)) {
14436e0832faSShawn Lin 		err = PTR_ERR(pcie->pads);
14446e0832faSShawn Lin 		goto phys_put;
14456e0832faSShawn Lin 	}
14466e0832faSShawn Lin 
1447e2dcd20bSDejin Zheng 	pcie->afi = devm_platform_ioremap_resource_byname(pdev, "afi");
14486e0832faSShawn Lin 	if (IS_ERR(pcie->afi)) {
14496e0832faSShawn Lin 		err = PTR_ERR(pcie->afi);
14506e0832faSShawn Lin 		goto phys_put;
14516e0832faSShawn Lin 	}
14526e0832faSShawn Lin 
14536e0832faSShawn Lin 	/* request configuration space, but remap later, on demand */
14546e0832faSShawn Lin 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs");
14556e0832faSShawn Lin 	if (!res) {
14566e0832faSShawn Lin 		err = -EADDRNOTAVAIL;
14576e0832faSShawn Lin 		goto phys_put;
14586e0832faSShawn Lin 	}
14596e0832faSShawn Lin 
14606e0832faSShawn Lin 	pcie->cs = *res;
14616e0832faSShawn Lin 
14626e0832faSShawn Lin 	/* constrain configuration space to 4 KiB */
14636e0832faSShawn Lin 	pcie->cs.end = pcie->cs.start + SZ_4K - 1;
14646e0832faSShawn Lin 
14656e0832faSShawn Lin 	pcie->cfg = devm_ioremap_resource(dev, &pcie->cs);
14666e0832faSShawn Lin 	if (IS_ERR(pcie->cfg)) {
14676e0832faSShawn Lin 		err = PTR_ERR(pcie->cfg);
14686e0832faSShawn Lin 		goto phys_put;
14696e0832faSShawn Lin 	}
14706e0832faSShawn Lin 
14716e0832faSShawn Lin 	/* request interrupt */
14726e0832faSShawn Lin 	err = platform_get_irq_byname(pdev, "intr");
1473caecb05cSKrzysztof Wilczyński 	if (err < 0)
14746e0832faSShawn Lin 		goto phys_put;
14756e0832faSShawn Lin 
14766e0832faSShawn Lin 	pcie->irq = err;
14776e0832faSShawn Lin 
14786e0832faSShawn Lin 	err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE", pcie);
14796e0832faSShawn Lin 	if (err) {
14806e0832faSShawn Lin 		dev_err(dev, "failed to register IRQ: %d\n", err);
14816e0832faSShawn Lin 		goto phys_put;
14826e0832faSShawn Lin 	}
14836e0832faSShawn Lin 
14846e0832faSShawn Lin 	return 0;
14856e0832faSShawn Lin 
14866e0832faSShawn Lin phys_put:
14876e0832faSShawn Lin 	if (soc->program_uphy)
14886e0832faSShawn Lin 		tegra_pcie_phys_put(pcie);
14892c99e55fSMarc Zyngier 
14906e0832faSShawn Lin 	return err;
14916e0832faSShawn Lin }
14926e0832faSShawn Lin 
tegra_pcie_put_resources(struct tegra_pcie * pcie)14936e0832faSShawn Lin static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
14946e0832faSShawn Lin {
14956e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
14966e0832faSShawn Lin 
14976e0832faSShawn Lin 	if (pcie->irq > 0)
14986e0832faSShawn Lin 		free_irq(pcie->irq, pcie);
14996e0832faSShawn Lin 
15006e0832faSShawn Lin 	if (soc->program_uphy)
15016e0832faSShawn Lin 		tegra_pcie_phys_put(pcie);
15026e0832faSShawn Lin 
15036e0832faSShawn Lin 	return 0;
15046e0832faSShawn Lin }
15056e0832faSShawn Lin 
tegra_pcie_pme_turnoff(struct tegra_pcie_port * port)15066e0832faSShawn Lin static void tegra_pcie_pme_turnoff(struct tegra_pcie_port *port)
15076e0832faSShawn Lin {
15086e0832faSShawn Lin 	struct tegra_pcie *pcie = port->pcie;
15096e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
15106e0832faSShawn Lin 	int err;
15116e0832faSShawn Lin 	u32 val;
15126e0832faSShawn Lin 	u8 ack_bit;
15136e0832faSShawn Lin 
15146e0832faSShawn Lin 	val = afi_readl(pcie, AFI_PCIE_PME);
15156e0832faSShawn Lin 	val |= (0x1 << soc->ports[port->index].pme.turnoff_bit);
15166e0832faSShawn Lin 	afi_writel(pcie, val, AFI_PCIE_PME);
15176e0832faSShawn Lin 
15186e0832faSShawn Lin 	ack_bit = soc->ports[port->index].pme.ack_bit;
15196e0832faSShawn Lin 	err = readl_poll_timeout(pcie->afi + AFI_PCIE_PME, val,
15206e0832faSShawn Lin 				 val & (0x1 << ack_bit), 1, PME_ACK_TIMEOUT);
15216e0832faSShawn Lin 	if (err)
15226e0832faSShawn Lin 		dev_err(pcie->dev, "PME Ack is not received on port: %d\n",
15236e0832faSShawn Lin 			port->index);
15246e0832faSShawn Lin 
15256e0832faSShawn Lin 	usleep_range(10000, 11000);
15266e0832faSShawn Lin 
15276e0832faSShawn Lin 	val = afi_readl(pcie, AFI_PCIE_PME);
15286e0832faSShawn Lin 	val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit);
15296e0832faSShawn Lin 	afi_writel(pcie, val, AFI_PCIE_PME);
15306e0832faSShawn Lin }
15316e0832faSShawn Lin 
tegra_pcie_msi_irq(struct irq_desc * desc)15322c99e55fSMarc Zyngier static void tegra_pcie_msi_irq(struct irq_desc *desc)
15336e0832faSShawn Lin {
15342c99e55fSMarc Zyngier 	struct tegra_pcie *pcie = irq_desc_get_handler_data(desc);
15352c99e55fSMarc Zyngier 	struct irq_chip *chip = irq_desc_get_chip(desc);
15366e0832faSShawn Lin 	struct tegra_msi *msi = &pcie->msi;
15372c99e55fSMarc Zyngier 	struct device *dev = pcie->dev;
15382c99e55fSMarc Zyngier 	unsigned int i;
15392c99e55fSMarc Zyngier 
15402c99e55fSMarc Zyngier 	chained_irq_enter(chip, desc);
15416e0832faSShawn Lin 
15426e0832faSShawn Lin 	for (i = 0; i < 8; i++) {
15432c99e55fSMarc Zyngier 		unsigned long reg = afi_readl(pcie, AFI_MSI_VEC(i));
15446e0832faSShawn Lin 
15456e0832faSShawn Lin 		while (reg) {
15466e0832faSShawn Lin 			unsigned int offset = find_first_bit(&reg, 32);
15476e0832faSShawn Lin 			unsigned int index = i * 32 + offset;
1548d21faba1SMarc Zyngier 			int ret;
15496e0832faSShawn Lin 
1550d21faba1SMarc Zyngier 			ret = generic_handle_domain_irq(msi->domain->parent, index);
1551d21faba1SMarc Zyngier 			if (ret) {
15526e0832faSShawn Lin 				/*
15536e0832faSShawn Lin 				 * that's weird who triggered this?
15546e0832faSShawn Lin 				 * just clear it
15556e0832faSShawn Lin 				 */
15566e0832faSShawn Lin 				dev_info(dev, "unexpected MSI\n");
15572c99e55fSMarc Zyngier 				afi_writel(pcie, BIT(index % 32), AFI_MSI_VEC(index));
15586e0832faSShawn Lin 			}
15596e0832faSShawn Lin 
15606e0832faSShawn Lin 			/* see if there's any more pending in this vector */
15612c99e55fSMarc Zyngier 			reg = afi_readl(pcie, AFI_MSI_VEC(i));
15626e0832faSShawn Lin 		}
15636e0832faSShawn Lin 	}
15646e0832faSShawn Lin 
15652c99e55fSMarc Zyngier 	chained_irq_exit(chip, desc);
15666e0832faSShawn Lin }
15676e0832faSShawn Lin 
tegra_msi_top_irq_ack(struct irq_data * d)15682c99e55fSMarc Zyngier static void tegra_msi_top_irq_ack(struct irq_data *d)
15696e0832faSShawn Lin {
15702c99e55fSMarc Zyngier 	irq_chip_ack_parent(d);
15712c99e55fSMarc Zyngier }
15726e0832faSShawn Lin 
tegra_msi_top_irq_mask(struct irq_data * d)15732c99e55fSMarc Zyngier static void tegra_msi_top_irq_mask(struct irq_data *d)
15742c99e55fSMarc Zyngier {
15752c99e55fSMarc Zyngier 	pci_msi_mask_irq(d);
15762c99e55fSMarc Zyngier 	irq_chip_mask_parent(d);
15772c99e55fSMarc Zyngier }
15786e0832faSShawn Lin 
tegra_msi_top_irq_unmask(struct irq_data * d)15792c99e55fSMarc Zyngier static void tegra_msi_top_irq_unmask(struct irq_data *d)
15802c99e55fSMarc Zyngier {
15812c99e55fSMarc Zyngier 	pci_msi_unmask_irq(d);
15822c99e55fSMarc Zyngier 	irq_chip_unmask_parent(d);
15832c99e55fSMarc Zyngier }
15842c99e55fSMarc Zyngier 
15852c99e55fSMarc Zyngier static struct irq_chip tegra_msi_top_chip = {
15862c99e55fSMarc Zyngier 	.name		= "Tegra PCIe MSI",
15872c99e55fSMarc Zyngier 	.irq_ack	= tegra_msi_top_irq_ack,
15882c99e55fSMarc Zyngier 	.irq_mask	= tegra_msi_top_irq_mask,
15892c99e55fSMarc Zyngier 	.irq_unmask	= tegra_msi_top_irq_unmask,
15902c99e55fSMarc Zyngier };
15912c99e55fSMarc Zyngier 
tegra_msi_irq_ack(struct irq_data * d)15922c99e55fSMarc Zyngier static void tegra_msi_irq_ack(struct irq_data *d)
15932c99e55fSMarc Zyngier {
15942c99e55fSMarc Zyngier 	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
15952c99e55fSMarc Zyngier 	struct tegra_pcie *pcie = msi_to_pcie(msi);
15962c99e55fSMarc Zyngier 	unsigned int index = d->hwirq / 32;
15972c99e55fSMarc Zyngier 
15982c99e55fSMarc Zyngier 	/* clear the interrupt */
15992c99e55fSMarc Zyngier 	afi_writel(pcie, BIT(d->hwirq % 32), AFI_MSI_VEC(index));
16002c99e55fSMarc Zyngier }
16012c99e55fSMarc Zyngier 
tegra_msi_irq_mask(struct irq_data * d)16022c99e55fSMarc Zyngier static void tegra_msi_irq_mask(struct irq_data *d)
16032c99e55fSMarc Zyngier {
16042c99e55fSMarc Zyngier 	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
16052c99e55fSMarc Zyngier 	struct tegra_pcie *pcie = msi_to_pcie(msi);
16062c99e55fSMarc Zyngier 	unsigned int index = d->hwirq / 32;
16072c99e55fSMarc Zyngier 	unsigned long flags;
16082c99e55fSMarc Zyngier 	u32 value;
16092c99e55fSMarc Zyngier 
16102c99e55fSMarc Zyngier 	spin_lock_irqsave(&msi->mask_lock, flags);
16112c99e55fSMarc Zyngier 	value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
16122c99e55fSMarc Zyngier 	value &= ~BIT(d->hwirq % 32);
16132c99e55fSMarc Zyngier 	afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
16142c99e55fSMarc Zyngier 	spin_unlock_irqrestore(&msi->mask_lock, flags);
16152c99e55fSMarc Zyngier }
16162c99e55fSMarc Zyngier 
tegra_msi_irq_unmask(struct irq_data * d)16172c99e55fSMarc Zyngier static void tegra_msi_irq_unmask(struct irq_data *d)
16182c99e55fSMarc Zyngier {
16192c99e55fSMarc Zyngier 	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
16202c99e55fSMarc Zyngier 	struct tegra_pcie *pcie = msi_to_pcie(msi);
16212c99e55fSMarc Zyngier 	unsigned int index = d->hwirq / 32;
16222c99e55fSMarc Zyngier 	unsigned long flags;
16232c99e55fSMarc Zyngier 	u32 value;
16242c99e55fSMarc Zyngier 
16252c99e55fSMarc Zyngier 	spin_lock_irqsave(&msi->mask_lock, flags);
16262c99e55fSMarc Zyngier 	value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
16272c99e55fSMarc Zyngier 	value |= BIT(d->hwirq % 32);
16282c99e55fSMarc Zyngier 	afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
16292c99e55fSMarc Zyngier 	spin_unlock_irqrestore(&msi->mask_lock, flags);
16302c99e55fSMarc Zyngier }
16312c99e55fSMarc Zyngier 
tegra_msi_set_affinity(struct irq_data * d,const struct cpumask * mask,bool force)16322c99e55fSMarc Zyngier static int tegra_msi_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
16332c99e55fSMarc Zyngier {
16346e0832faSShawn Lin 	return -EINVAL;
16356e0832faSShawn Lin }
16366e0832faSShawn Lin 
tegra_compose_msi_msg(struct irq_data * data,struct msi_msg * msg)16372c99e55fSMarc Zyngier static void tegra_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
16386e0832faSShawn Lin {
16392c99e55fSMarc Zyngier 	struct tegra_msi *msi = irq_data_get_irq_chip_data(data);
16406e0832faSShawn Lin 
16412c99e55fSMarc Zyngier 	msg->address_lo = lower_32_bits(msi->phys);
16422c99e55fSMarc Zyngier 	msg->address_hi = upper_32_bits(msi->phys);
16432c99e55fSMarc Zyngier 	msg->data = data->hwirq;
16446e0832faSShawn Lin }
16456e0832faSShawn Lin 
16462c99e55fSMarc Zyngier static struct irq_chip tegra_msi_bottom_chip = {
16472c99e55fSMarc Zyngier 	.name			= "Tegra MSI",
16482c99e55fSMarc Zyngier 	.irq_ack		= tegra_msi_irq_ack,
16492c99e55fSMarc Zyngier 	.irq_mask		= tegra_msi_irq_mask,
16502c99e55fSMarc Zyngier 	.irq_unmask		= tegra_msi_irq_unmask,
16512c99e55fSMarc Zyngier 	.irq_set_affinity 	= tegra_msi_set_affinity,
16522c99e55fSMarc Zyngier 	.irq_compose_msi_msg	= tegra_compose_msi_msg,
16536e0832faSShawn Lin };
16546e0832faSShawn Lin 
tegra_msi_domain_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * args)16552c99e55fSMarc Zyngier static int tegra_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
16562c99e55fSMarc Zyngier 				  unsigned int nr_irqs, void *args)
16576e0832faSShawn Lin {
16582c99e55fSMarc Zyngier 	struct tegra_msi *msi = domain->host_data;
16592c99e55fSMarc Zyngier 	unsigned int i;
16602c99e55fSMarc Zyngier 	int hwirq;
16612c99e55fSMarc Zyngier 
16622c99e55fSMarc Zyngier 	mutex_lock(&msi->map_lock);
16632c99e55fSMarc Zyngier 
16642c99e55fSMarc Zyngier 	hwirq = bitmap_find_free_region(msi->used, INT_PCI_MSI_NR, order_base_2(nr_irqs));
16652c99e55fSMarc Zyngier 
16662c99e55fSMarc Zyngier 	mutex_unlock(&msi->map_lock);
16672c99e55fSMarc Zyngier 
16682c99e55fSMarc Zyngier 	if (hwirq < 0)
16692c99e55fSMarc Zyngier 		return -ENOSPC;
16702c99e55fSMarc Zyngier 
16712c99e55fSMarc Zyngier 	for (i = 0; i < nr_irqs; i++)
16722c99e55fSMarc Zyngier 		irq_domain_set_info(domain, virq + i, hwirq + i,
16732c99e55fSMarc Zyngier 				    &tegra_msi_bottom_chip, domain->host_data,
16742c99e55fSMarc Zyngier 				    handle_edge_irq, NULL, NULL);
16756e0832faSShawn Lin 
16766e0832faSShawn Lin 	tegra_cpuidle_pcie_irqs_in_use();
16776e0832faSShawn Lin 
16786e0832faSShawn Lin 	return 0;
16796e0832faSShawn Lin }
16806e0832faSShawn Lin 
tegra_msi_domain_free(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs)16812c99e55fSMarc Zyngier static void tegra_msi_domain_free(struct irq_domain *domain, unsigned int virq,
16822c99e55fSMarc Zyngier 				  unsigned int nr_irqs)
16832c99e55fSMarc Zyngier {
16842c99e55fSMarc Zyngier 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
16852c99e55fSMarc Zyngier 	struct tegra_msi *msi = domain->host_data;
16862c99e55fSMarc Zyngier 
16872c99e55fSMarc Zyngier 	mutex_lock(&msi->map_lock);
16882c99e55fSMarc Zyngier 
16892c99e55fSMarc Zyngier 	bitmap_release_region(msi->used, d->hwirq, order_base_2(nr_irqs));
16902c99e55fSMarc Zyngier 
16912c99e55fSMarc Zyngier 	mutex_unlock(&msi->map_lock);
16922c99e55fSMarc Zyngier }
16932c99e55fSMarc Zyngier 
16942c99e55fSMarc Zyngier static const struct irq_domain_ops tegra_msi_domain_ops = {
16952c99e55fSMarc Zyngier 	.alloc = tegra_msi_domain_alloc,
16962c99e55fSMarc Zyngier 	.free = tegra_msi_domain_free,
16976e0832faSShawn Lin };
16986e0832faSShawn Lin 
16992c99e55fSMarc Zyngier static struct msi_domain_info tegra_msi_info = {
17002c99e55fSMarc Zyngier 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
17012c99e55fSMarc Zyngier 		   MSI_FLAG_PCI_MSIX),
17022c99e55fSMarc Zyngier 	.chip	= &tegra_msi_top_chip,
17032c99e55fSMarc Zyngier };
17042c99e55fSMarc Zyngier 
tegra_allocate_domains(struct tegra_msi * msi)17052c99e55fSMarc Zyngier static int tegra_allocate_domains(struct tegra_msi *msi)
17062c99e55fSMarc Zyngier {
17072c99e55fSMarc Zyngier 	struct tegra_pcie *pcie = msi_to_pcie(msi);
17082c99e55fSMarc Zyngier 	struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
17092c99e55fSMarc Zyngier 	struct irq_domain *parent;
17102c99e55fSMarc Zyngier 
17112c99e55fSMarc Zyngier 	parent = irq_domain_create_linear(fwnode, INT_PCI_MSI_NR,
17122c99e55fSMarc Zyngier 					  &tegra_msi_domain_ops, msi);
17132c99e55fSMarc Zyngier 	if (!parent) {
17142c99e55fSMarc Zyngier 		dev_err(pcie->dev, "failed to create IRQ domain\n");
17152c99e55fSMarc Zyngier 		return -ENOMEM;
17162c99e55fSMarc Zyngier 	}
17172c99e55fSMarc Zyngier 	irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
17182c99e55fSMarc Zyngier 
17192c99e55fSMarc Zyngier 	msi->domain = pci_msi_create_irq_domain(fwnode, &tegra_msi_info, parent);
17202c99e55fSMarc Zyngier 	if (!msi->domain) {
17212c99e55fSMarc Zyngier 		dev_err(pcie->dev, "failed to create MSI domain\n");
17222c99e55fSMarc Zyngier 		irq_domain_remove(parent);
17232c99e55fSMarc Zyngier 		return -ENOMEM;
17242c99e55fSMarc Zyngier 	}
17252c99e55fSMarc Zyngier 
17262c99e55fSMarc Zyngier 	return 0;
17272c99e55fSMarc Zyngier }
17282c99e55fSMarc Zyngier 
tegra_free_domains(struct tegra_msi * msi)17292c99e55fSMarc Zyngier static void tegra_free_domains(struct tegra_msi *msi)
17302c99e55fSMarc Zyngier {
17312c99e55fSMarc Zyngier 	struct irq_domain *parent = msi->domain->parent;
17322c99e55fSMarc Zyngier 
17332c99e55fSMarc Zyngier 	irq_domain_remove(msi->domain);
17342c99e55fSMarc Zyngier 	irq_domain_remove(parent);
17352c99e55fSMarc Zyngier }
17362c99e55fSMarc Zyngier 
tegra_pcie_msi_setup(struct tegra_pcie * pcie)17376e0832faSShawn Lin static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
17386e0832faSShawn Lin {
17396e0832faSShawn Lin 	struct platform_device *pdev = to_platform_device(pcie->dev);
17406e0832faSShawn Lin 	struct tegra_msi *msi = &pcie->msi;
17416e0832faSShawn Lin 	struct device *dev = pcie->dev;
17426e0832faSShawn Lin 	int err;
17436e0832faSShawn Lin 
17442c99e55fSMarc Zyngier 	mutex_init(&msi->map_lock);
17452c99e55fSMarc Zyngier 	spin_lock_init(&msi->mask_lock);
17466e0832faSShawn Lin 
17472c99e55fSMarc Zyngier 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
17482c99e55fSMarc Zyngier 		err = tegra_allocate_domains(msi);
17492c99e55fSMarc Zyngier 		if (err)
17502c99e55fSMarc Zyngier 			return err;
17516e0832faSShawn Lin 	}
17526e0832faSShawn Lin 
17536e0832faSShawn Lin 	err = platform_get_irq_byname(pdev, "msi");
1754caecb05cSKrzysztof Wilczyński 	if (err < 0)
175521e2079fSVidya Sagar 		goto free_irq_domain;
17566e0832faSShawn Lin 
17576e0832faSShawn Lin 	msi->irq = err;
17586e0832faSShawn Lin 
17592c99e55fSMarc Zyngier 	irq_set_chained_handler_and_data(msi->irq, tegra_pcie_msi_irq, pcie);
17606e0832faSShawn Lin 
176121e2079fSVidya Sagar 	/* Though the PCIe controller can address >32-bit address space, to
176221e2079fSVidya Sagar 	 * facilitate endpoints that support only 32-bit MSI target address,
176321e2079fSVidya Sagar 	 * the mask is set to 32-bit to make sure that MSI target address is
176421e2079fSVidya Sagar 	 * always a 32-bit address
176521e2079fSVidya Sagar 	 */
176621e2079fSVidya Sagar 	err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
176721e2079fSVidya Sagar 	if (err < 0) {
176821e2079fSVidya Sagar 		dev_err(dev, "failed to set DMA coherent mask: %d\n", err);
176921e2079fSVidya Sagar 		goto free_irq;
177021e2079fSVidya Sagar 	}
177121e2079fSVidya Sagar 
177221e2079fSVidya Sagar 	msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
177321e2079fSVidya Sagar 				    DMA_ATTR_NO_KERNEL_MAPPING);
177421e2079fSVidya Sagar 	if (!msi->virt) {
177521e2079fSVidya Sagar 		dev_err(dev, "failed to allocate DMA memory for MSI\n");
177621e2079fSVidya Sagar 		err = -ENOMEM;
177721e2079fSVidya Sagar 		goto free_irq;
177821e2079fSVidya Sagar 	}
177921e2079fSVidya Sagar 
17806e0832faSShawn Lin 	return 0;
17816e0832faSShawn Lin 
178221e2079fSVidya Sagar free_irq:
17832c99e55fSMarc Zyngier 	irq_set_chained_handler_and_data(msi->irq, NULL, NULL);
178421e2079fSVidya Sagar free_irq_domain:
17852c99e55fSMarc Zyngier 	if (IS_ENABLED(CONFIG_PCI_MSI))
17862c99e55fSMarc Zyngier 		tegra_free_domains(msi);
17872c99e55fSMarc Zyngier 
17886e0832faSShawn Lin 	return err;
17896e0832faSShawn Lin }
17906e0832faSShawn Lin 
tegra_pcie_enable_msi(struct tegra_pcie * pcie)17916e0832faSShawn Lin static void tegra_pcie_enable_msi(struct tegra_pcie *pcie)
17926e0832faSShawn Lin {
17936e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
17946e0832faSShawn Lin 	struct tegra_msi *msi = &pcie->msi;
17952c99e55fSMarc Zyngier 	u32 reg, msi_state[INT_PCI_MSI_NR / 32];
17962c99e55fSMarc Zyngier 	int i;
17976e0832faSShawn Lin 
17986e0832faSShawn Lin 	afi_writel(pcie, msi->phys >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
17996e0832faSShawn Lin 	afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST);
18006e0832faSShawn Lin 	/* this register is in 4K increments */
18016e0832faSShawn Lin 	afi_writel(pcie, 1, AFI_MSI_BAR_SZ);
18026e0832faSShawn Lin 
18032c99e55fSMarc Zyngier 	/* Restore the MSI allocation state */
18042c99e55fSMarc Zyngier 	bitmap_to_arr32(msi_state, msi->used, INT_PCI_MSI_NR);
18052c99e55fSMarc Zyngier 	for (i = 0; i < ARRAY_SIZE(msi_state); i++)
18062c99e55fSMarc Zyngier 		afi_writel(pcie, msi_state[i], AFI_MSI_EN_VEC(i));
18076e0832faSShawn Lin 
18086e0832faSShawn Lin 	/* and unmask the MSI interrupt */
18096e0832faSShawn Lin 	reg = afi_readl(pcie, AFI_INTR_MASK);
18106e0832faSShawn Lin 	reg |= AFI_INTR_MASK_MSI_MASK;
18116e0832faSShawn Lin 	afi_writel(pcie, reg, AFI_INTR_MASK);
18126e0832faSShawn Lin }
18136e0832faSShawn Lin 
tegra_pcie_msi_teardown(struct tegra_pcie * pcie)18146e0832faSShawn Lin static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie)
18156e0832faSShawn Lin {
18166e0832faSShawn Lin 	struct tegra_msi *msi = &pcie->msi;
18176e0832faSShawn Lin 	unsigned int i, irq;
18186e0832faSShawn Lin 
181921e2079fSVidya Sagar 	dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys,
182021e2079fSVidya Sagar 		       DMA_ATTR_NO_KERNEL_MAPPING);
18216e0832faSShawn Lin 
18226e0832faSShawn Lin 	for (i = 0; i < INT_PCI_MSI_NR; i++) {
18236e0832faSShawn Lin 		irq = irq_find_mapping(msi->domain, i);
18246e0832faSShawn Lin 		if (irq > 0)
18252c99e55fSMarc Zyngier 			irq_domain_free_irqs(irq, 1);
18266e0832faSShawn Lin 	}
18276e0832faSShawn Lin 
18282c99e55fSMarc Zyngier 	irq_set_chained_handler_and_data(msi->irq, NULL, NULL);
18292c99e55fSMarc Zyngier 
18302c99e55fSMarc Zyngier 	if (IS_ENABLED(CONFIG_PCI_MSI))
18312c99e55fSMarc Zyngier 		tegra_free_domains(msi);
18326e0832faSShawn Lin }
18336e0832faSShawn Lin 
tegra_pcie_disable_msi(struct tegra_pcie * pcie)18346e0832faSShawn Lin static int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
18356e0832faSShawn Lin {
18366e0832faSShawn Lin 	u32 value;
18376e0832faSShawn Lin 
18386e0832faSShawn Lin 	/* mask the MSI interrupt */
18396e0832faSShawn Lin 	value = afi_readl(pcie, AFI_INTR_MASK);
18406e0832faSShawn Lin 	value &= ~AFI_INTR_MASK_MSI_MASK;
18416e0832faSShawn Lin 	afi_writel(pcie, value, AFI_INTR_MASK);
18426e0832faSShawn Lin 
18436e0832faSShawn Lin 	return 0;
18446e0832faSShawn Lin }
18456e0832faSShawn Lin 
tegra_pcie_disable_interrupts(struct tegra_pcie * pcie)1846316b9ef1SManikanta Maddireddy static void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie)
1847316b9ef1SManikanta Maddireddy {
1848316b9ef1SManikanta Maddireddy 	u32 value;
1849316b9ef1SManikanta Maddireddy 
1850316b9ef1SManikanta Maddireddy 	value = afi_readl(pcie, AFI_INTR_MASK);
1851316b9ef1SManikanta Maddireddy 	value &= ~AFI_INTR_MASK_INT_MASK;
1852316b9ef1SManikanta Maddireddy 	afi_writel(pcie, value, AFI_INTR_MASK);
1853316b9ef1SManikanta Maddireddy }
1854316b9ef1SManikanta Maddireddy 
tegra_pcie_get_xbar_config(struct tegra_pcie * pcie,u32 lanes,u32 * xbar)18556e0832faSShawn Lin static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
18566e0832faSShawn Lin 				      u32 *xbar)
18576e0832faSShawn Lin {
18586e0832faSShawn Lin 	struct device *dev = pcie->dev;
18596e0832faSShawn Lin 	struct device_node *np = dev->of_node;
18606e0832faSShawn Lin 
18616e0832faSShawn Lin 	if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
18626e0832faSShawn Lin 		switch (lanes) {
18636e0832faSShawn Lin 		case 0x010004:
18646e0832faSShawn Lin 			dev_info(dev, "4x1, 1x1 configuration\n");
18656e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401;
18666e0832faSShawn Lin 			return 0;
18676e0832faSShawn Lin 
18686e0832faSShawn Lin 		case 0x010102:
18696e0832faSShawn Lin 			dev_info(dev, "2x1, 1X1, 1x1 configuration\n");
18706e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
18716e0832faSShawn Lin 			return 0;
18726e0832faSShawn Lin 
18736e0832faSShawn Lin 		case 0x010101:
18746e0832faSShawn Lin 			dev_info(dev, "1x1, 1x1, 1x1 configuration\n");
18756e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111;
18766e0832faSShawn Lin 			return 0;
18776e0832faSShawn Lin 
18786e0832faSShawn Lin 		default:
18796e0832faSShawn Lin 			dev_info(dev, "wrong configuration updated in DT, "
18806e0832faSShawn Lin 				 "switching to default 2x1, 1x1, 1x1 "
18816e0832faSShawn Lin 				 "configuration\n");
18826e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
18836e0832faSShawn Lin 			return 0;
18846e0832faSShawn Lin 		}
18856e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
18866e0832faSShawn Lin 		   of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
18876e0832faSShawn Lin 		switch (lanes) {
18886e0832faSShawn Lin 		case 0x0000104:
18896e0832faSShawn Lin 			dev_info(dev, "4x1, 1x1 configuration\n");
18906e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
18916e0832faSShawn Lin 			return 0;
18926e0832faSShawn Lin 
18936e0832faSShawn Lin 		case 0x0000102:
18946e0832faSShawn Lin 			dev_info(dev, "2x1, 1x1 configuration\n");
18956e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
18966e0832faSShawn Lin 			return 0;
18976e0832faSShawn Lin 		}
18986e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
18996e0832faSShawn Lin 		switch (lanes) {
19006e0832faSShawn Lin 		case 0x00000204:
19016e0832faSShawn Lin 			dev_info(dev, "4x1, 2x1 configuration\n");
19026e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420;
19036e0832faSShawn Lin 			return 0;
19046e0832faSShawn Lin 
19056e0832faSShawn Lin 		case 0x00020202:
19066e0832faSShawn Lin 			dev_info(dev, "2x3 configuration\n");
19076e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222;
19086e0832faSShawn Lin 			return 0;
19096e0832faSShawn Lin 
19106e0832faSShawn Lin 		case 0x00010104:
19116e0832faSShawn Lin 			dev_info(dev, "4x1, 1x2 configuration\n");
19126e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
19136e0832faSShawn Lin 			return 0;
19146e0832faSShawn Lin 		}
19156e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) {
19166e0832faSShawn Lin 		switch (lanes) {
19176e0832faSShawn Lin 		case 0x00000004:
19186e0832faSShawn Lin 			dev_info(dev, "single-mode configuration\n");
19196e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
19206e0832faSShawn Lin 			return 0;
19216e0832faSShawn Lin 
19226e0832faSShawn Lin 		case 0x00000202:
19236e0832faSShawn Lin 			dev_info(dev, "dual-mode configuration\n");
19246e0832faSShawn Lin 			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
19256e0832faSShawn Lin 			return 0;
19266e0832faSShawn Lin 		}
19276e0832faSShawn Lin 	}
19286e0832faSShawn Lin 
19296e0832faSShawn Lin 	return -EINVAL;
19306e0832faSShawn Lin }
19316e0832faSShawn Lin 
19326e0832faSShawn Lin /*
19336e0832faSShawn Lin  * Check whether a given set of supplies is available in a device tree node.
19346e0832faSShawn Lin  * This is used to check whether the new or the legacy device tree bindings
19356e0832faSShawn Lin  * should be used.
19366e0832faSShawn Lin  */
of_regulator_bulk_available(struct device_node * np,struct regulator_bulk_data * supplies,unsigned int num_supplies)19376e0832faSShawn Lin static bool of_regulator_bulk_available(struct device_node *np,
19386e0832faSShawn Lin 					struct regulator_bulk_data *supplies,
19396e0832faSShawn Lin 					unsigned int num_supplies)
19406e0832faSShawn Lin {
19416e0832faSShawn Lin 	char property[32];
19426e0832faSShawn Lin 	unsigned int i;
19436e0832faSShawn Lin 
19446e0832faSShawn Lin 	for (i = 0; i < num_supplies; i++) {
19456e0832faSShawn Lin 		snprintf(property, 32, "%s-supply", supplies[i].supply);
19466e0832faSShawn Lin 
1947*9195ee1aSRob Herring 		if (!of_property_present(np, property))
19486e0832faSShawn Lin 			return false;
19496e0832faSShawn Lin 	}
19506e0832faSShawn Lin 
19516e0832faSShawn Lin 	return true;
19526e0832faSShawn Lin }
19536e0832faSShawn Lin 
19546e0832faSShawn Lin /*
19556e0832faSShawn Lin  * Old versions of the device tree binding for this device used a set of power
19566e0832faSShawn Lin  * supplies that didn't match the hardware inputs. This happened to work for a
19576e0832faSShawn Lin  * number of cases but is not future proof. However to preserve backwards-
19586e0832faSShawn Lin  * compatibility with old device trees, this function will try to use the old
19596e0832faSShawn Lin  * set of supplies.
19606e0832faSShawn Lin  */
tegra_pcie_get_legacy_regulators(struct tegra_pcie * pcie)19616e0832faSShawn Lin static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie)
19626e0832faSShawn Lin {
19636e0832faSShawn Lin 	struct device *dev = pcie->dev;
19646e0832faSShawn Lin 	struct device_node *np = dev->of_node;
19656e0832faSShawn Lin 
19666e0832faSShawn Lin 	if (of_device_is_compatible(np, "nvidia,tegra30-pcie"))
19676e0832faSShawn Lin 		pcie->num_supplies = 3;
19686e0832faSShawn Lin 	else if (of_device_is_compatible(np, "nvidia,tegra20-pcie"))
19696e0832faSShawn Lin 		pcie->num_supplies = 2;
19706e0832faSShawn Lin 
19716e0832faSShawn Lin 	if (pcie->num_supplies == 0) {
19726e0832faSShawn Lin 		dev_err(dev, "device %pOF not supported in legacy mode\n", np);
19736e0832faSShawn Lin 		return -ENODEV;
19746e0832faSShawn Lin 	}
19756e0832faSShawn Lin 
19766e0832faSShawn Lin 	pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
19776e0832faSShawn Lin 				      sizeof(*pcie->supplies),
19786e0832faSShawn Lin 				      GFP_KERNEL);
19796e0832faSShawn Lin 	if (!pcie->supplies)
19806e0832faSShawn Lin 		return -ENOMEM;
19816e0832faSShawn Lin 
19826e0832faSShawn Lin 	pcie->supplies[0].supply = "pex-clk";
19836e0832faSShawn Lin 	pcie->supplies[1].supply = "vdd";
19846e0832faSShawn Lin 
19856e0832faSShawn Lin 	if (pcie->num_supplies > 2)
19866e0832faSShawn Lin 		pcie->supplies[2].supply = "avdd";
19876e0832faSShawn Lin 
19886e0832faSShawn Lin 	return devm_regulator_bulk_get(dev, pcie->num_supplies, pcie->supplies);
19896e0832faSShawn Lin }
19906e0832faSShawn Lin 
19916e0832faSShawn Lin /*
19926e0832faSShawn Lin  * Obtains the list of regulators required for a particular generation of the
19936e0832faSShawn Lin  * IP block.
19946e0832faSShawn Lin  *
19956e0832faSShawn Lin  * This would've been nice to do simply by providing static tables for use
19966e0832faSShawn Lin  * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky
19976e0832faSShawn Lin  * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB)
19986e0832faSShawn Lin  * and either seems to be optional depending on which ports are being used.
19996e0832faSShawn Lin  */
tegra_pcie_get_regulators(struct tegra_pcie * pcie,u32 lane_mask)20006e0832faSShawn Lin static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
20016e0832faSShawn Lin {
20026e0832faSShawn Lin 	struct device *dev = pcie->dev;
20036e0832faSShawn Lin 	struct device_node *np = dev->of_node;
20046e0832faSShawn Lin 	unsigned int i = 0;
20056e0832faSShawn Lin 
20066e0832faSShawn Lin 	if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
20076e0832faSShawn Lin 		pcie->num_supplies = 4;
20086e0832faSShawn Lin 
20096e0832faSShawn Lin 		pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
20106e0832faSShawn Lin 					      sizeof(*pcie->supplies),
20116e0832faSShawn Lin 					      GFP_KERNEL);
20126e0832faSShawn Lin 		if (!pcie->supplies)
20136e0832faSShawn Lin 			return -ENOMEM;
20146e0832faSShawn Lin 
20156e0832faSShawn Lin 		pcie->supplies[i++].supply = "dvdd-pex";
20166e0832faSShawn Lin 		pcie->supplies[i++].supply = "hvdd-pex-pll";
20176e0832faSShawn Lin 		pcie->supplies[i++].supply = "hvdd-pex";
20186e0832faSShawn Lin 		pcie->supplies[i++].supply = "vddio-pexctl-aud";
20196e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
2020a6fbb4a4SThierry Reding 		pcie->num_supplies = 3;
20216e0832faSShawn Lin 
20226e0832faSShawn Lin 		pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
20236e0832faSShawn Lin 					      sizeof(*pcie->supplies),
20246e0832faSShawn Lin 					      GFP_KERNEL);
20256e0832faSShawn Lin 		if (!pcie->supplies)
20266e0832faSShawn Lin 			return -ENOMEM;
20276e0832faSShawn Lin 
20286e0832faSShawn Lin 		pcie->supplies[i++].supply = "hvddio-pex";
20296e0832faSShawn Lin 		pcie->supplies[i++].supply = "dvddio-pex";
20306e0832faSShawn Lin 		pcie->supplies[i++].supply = "vddio-pex-ctl";
20316e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
2032a6fbb4a4SThierry Reding 		pcie->num_supplies = 4;
20336e0832faSShawn Lin 
20346e0832faSShawn Lin 		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
20356e0832faSShawn Lin 					      sizeof(*pcie->supplies),
20366e0832faSShawn Lin 					      GFP_KERNEL);
20376e0832faSShawn Lin 		if (!pcie->supplies)
20386e0832faSShawn Lin 			return -ENOMEM;
20396e0832faSShawn Lin 
20406e0832faSShawn Lin 		pcie->supplies[i++].supply = "avddio-pex";
20416e0832faSShawn Lin 		pcie->supplies[i++].supply = "dvddio-pex";
20426e0832faSShawn Lin 		pcie->supplies[i++].supply = "hvdd-pex";
20436e0832faSShawn Lin 		pcie->supplies[i++].supply = "vddio-pex-ctl";
20446e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
20456e0832faSShawn Lin 		bool need_pexa = false, need_pexb = false;
20466e0832faSShawn Lin 
20476e0832faSShawn Lin 		/* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */
20486e0832faSShawn Lin 		if (lane_mask & 0x0f)
20496e0832faSShawn Lin 			need_pexa = true;
20506e0832faSShawn Lin 
20516e0832faSShawn Lin 		/* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */
20526e0832faSShawn Lin 		if (lane_mask & 0x30)
20536e0832faSShawn Lin 			need_pexb = true;
20546e0832faSShawn Lin 
20556e0832faSShawn Lin 		pcie->num_supplies = 4 + (need_pexa ? 2 : 0) +
20566e0832faSShawn Lin 					 (need_pexb ? 2 : 0);
20576e0832faSShawn Lin 
20586e0832faSShawn Lin 		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
20596e0832faSShawn Lin 					      sizeof(*pcie->supplies),
20606e0832faSShawn Lin 					      GFP_KERNEL);
20616e0832faSShawn Lin 		if (!pcie->supplies)
20626e0832faSShawn Lin 			return -ENOMEM;
20636e0832faSShawn Lin 
20646e0832faSShawn Lin 		pcie->supplies[i++].supply = "avdd-pex-pll";
20656e0832faSShawn Lin 		pcie->supplies[i++].supply = "hvdd-pex";
20666e0832faSShawn Lin 		pcie->supplies[i++].supply = "vddio-pex-ctl";
20676e0832faSShawn Lin 		pcie->supplies[i++].supply = "avdd-plle";
20686e0832faSShawn Lin 
20696e0832faSShawn Lin 		if (need_pexa) {
20706e0832faSShawn Lin 			pcie->supplies[i++].supply = "avdd-pexa";
20716e0832faSShawn Lin 			pcie->supplies[i++].supply = "vdd-pexa";
20726e0832faSShawn Lin 		}
20736e0832faSShawn Lin 
20746e0832faSShawn Lin 		if (need_pexb) {
20756e0832faSShawn Lin 			pcie->supplies[i++].supply = "avdd-pexb";
20766e0832faSShawn Lin 			pcie->supplies[i++].supply = "vdd-pexb";
20776e0832faSShawn Lin 		}
20786e0832faSShawn Lin 	} else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) {
20796e0832faSShawn Lin 		pcie->num_supplies = 5;
20806e0832faSShawn Lin 
20816e0832faSShawn Lin 		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
20826e0832faSShawn Lin 					      sizeof(*pcie->supplies),
20836e0832faSShawn Lin 					      GFP_KERNEL);
20846e0832faSShawn Lin 		if (!pcie->supplies)
20856e0832faSShawn Lin 			return -ENOMEM;
20866e0832faSShawn Lin 
20876e0832faSShawn Lin 		pcie->supplies[0].supply = "avdd-pex";
20886e0832faSShawn Lin 		pcie->supplies[1].supply = "vdd-pex";
20896e0832faSShawn Lin 		pcie->supplies[2].supply = "avdd-pex-pll";
20906e0832faSShawn Lin 		pcie->supplies[3].supply = "avdd-plle";
20916e0832faSShawn Lin 		pcie->supplies[4].supply = "vddio-pex-clk";
20926e0832faSShawn Lin 	}
20936e0832faSShawn Lin 
20946e0832faSShawn Lin 	if (of_regulator_bulk_available(dev->of_node, pcie->supplies,
20956e0832faSShawn Lin 					pcie->num_supplies))
20966e0832faSShawn Lin 		return devm_regulator_bulk_get(dev, pcie->num_supplies,
20976e0832faSShawn Lin 					       pcie->supplies);
20986e0832faSShawn Lin 
20996e0832faSShawn Lin 	/*
21006e0832faSShawn Lin 	 * If not all regulators are available for this new scheme, assume
21016e0832faSShawn Lin 	 * that the device tree complies with an older version of the device
21026e0832faSShawn Lin 	 * tree binding.
21036e0832faSShawn Lin 	 */
21046e0832faSShawn Lin 	dev_info(dev, "using legacy DT binding for power supplies\n");
21056e0832faSShawn Lin 
21066e0832faSShawn Lin 	devm_kfree(dev, pcie->supplies);
21076e0832faSShawn Lin 	pcie->num_supplies = 0;
21086e0832faSShawn Lin 
21096e0832faSShawn Lin 	return tegra_pcie_get_legacy_regulators(pcie);
21106e0832faSShawn Lin }
21116e0832faSShawn Lin 
tegra_pcie_parse_dt(struct tegra_pcie * pcie)21126e0832faSShawn Lin static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
21136e0832faSShawn Lin {
21146e0832faSShawn Lin 	struct device *dev = pcie->dev;
21156e0832faSShawn Lin 	struct device_node *np = dev->of_node, *port;
21166e0832faSShawn Lin 	const struct tegra_pcie_soc *soc = pcie->soc;
21176e0832faSShawn Lin 	u32 lanes = 0, mask = 0;
21186e0832faSShawn Lin 	unsigned int lane = 0;
21196e0832faSShawn Lin 	int err;
21206e0832faSShawn Lin 
21216e0832faSShawn Lin 	/* parse root ports */
21226e0832faSShawn Lin 	for_each_child_of_node(np, port) {
21236e0832faSShawn Lin 		struct tegra_pcie_port *rp;
21246e0832faSShawn Lin 		unsigned int index;
21256e0832faSShawn Lin 		u32 value;
2126dbdcc22cSManikanta Maddireddy 		char *label;
21276e0832faSShawn Lin 
21286e0832faSShawn Lin 		err = of_pci_get_devfn(port);
21296e0832faSShawn Lin 		if (err < 0) {
21306e0832faSShawn Lin 			dev_err(dev, "failed to parse address: %d\n", err);
21319e38e690SNishka Dasgupta 			goto err_node_put;
21326e0832faSShawn Lin 		}
21336e0832faSShawn Lin 
21346e0832faSShawn Lin 		index = PCI_SLOT(err);
21356e0832faSShawn Lin 
21366e0832faSShawn Lin 		if (index < 1 || index > soc->num_ports) {
21376e0832faSShawn Lin 			dev_err(dev, "invalid port number: %d\n", index);
21389e38e690SNishka Dasgupta 			err = -EINVAL;
21399e38e690SNishka Dasgupta 			goto err_node_put;
21406e0832faSShawn Lin 		}
21416e0832faSShawn Lin 
21426e0832faSShawn Lin 		index--;
21436e0832faSShawn Lin 
21446e0832faSShawn Lin 		err = of_property_read_u32(port, "nvidia,num-lanes", &value);
21456e0832faSShawn Lin 		if (err < 0) {
21466e0832faSShawn Lin 			dev_err(dev, "failed to parse # of lanes: %d\n",
21476e0832faSShawn Lin 				err);
21489e38e690SNishka Dasgupta 			goto err_node_put;
21496e0832faSShawn Lin 		}
21506e0832faSShawn Lin 
21516e0832faSShawn Lin 		if (value > 16) {
21526e0832faSShawn Lin 			dev_err(dev, "invalid # of lanes: %u\n", value);
21539e38e690SNishka Dasgupta 			err = -EINVAL;
21549e38e690SNishka Dasgupta 			goto err_node_put;
21556e0832faSShawn Lin 		}
21566e0832faSShawn Lin 
21576e0832faSShawn Lin 		lanes |= value << (index << 3);
21586e0832faSShawn Lin 
21596e0832faSShawn Lin 		if (!of_device_is_available(port)) {
21606e0832faSShawn Lin 			lane += value;
21616e0832faSShawn Lin 			continue;
21626e0832faSShawn Lin 		}
21636e0832faSShawn Lin 
21646e0832faSShawn Lin 		mask |= ((1 << value) - 1) << lane;
21656e0832faSShawn Lin 		lane += value;
21666e0832faSShawn Lin 
21676e0832faSShawn Lin 		rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL);
21689e38e690SNishka Dasgupta 		if (!rp) {
21699e38e690SNishka Dasgupta 			err = -ENOMEM;
21709e38e690SNishka Dasgupta 			goto err_node_put;
21719e38e690SNishka Dasgupta 		}
21726e0832faSShawn Lin 
21736e0832faSShawn Lin 		err = of_address_to_resource(port, 0, &rp->regs);
21746e0832faSShawn Lin 		if (err < 0) {
21756e0832faSShawn Lin 			dev_err(dev, "failed to parse address: %d\n", err);
21769e38e690SNishka Dasgupta 			goto err_node_put;
21776e0832faSShawn Lin 		}
21786e0832faSShawn Lin 
21796e0832faSShawn Lin 		INIT_LIST_HEAD(&rp->list);
21806e0832faSShawn Lin 		rp->index = index;
21816e0832faSShawn Lin 		rp->lanes = value;
21826e0832faSShawn Lin 		rp->pcie = pcie;
21836e0832faSShawn Lin 		rp->np = port;
21846e0832faSShawn Lin 
21856e0832faSShawn Lin 		rp->base = devm_pci_remap_cfg_resource(dev, &rp->regs);
2186eff21f5dSChristophe JAILLET 		if (IS_ERR(rp->base)) {
2187eff21f5dSChristophe JAILLET 			err = PTR_ERR(rp->base);
2188eff21f5dSChristophe JAILLET 			goto err_node_put;
2189eff21f5dSChristophe JAILLET 		}
21906e0832faSShawn Lin 
2191dbdcc22cSManikanta Maddireddy 		label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index);
2192dbdcc22cSManikanta Maddireddy 		if (!label) {
2193eff21f5dSChristophe JAILLET 			err = -ENOMEM;
2194eff21f5dSChristophe JAILLET 			goto err_node_put;
2195dbdcc22cSManikanta Maddireddy 		}
2196dbdcc22cSManikanta Maddireddy 
2197dbdcc22cSManikanta Maddireddy 		/*
2198dbdcc22cSManikanta Maddireddy 		 * Returns -ENOENT if reset-gpios property is not populated
2199dbdcc22cSManikanta Maddireddy 		 * and in this case fall back to using AFI per port register
2200dbdcc22cSManikanta Maddireddy 		 * to toggle PERST# SFIO line.
2201dbdcc22cSManikanta Maddireddy 		 */
220216e3f407SDmitry Torokhov 		rp->reset_gpio = devm_fwnode_gpiod_get(dev,
220316e3f407SDmitry Torokhov 						       of_fwnode_handle(port),
220416e3f407SDmitry Torokhov 						       "reset",
2205dbdcc22cSManikanta Maddireddy 						       GPIOD_OUT_LOW,
2206dbdcc22cSManikanta Maddireddy 						       label);
2207dbdcc22cSManikanta Maddireddy 		if (IS_ERR(rp->reset_gpio)) {
2208dbdcc22cSManikanta Maddireddy 			if (PTR_ERR(rp->reset_gpio) == -ENOENT) {
2209dbdcc22cSManikanta Maddireddy 				rp->reset_gpio = NULL;
2210dbdcc22cSManikanta Maddireddy 			} else {
221163605f1cSPali Rohár 				dev_err(dev, "failed to get reset GPIO: %ld\n",
221263605f1cSPali Rohár 					PTR_ERR(rp->reset_gpio));
2213eff21f5dSChristophe JAILLET 				err = PTR_ERR(rp->reset_gpio);
2214eff21f5dSChristophe JAILLET 				goto err_node_put;
2215dbdcc22cSManikanta Maddireddy 			}
2216dbdcc22cSManikanta Maddireddy 		}
2217dbdcc22cSManikanta Maddireddy 
22186e0832faSShawn Lin 		list_add_tail(&rp->list, &pcie->ports);
22196e0832faSShawn Lin 	}
22206e0832faSShawn Lin 
22216e0832faSShawn Lin 	err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config);
22226e0832faSShawn Lin 	if (err < 0) {
22236e0832faSShawn Lin 		dev_err(dev, "invalid lane configuration\n");
22246e0832faSShawn Lin 		return err;
22256e0832faSShawn Lin 	}
22266e0832faSShawn Lin 
22276e0832faSShawn Lin 	err = tegra_pcie_get_regulators(pcie, mask);
22286e0832faSShawn Lin 	if (err < 0)
22296e0832faSShawn Lin 		return err;
22306e0832faSShawn Lin 
22316e0832faSShawn Lin 	return 0;
22329e38e690SNishka Dasgupta 
22339e38e690SNishka Dasgupta err_node_put:
22349e38e690SNishka Dasgupta 	of_node_put(port);
22359e38e690SNishka Dasgupta 	return err;
22366e0832faSShawn Lin }
22376e0832faSShawn Lin 
22386e0832faSShawn Lin /*
22396e0832faSShawn Lin  * FIXME: If there are no PCIe cards attached, then calling this function
22406e0832faSShawn Lin  * can result in the increase of the bootup time as there are big timeout
22416e0832faSShawn Lin  * loops.
22426e0832faSShawn Lin  */
22436e0832faSShawn Lin #define TEGRA_PCIE_LINKUP_TIMEOUT	200	/* up to 1.2 seconds */
tegra_pcie_port_check_link(struct tegra_pcie_port * port)22446e0832faSShawn Lin static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
22456e0832faSShawn Lin {
22466e0832faSShawn Lin 	struct device *dev = port->pcie->dev;
22476e0832faSShawn Lin 	unsigned int retries = 3;
22486e0832faSShawn Lin 	unsigned long value;
22496e0832faSShawn Lin 
22506e0832faSShawn Lin 	/* override presence detection */
22516e0832faSShawn Lin 	value = readl(port->base + RP_PRIV_MISC);
22526e0832faSShawn Lin 	value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
22536e0832faSShawn Lin 	value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
22546e0832faSShawn Lin 	writel(value, port->base + RP_PRIV_MISC);
22556e0832faSShawn Lin 
22566e0832faSShawn Lin 	do {
22576e0832faSShawn Lin 		unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
22586e0832faSShawn Lin 
22596e0832faSShawn Lin 		do {
22606e0832faSShawn Lin 			value = readl(port->base + RP_VEND_XP);
22616e0832faSShawn Lin 
22626e0832faSShawn Lin 			if (value & RP_VEND_XP_DL_UP)
22636e0832faSShawn Lin 				break;
22646e0832faSShawn Lin 
22656e0832faSShawn Lin 			usleep_range(1000, 2000);
22666e0832faSShawn Lin 		} while (--timeout);
22676e0832faSShawn Lin 
22686e0832faSShawn Lin 		if (!timeout) {
22694b16a822SManikanta Maddireddy 			dev_dbg(dev, "link %u down, retrying\n", port->index);
22706e0832faSShawn Lin 			goto retry;
22716e0832faSShawn Lin 		}
22726e0832faSShawn Lin 
22736e0832faSShawn Lin 		timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
22746e0832faSShawn Lin 
22756e0832faSShawn Lin 		do {
22766e0832faSShawn Lin 			value = readl(port->base + RP_LINK_CONTROL_STATUS);
22776e0832faSShawn Lin 
22786e0832faSShawn Lin 			if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
22796e0832faSShawn Lin 				return true;
22806e0832faSShawn Lin 
22816e0832faSShawn Lin 			usleep_range(1000, 2000);
22826e0832faSShawn Lin 		} while (--timeout);
22836e0832faSShawn Lin 
22846e0832faSShawn Lin retry:
22856e0832faSShawn Lin 		tegra_pcie_port_reset(port);
22866e0832faSShawn Lin 	} while (--retries);
22876e0832faSShawn Lin 
22886e0832faSShawn Lin 	return false;
22896e0832faSShawn Lin }
22906e0832faSShawn Lin 
tegra_pcie_change_link_speed(struct tegra_pcie * pcie)2291538123a2SManikanta Maddireddy static void tegra_pcie_change_link_speed(struct tegra_pcie *pcie)
2292538123a2SManikanta Maddireddy {
2293538123a2SManikanta Maddireddy 	struct device *dev = pcie->dev;
2294538123a2SManikanta Maddireddy 	struct tegra_pcie_port *port;
2295538123a2SManikanta Maddireddy 	ktime_t deadline;
2296538123a2SManikanta Maddireddy 	u32 value;
2297538123a2SManikanta Maddireddy 
2298538123a2SManikanta Maddireddy 	list_for_each_entry(port, &pcie->ports, list) {
2299538123a2SManikanta Maddireddy 		/*
2300538123a2SManikanta Maddireddy 		 * "Supported Link Speeds Vector" in "Link Capabilities 2"
2301538123a2SManikanta Maddireddy 		 * is not supported by Tegra. tegra_pcie_change_link_speed()
2302538123a2SManikanta Maddireddy 		 * is called only for Tegra chips which support Gen2.
2303538123a2SManikanta Maddireddy 		 * So there no harm if supported link speed is not verified.
2304538123a2SManikanta Maddireddy 		 */
2305538123a2SManikanta Maddireddy 		value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
2306538123a2SManikanta Maddireddy 		value &= ~PCI_EXP_LNKSTA_CLS;
2307538123a2SManikanta Maddireddy 		value |= PCI_EXP_LNKSTA_CLS_5_0GB;
2308538123a2SManikanta Maddireddy 		writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
2309538123a2SManikanta Maddireddy 
2310538123a2SManikanta Maddireddy 		/*
2311538123a2SManikanta Maddireddy 		 * Poll until link comes back from recovery to avoid race
2312538123a2SManikanta Maddireddy 		 * condition.
2313538123a2SManikanta Maddireddy 		 */
2314538123a2SManikanta Maddireddy 		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
2315538123a2SManikanta Maddireddy 
2316538123a2SManikanta Maddireddy 		while (ktime_before(ktime_get(), deadline)) {
2317538123a2SManikanta Maddireddy 			value = readl(port->base + RP_LINK_CONTROL_STATUS);
2318538123a2SManikanta Maddireddy 			if ((value & PCI_EXP_LNKSTA_LT) == 0)
2319538123a2SManikanta Maddireddy 				break;
2320538123a2SManikanta Maddireddy 
2321538123a2SManikanta Maddireddy 			usleep_range(2000, 3000);
2322538123a2SManikanta Maddireddy 		}
2323538123a2SManikanta Maddireddy 
2324538123a2SManikanta Maddireddy 		if (value & PCI_EXP_LNKSTA_LT)
2325538123a2SManikanta Maddireddy 			dev_warn(dev, "PCIe port %u link is in recovery\n",
2326538123a2SManikanta Maddireddy 				 port->index);
2327538123a2SManikanta Maddireddy 
2328538123a2SManikanta Maddireddy 		/* Retrain the link */
2329538123a2SManikanta Maddireddy 		value = readl(port->base + RP_LINK_CONTROL_STATUS);
2330538123a2SManikanta Maddireddy 		value |= PCI_EXP_LNKCTL_RL;
2331538123a2SManikanta Maddireddy 		writel(value, port->base + RP_LINK_CONTROL_STATUS);
2332538123a2SManikanta Maddireddy 
2333538123a2SManikanta Maddireddy 		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
2334538123a2SManikanta Maddireddy 
2335538123a2SManikanta Maddireddy 		while (ktime_before(ktime_get(), deadline)) {
2336538123a2SManikanta Maddireddy 			value = readl(port->base + RP_LINK_CONTROL_STATUS);
2337538123a2SManikanta Maddireddy 			if ((value & PCI_EXP_LNKSTA_LT) == 0)
2338538123a2SManikanta Maddireddy 				break;
2339538123a2SManikanta Maddireddy 
2340538123a2SManikanta Maddireddy 			usleep_range(2000, 3000);
2341538123a2SManikanta Maddireddy 		}
2342538123a2SManikanta Maddireddy 
2343538123a2SManikanta Maddireddy 		if (value & PCI_EXP_LNKSTA_LT)
2344538123a2SManikanta Maddireddy 			dev_err(dev, "failed to retrain link of port %u\n",
2345538123a2SManikanta Maddireddy 				port->index);
2346538123a2SManikanta Maddireddy 	}
2347538123a2SManikanta Maddireddy }
2348538123a2SManikanta Maddireddy 
tegra_pcie_enable_ports(struct tegra_pcie * pcie)23496e0832faSShawn Lin static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
23506e0832faSShawn Lin {
23516e0832faSShawn Lin 	struct device *dev = pcie->dev;
23526e0832faSShawn Lin 	struct tegra_pcie_port *port, *tmp;
23536e0832faSShawn Lin 
23546e0832faSShawn Lin 	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
23556e0832faSShawn Lin 		dev_info(dev, "probing port %u, using %u lanes\n",
23566e0832faSShawn Lin 			 port->index, port->lanes);
23576e0832faSShawn Lin 
23586e0832faSShawn Lin 		tegra_pcie_port_enable(port);
2359d1f9113fSManikanta Maddireddy 	}
23606e0832faSShawn Lin 
2361d1f9113fSManikanta Maddireddy 	/* Start LTSSM from Tegra side */
2362d1f9113fSManikanta Maddireddy 	reset_control_deassert(pcie->pcie_xrst);
2363d1f9113fSManikanta Maddireddy 
2364d1f9113fSManikanta Maddireddy 	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
23656e0832faSShawn Lin 		if (tegra_pcie_port_check_link(port))
23666e0832faSShawn Lin 			continue;
23676e0832faSShawn Lin 
23686e0832faSShawn Lin 		dev_info(dev, "link %u down, ignoring\n", port->index);
23696e0832faSShawn Lin 
23706e0832faSShawn Lin 		tegra_pcie_port_disable(port);
23716e0832faSShawn Lin 		tegra_pcie_port_free(port);
23726e0832faSShawn Lin 	}
2373538123a2SManikanta Maddireddy 
2374538123a2SManikanta Maddireddy 	if (pcie->soc->has_gen2)
2375538123a2SManikanta Maddireddy 		tegra_pcie_change_link_speed(pcie);
23766e0832faSShawn Lin }
23776e0832faSShawn Lin 
tegra_pcie_disable_ports(struct tegra_pcie * pcie)23786e0832faSShawn Lin static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
23796e0832faSShawn Lin {
23806e0832faSShawn Lin 	struct tegra_pcie_port *port, *tmp;
23816e0832faSShawn Lin 
2382d1f9113fSManikanta Maddireddy 	reset_control_assert(pcie->pcie_xrst);
2383d1f9113fSManikanta Maddireddy 
23846e0832faSShawn Lin 	list_for_each_entry_safe(port, tmp, &pcie->ports, list)
23856e0832faSShawn Lin 		tegra_pcie_port_disable(port);
23866e0832faSShawn Lin }
23876e0832faSShawn Lin 
23886e0832faSShawn Lin static const struct tegra_pcie_port_soc tegra20_pcie_ports[] = {
23896e0832faSShawn Lin 	{ .pme.turnoff_bit = 0, .pme.ack_bit =  5 },
23906e0832faSShawn Lin 	{ .pme.turnoff_bit = 8, .pme.ack_bit = 10 },
23916e0832faSShawn Lin };
23926e0832faSShawn Lin 
23936e0832faSShawn Lin static const struct tegra_pcie_soc tegra20_pcie = {
23946e0832faSShawn Lin 	.num_ports = 2,
23956e0832faSShawn Lin 	.ports = tegra20_pcie_ports,
23966e0832faSShawn Lin 	.msi_base_shift = 0,
23976e0832faSShawn Lin 	.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
23986e0832faSShawn Lin 	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
23996e0832faSShawn Lin 	.pads_refclk_cfg0 = 0xfa5cfa5c,
24006e0832faSShawn Lin 	.has_pex_clkreq_en = false,
24016e0832faSShawn Lin 	.has_pex_bias_ctrl = false,
24026e0832faSShawn Lin 	.has_intr_prsnt_sense = false,
24036e0832faSShawn Lin 	.has_cml_clk = false,
24046e0832faSShawn Lin 	.has_gen2 = false,
24056e0832faSShawn Lin 	.force_pca_enable = false,
24066e0832faSShawn Lin 	.program_uphy = true,
2407f1178099SManikanta Maddireddy 	.update_clamp_threshold = false,
2408b2634cd0SManikanta Maddireddy 	.program_deskew_time = false,
24099f570b6cSManikanta Maddireddy 	.update_fc_timer = false,
2410b5b4717eSManikanta Maddireddy 	.has_cache_bars = true,
24112513a4eeSManikanta Maddireddy 	.ectl.enable = false,
24126e0832faSShawn Lin };
24136e0832faSShawn Lin 
24146e0832faSShawn Lin static const struct tegra_pcie_port_soc tegra30_pcie_ports[] = {
24156e0832faSShawn Lin 	{ .pme.turnoff_bit =  0, .pme.ack_bit =  5 },
24166e0832faSShawn Lin 	{ .pme.turnoff_bit =  8, .pme.ack_bit = 10 },
24176e0832faSShawn Lin 	{ .pme.turnoff_bit = 16, .pme.ack_bit = 18 },
24186e0832faSShawn Lin };
24196e0832faSShawn Lin 
24206e0832faSShawn Lin static const struct tegra_pcie_soc tegra30_pcie = {
24216e0832faSShawn Lin 	.num_ports = 3,
24226e0832faSShawn Lin 	.ports = tegra30_pcie_ports,
24236e0832faSShawn Lin 	.msi_base_shift = 8,
242421a92676SMarcel Ziswiler 	.afi_pex2_ctrl = 0x128,
24256e0832faSShawn Lin 	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
24266e0832faSShawn Lin 	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
24276e0832faSShawn Lin 	.pads_refclk_cfg0 = 0xfa5cfa5c,
24286e0832faSShawn Lin 	.pads_refclk_cfg1 = 0xfa5cfa5c,
24296e0832faSShawn Lin 	.has_pex_clkreq_en = true,
24306e0832faSShawn Lin 	.has_pex_bias_ctrl = true,
24316e0832faSShawn Lin 	.has_intr_prsnt_sense = true,
24326e0832faSShawn Lin 	.has_cml_clk = true,
24336e0832faSShawn Lin 	.has_gen2 = false,
24346e0832faSShawn Lin 	.force_pca_enable = false,
24356e0832faSShawn Lin 	.program_uphy = true,
2436f1178099SManikanta Maddireddy 	.update_clamp_threshold = false,
2437b2634cd0SManikanta Maddireddy 	.program_deskew_time = false,
24389f570b6cSManikanta Maddireddy 	.update_fc_timer = false,
2439b5b4717eSManikanta Maddireddy 	.has_cache_bars = false,
24402513a4eeSManikanta Maddireddy 	.ectl.enable = false,
24416e0832faSShawn Lin };
24426e0832faSShawn Lin 
24436e0832faSShawn Lin static const struct tegra_pcie_soc tegra124_pcie = {
24446e0832faSShawn Lin 	.num_ports = 2,
24456e0832faSShawn Lin 	.ports = tegra20_pcie_ports,
24466e0832faSShawn Lin 	.msi_base_shift = 8,
24476e0832faSShawn Lin 	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
24486e0832faSShawn Lin 	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
24496e0832faSShawn Lin 	.pads_refclk_cfg0 = 0x44ac44ac,
24506e0832faSShawn Lin 	.has_pex_clkreq_en = true,
24516e0832faSShawn Lin 	.has_pex_bias_ctrl = true,
24526e0832faSShawn Lin 	.has_intr_prsnt_sense = true,
24536e0832faSShawn Lin 	.has_cml_clk = true,
24546e0832faSShawn Lin 	.has_gen2 = true,
24556e0832faSShawn Lin 	.force_pca_enable = false,
24566e0832faSShawn Lin 	.program_uphy = true,
2457f1178099SManikanta Maddireddy 	.update_clamp_threshold = true,
2458b2634cd0SManikanta Maddireddy 	.program_deskew_time = false,
24599f570b6cSManikanta Maddireddy 	.update_fc_timer = false,
2460b5b4717eSManikanta Maddireddy 	.has_cache_bars = false,
24612513a4eeSManikanta Maddireddy 	.ectl.enable = false,
24626e0832faSShawn Lin };
24636e0832faSShawn Lin 
24646e0832faSShawn Lin static const struct tegra_pcie_soc tegra210_pcie = {
24656e0832faSShawn Lin 	.num_ports = 2,
24666e0832faSShawn Lin 	.ports = tegra20_pcie_ports,
24676e0832faSShawn Lin 	.msi_base_shift = 8,
24686e0832faSShawn Lin 	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
24696e0832faSShawn Lin 	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
24706e0832faSShawn Lin 	.pads_refclk_cfg0 = 0x90b890b8,
24719f570b6cSManikanta Maddireddy 	/* FC threshold is bit[25:18] */
24729f570b6cSManikanta Maddireddy 	.update_fc_threshold = 0x01800000,
24736e0832faSShawn Lin 	.has_pex_clkreq_en = true,
24746e0832faSShawn Lin 	.has_pex_bias_ctrl = true,
24756e0832faSShawn Lin 	.has_intr_prsnt_sense = true,
24766e0832faSShawn Lin 	.has_cml_clk = true,
24776e0832faSShawn Lin 	.has_gen2 = true,
24786e0832faSShawn Lin 	.force_pca_enable = true,
24796e0832faSShawn Lin 	.program_uphy = true,
2480f1178099SManikanta Maddireddy 	.update_clamp_threshold = true,
2481b2634cd0SManikanta Maddireddy 	.program_deskew_time = true,
24829f570b6cSManikanta Maddireddy 	.update_fc_timer = true,
2483b5b4717eSManikanta Maddireddy 	.has_cache_bars = false,
24842513a4eeSManikanta Maddireddy 	.ectl = {
24852513a4eeSManikanta Maddireddy 		.regs = {
24862513a4eeSManikanta Maddireddy 			.rp_ectl_2_r1 = 0x0000000f,
24872513a4eeSManikanta Maddireddy 			.rp_ectl_4_r1 = 0x00000067,
24882513a4eeSManikanta Maddireddy 			.rp_ectl_5_r1 = 0x55010000,
24892513a4eeSManikanta Maddireddy 			.rp_ectl_6_r1 = 0x00000001,
24902513a4eeSManikanta Maddireddy 			.rp_ectl_2_r2 = 0x0000008f,
24912513a4eeSManikanta Maddireddy 			.rp_ectl_4_r2 = 0x000000c7,
24922513a4eeSManikanta Maddireddy 			.rp_ectl_5_r2 = 0x55010000,
24932513a4eeSManikanta Maddireddy 			.rp_ectl_6_r2 = 0x00000001,
24942513a4eeSManikanta Maddireddy 		},
24952513a4eeSManikanta Maddireddy 		.enable = true,
24962513a4eeSManikanta Maddireddy 	},
24976e0832faSShawn Lin };
24986e0832faSShawn Lin 
24996e0832faSShawn Lin static const struct tegra_pcie_port_soc tegra186_pcie_ports[] = {
25006e0832faSShawn Lin 	{ .pme.turnoff_bit =  0, .pme.ack_bit =  5 },
25016e0832faSShawn Lin 	{ .pme.turnoff_bit =  8, .pme.ack_bit = 10 },
25026e0832faSShawn Lin 	{ .pme.turnoff_bit = 12, .pme.ack_bit = 14 },
25036e0832faSShawn Lin };
25046e0832faSShawn Lin 
25056e0832faSShawn Lin static const struct tegra_pcie_soc tegra186_pcie = {
25066e0832faSShawn Lin 	.num_ports = 3,
25076e0832faSShawn Lin 	.ports = tegra186_pcie_ports,
25086e0832faSShawn Lin 	.msi_base_shift = 8,
2509adb2653bSManikanta Maddireddy 	.afi_pex2_ctrl = 0x19c,
25106e0832faSShawn Lin 	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
25116e0832faSShawn Lin 	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
25126e0832faSShawn Lin 	.pads_refclk_cfg0 = 0x80b880b8,
25136e0832faSShawn Lin 	.pads_refclk_cfg1 = 0x000480b8,
25146e0832faSShawn Lin 	.has_pex_clkreq_en = true,
25156e0832faSShawn Lin 	.has_pex_bias_ctrl = true,
25166e0832faSShawn Lin 	.has_intr_prsnt_sense = true,
25176e0832faSShawn Lin 	.has_cml_clk = false,
25186e0832faSShawn Lin 	.has_gen2 = true,
25196e0832faSShawn Lin 	.force_pca_enable = false,
25206e0832faSShawn Lin 	.program_uphy = false,
2521f1178099SManikanta Maddireddy 	.update_clamp_threshold = false,
2522b2634cd0SManikanta Maddireddy 	.program_deskew_time = false,
25239f570b6cSManikanta Maddireddy 	.update_fc_timer = false,
2524b5b4717eSManikanta Maddireddy 	.has_cache_bars = false,
25252513a4eeSManikanta Maddireddy 	.ectl.enable = false,
25266e0832faSShawn Lin };
25276e0832faSShawn Lin 
25286e0832faSShawn Lin static const struct of_device_id tegra_pcie_of_match[] = {
25296e0832faSShawn Lin 	{ .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
25306e0832faSShawn Lin 	{ .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
25316e0832faSShawn Lin 	{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
25326e0832faSShawn Lin 	{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
25336e0832faSShawn Lin 	{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie },
25346e0832faSShawn Lin 	{ },
25356e0832faSShawn Lin };
25367bf475a4SZou Wei MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
25376e0832faSShawn Lin 
tegra_pcie_ports_seq_start(struct seq_file * s,loff_t * pos)25386e0832faSShawn Lin static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
25396e0832faSShawn Lin {
25406e0832faSShawn Lin 	struct tegra_pcie *pcie = s->private;
25416e0832faSShawn Lin 
25426e0832faSShawn Lin 	if (list_empty(&pcie->ports))
25436e0832faSShawn Lin 		return NULL;
25446e0832faSShawn Lin 
2545804b2b6fSChristophe JAILLET 	seq_puts(s, "Index  Status\n");
25466e0832faSShawn Lin 
25476e0832faSShawn Lin 	return seq_list_start(&pcie->ports, *pos);
25486e0832faSShawn Lin }
25496e0832faSShawn Lin 
tegra_pcie_ports_seq_next(struct seq_file * s,void * v,loff_t * pos)25506e0832faSShawn Lin static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos)
25516e0832faSShawn Lin {
25526e0832faSShawn Lin 	struct tegra_pcie *pcie = s->private;
25536e0832faSShawn Lin 
25546e0832faSShawn Lin 	return seq_list_next(v, &pcie->ports, pos);
25556e0832faSShawn Lin }
25566e0832faSShawn Lin 
tegra_pcie_ports_seq_stop(struct seq_file * s,void * v)25576e0832faSShawn Lin static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v)
25586e0832faSShawn Lin {
25596e0832faSShawn Lin }
25606e0832faSShawn Lin 
tegra_pcie_ports_seq_show(struct seq_file * s,void * v)25616e0832faSShawn Lin static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
25626e0832faSShawn Lin {
25636e0832faSShawn Lin 	bool up = false, active = false;
25646e0832faSShawn Lin 	struct tegra_pcie_port *port;
25656e0832faSShawn Lin 	unsigned int value;
25666e0832faSShawn Lin 
25676e0832faSShawn Lin 	port = list_entry(v, struct tegra_pcie_port, list);
25686e0832faSShawn Lin 
25696e0832faSShawn Lin 	value = readl(port->base + RP_VEND_XP);
25706e0832faSShawn Lin 
25716e0832faSShawn Lin 	if (value & RP_VEND_XP_DL_UP)
25726e0832faSShawn Lin 		up = true;
25736e0832faSShawn Lin 
25746e0832faSShawn Lin 	value = readl(port->base + RP_LINK_CONTROL_STATUS);
25756e0832faSShawn Lin 
25766e0832faSShawn Lin 	if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
25776e0832faSShawn Lin 		active = true;
25786e0832faSShawn Lin 
25796e0832faSShawn Lin 	seq_printf(s, "%2u     ", port->index);
25806e0832faSShawn Lin 
25816e0832faSShawn Lin 	if (up)
2582804b2b6fSChristophe JAILLET 		seq_puts(s, "up");
25836e0832faSShawn Lin 
25846e0832faSShawn Lin 	if (active) {
25856e0832faSShawn Lin 		if (up)
2586804b2b6fSChristophe JAILLET 			seq_puts(s, ", ");
25876e0832faSShawn Lin 
2588804b2b6fSChristophe JAILLET 		seq_puts(s, "active");
25896e0832faSShawn Lin 	}
25906e0832faSShawn Lin 
2591804b2b6fSChristophe JAILLET 	seq_puts(s, "\n");
25926e0832faSShawn Lin 	return 0;
25936e0832faSShawn Lin }
25946e0832faSShawn Lin 
2595cd198909SLiu Shixin static const struct seq_operations tegra_pcie_ports_sops = {
25966e0832faSShawn Lin 	.start = tegra_pcie_ports_seq_start,
25976e0832faSShawn Lin 	.next = tegra_pcie_ports_seq_next,
25986e0832faSShawn Lin 	.stop = tegra_pcie_ports_seq_stop,
25996e0832faSShawn Lin 	.show = tegra_pcie_ports_seq_show,
26006e0832faSShawn Lin };
26016e0832faSShawn Lin 
2602cd198909SLiu Shixin DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports);
26036e0832faSShawn Lin 
tegra_pcie_debugfs_exit(struct tegra_pcie * pcie)26046e0832faSShawn Lin static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
26056e0832faSShawn Lin {
26066e0832faSShawn Lin 	debugfs_remove_recursive(pcie->debugfs);
26076e0832faSShawn Lin 	pcie->debugfs = NULL;
26086e0832faSShawn Lin }
26096e0832faSShawn Lin 
tegra_pcie_debugfs_init(struct tegra_pcie * pcie)2610d27b1cdcSGreg Kroah-Hartman static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
26116e0832faSShawn Lin {
26126e0832faSShawn Lin 	pcie->debugfs = debugfs_create_dir("pcie", NULL);
26136e0832faSShawn Lin 
2614d27b1cdcSGreg Kroah-Hartman 	debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie,
2615cd198909SLiu Shixin 			    &tegra_pcie_ports_fops);
26166e0832faSShawn Lin }
26176e0832faSShawn Lin 
tegra_pcie_probe(struct platform_device * pdev)26186e0832faSShawn Lin static int tegra_pcie_probe(struct platform_device *pdev)
26196e0832faSShawn Lin {
26206e0832faSShawn Lin 	struct device *dev = &pdev->dev;
26216e0832faSShawn Lin 	struct pci_host_bridge *host;
26226e0832faSShawn Lin 	struct tegra_pcie *pcie;
26236e0832faSShawn Lin 	int err;
26246e0832faSShawn Lin 
26256e0832faSShawn Lin 	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
26266e0832faSShawn Lin 	if (!host)
26276e0832faSShawn Lin 		return -ENOMEM;
26286e0832faSShawn Lin 
26296e0832faSShawn Lin 	pcie = pci_host_bridge_priv(host);
26306e0832faSShawn Lin 	host->sysdata = pcie;
26316e0832faSShawn Lin 	platform_set_drvdata(pdev, pcie);
26326e0832faSShawn Lin 
26336e0832faSShawn Lin 	pcie->soc = of_device_get_match_data(dev);
26346e0832faSShawn Lin 	INIT_LIST_HEAD(&pcie->ports);
26356e0832faSShawn Lin 	pcie->dev = dev;
26366e0832faSShawn Lin 
26376e0832faSShawn Lin 	err = tegra_pcie_parse_dt(pcie);
26386e0832faSShawn Lin 	if (err < 0)
26396e0832faSShawn Lin 		return err;
26406e0832faSShawn Lin 
26416e0832faSShawn Lin 	err = tegra_pcie_get_resources(pcie);
26426e0832faSShawn Lin 	if (err < 0) {
26436e0832faSShawn Lin 		dev_err(dev, "failed to request resources: %d\n", err);
26446e0832faSShawn Lin 		return err;
26456e0832faSShawn Lin 	}
26466e0832faSShawn Lin 
26476e0832faSShawn Lin 	err = tegra_pcie_msi_setup(pcie);
26486e0832faSShawn Lin 	if (err < 0) {
26496e0832faSShawn Lin 		dev_err(dev, "failed to enable MSI support: %d\n", err);
26506e0832faSShawn Lin 		goto put_resources;
26516e0832faSShawn Lin 	}
26526e0832faSShawn Lin 
26536e0832faSShawn Lin 	pm_runtime_enable(pcie->dev);
26546e0832faSShawn Lin 	err = pm_runtime_get_sync(pcie->dev);
265588519914SDavid Engraf 	if (err < 0) {
26566e0832faSShawn Lin 		dev_err(dev, "fail to enable pcie controller: %d\n", err);
2657fcee90cdSDinghao Liu 		goto pm_runtime_put;
26586e0832faSShawn Lin 	}
26596e0832faSShawn Lin 
26606e0832faSShawn Lin 	host->ops = &tegra_pcie_ops;
26616e0832faSShawn Lin 	host->map_irq = tegra_pcie_map_irq;
26626e0832faSShawn Lin 
266367047e8bSRob Herring 	err = pci_host_probe(host);
26646e0832faSShawn Lin 	if (err < 0) {
26656e0832faSShawn Lin 		dev_err(dev, "failed to register host: %d\n", err);
266694e99b19SRob Herring 		goto pm_runtime_put;
26676e0832faSShawn Lin 	}
26686e0832faSShawn Lin 
2669d27b1cdcSGreg Kroah-Hartman 	if (IS_ENABLED(CONFIG_DEBUG_FS))
2670d27b1cdcSGreg Kroah-Hartman 		tegra_pcie_debugfs_init(pcie);
26716e0832faSShawn Lin 
26726e0832faSShawn Lin 	return 0;
26736e0832faSShawn Lin 
26746e0832faSShawn Lin pm_runtime_put:
26756e0832faSShawn Lin 	pm_runtime_put_sync(pcie->dev);
26766e0832faSShawn Lin 	pm_runtime_disable(pcie->dev);
26776e0832faSShawn Lin 	tegra_pcie_msi_teardown(pcie);
26786e0832faSShawn Lin put_resources:
26796e0832faSShawn Lin 	tegra_pcie_put_resources(pcie);
26806e0832faSShawn Lin 	return err;
26816e0832faSShawn Lin }
26826e0832faSShawn Lin 
tegra_pcie_remove(struct platform_device * pdev)26836e0832faSShawn Lin static void tegra_pcie_remove(struct platform_device *pdev)
26846e0832faSShawn Lin {
26856e0832faSShawn Lin 	struct tegra_pcie *pcie = platform_get_drvdata(pdev);
26866e0832faSShawn Lin 	struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
26876e0832faSShawn Lin 	struct tegra_pcie_port *port, *tmp;
26886e0832faSShawn Lin 
26896e0832faSShawn Lin 	if (IS_ENABLED(CONFIG_DEBUG_FS))
26906e0832faSShawn Lin 		tegra_pcie_debugfs_exit(pcie);
26916e0832faSShawn Lin 
26926e0832faSShawn Lin 	pci_stop_root_bus(host->bus);
26936e0832faSShawn Lin 	pci_remove_root_bus(host->bus);
26946e0832faSShawn Lin 	pm_runtime_put_sync(pcie->dev);
26956e0832faSShawn Lin 	pm_runtime_disable(pcie->dev);
26966e0832faSShawn Lin 
26976e0832faSShawn Lin 	if (IS_ENABLED(CONFIG_PCI_MSI))
26986e0832faSShawn Lin 		tegra_pcie_msi_teardown(pcie);
26996e0832faSShawn Lin 
27006e0832faSShawn Lin 	tegra_pcie_put_resources(pcie);
27016e0832faSShawn Lin 
27026e0832faSShawn Lin 	list_for_each_entry_safe(port, tmp, &pcie->ports, list)
27036e0832faSShawn Lin 		tegra_pcie_port_free(port);
27046e0832faSShawn Lin }
27056e0832faSShawn Lin 
tegra_pcie_pm_suspend(struct device * dev)27066e0832faSShawn Lin static int tegra_pcie_pm_suspend(struct device *dev)
27076e0832faSShawn Lin {
270819b7858cSBjorn Helgaas 	struct tegra_pcie *pcie = dev_get_drvdata(dev);
27096e0832faSShawn Lin 	struct tegra_pcie_port *port;
27106e0832faSShawn Lin 	int err;
27116e0832faSShawn Lin 
2712973d7499SManikanta Maddireddy 	list_for_each_entry(port, &pcie->ports, list)
27136e0832faSShawn Lin 		tegra_pcie_pme_turnoff(port);
27146e0832faSShawn Lin 
27156e0832faSShawn Lin 	tegra_pcie_disable_ports(pcie);
27166e0832faSShawn Lin 
27176e0832faSShawn Lin 	/*
27186e0832faSShawn Lin 	 * AFI_INTR is unmasked in tegra_pcie_enable_controller(), mask it to
2719316b9ef1SManikanta Maddireddy 	 * avoid unwanted interrupts raised by AFI after pex_rst is asserted.
2720316b9ef1SManikanta Maddireddy 	 */
2721316b9ef1SManikanta Maddireddy 	tegra_pcie_disable_interrupts(pcie);
2722316b9ef1SManikanta Maddireddy 
2723316b9ef1SManikanta Maddireddy 	if (pcie->soc->program_uphy) {
2724316b9ef1SManikanta Maddireddy 		err = tegra_pcie_phy_power_off(pcie);
2725973d7499SManikanta Maddireddy 		if (err < 0)
2726973d7499SManikanta Maddireddy 			dev_err(dev, "failed to power off PHY(s): %d\n", err);
2727973d7499SManikanta Maddireddy 	}
2728973d7499SManikanta Maddireddy 
2729973d7499SManikanta Maddireddy 	reset_control_assert(pcie->pex_rst);
2730973d7499SManikanta Maddireddy 	clk_disable_unprepare(pcie->pex_clk);
2731d1f9113fSManikanta Maddireddy 
2732d1f9113fSManikanta Maddireddy 	if (IS_ENABLED(CONFIG_PCI_MSI))
2733d1f9113fSManikanta Maddireddy 		tegra_pcie_disable_msi(pcie);
27346e0832faSShawn Lin 
27356e0832faSShawn Lin 	pinctrl_pm_select_idle_state(dev);
27366e0832faSShawn Lin 	tegra_pcie_power_off(pcie);
27372d8c7361SManikanta Maddireddy 
27386e0832faSShawn Lin 	return 0;
27396e0832faSShawn Lin }
27406e0832faSShawn Lin 
tegra_pcie_pm_resume(struct device * dev)27416e0832faSShawn Lin static int tegra_pcie_pm_resume(struct device *dev)
27426e0832faSShawn Lin {
274319b7858cSBjorn Helgaas 	struct tegra_pcie *pcie = dev_get_drvdata(dev);
27446e0832faSShawn Lin 	int err;
27456e0832faSShawn Lin 
27466e0832faSShawn Lin 	err = tegra_pcie_power_on(pcie);
27476e0832faSShawn Lin 	if (err) {
27486e0832faSShawn Lin 		dev_err(dev, "tegra pcie power on fail: %d\n", err);
27496e0832faSShawn Lin 		return err;
27506e0832faSShawn Lin 	}
27516e0832faSShawn Lin 
27526e0832faSShawn Lin 	err = pinctrl_pm_select_default_state(dev);
27532d8c7361SManikanta Maddireddy 	if (err < 0) {
27542d8c7361SManikanta Maddireddy 		dev_err(dev, "failed to disable PCIe IO DPD: %d\n", err);
27552d8c7361SManikanta Maddireddy 		goto poweroff;
27562d8c7361SManikanta Maddireddy 	}
27572d8c7361SManikanta Maddireddy 
27582d8c7361SManikanta Maddireddy 	tegra_pcie_enable_controller(pcie);
27592d8c7361SManikanta Maddireddy 	tegra_pcie_setup_translations(pcie);
2760973d7499SManikanta Maddireddy 
27616e0832faSShawn Lin 	if (IS_ENABLED(CONFIG_PCI_MSI))
27626e0832faSShawn Lin 		tegra_pcie_enable_msi(pcie);
27636e0832faSShawn Lin 
27646e0832faSShawn Lin 	err = clk_prepare_enable(pcie->pex_clk);
27656e0832faSShawn Lin 	if (err) {
2766d1f9113fSManikanta Maddireddy 		dev_err(dev, "failed to enable PEX clock: %d\n", err);
2767d1f9113fSManikanta Maddireddy 		goto pex_dpd_enable;
2768d1f9113fSManikanta Maddireddy 	}
27692d8c7361SManikanta Maddireddy 
2770d1f9113fSManikanta Maddireddy 	reset_control_deassert(pcie->pex_rst);
2771d1f9113fSManikanta Maddireddy 
2772d1f9113fSManikanta Maddireddy 	if (pcie->soc->program_uphy) {
2773d1f9113fSManikanta Maddireddy 		err = tegra_pcie_phy_power_on(pcie);
2774973d7499SManikanta Maddireddy 		if (err < 0) {
2775973d7499SManikanta Maddireddy 			dev_err(dev, "failed to power on PHY(s): %d\n", err);
2776973d7499SManikanta Maddireddy 			goto disable_pex_clk;
2777973d7499SManikanta Maddireddy 		}
2778d1f9113fSManikanta Maddireddy 	}
2779973d7499SManikanta Maddireddy 
2780973d7499SManikanta Maddireddy 	tegra_pcie_apply_pad_settings(pcie);
2781973d7499SManikanta Maddireddy 	tegra_pcie_enable_ports(pcie);
2782973d7499SManikanta Maddireddy 
27836e0832faSShawn Lin 	return 0;
27846e0832faSShawn Lin 
27856e0832faSShawn Lin disable_pex_clk:
27866e0832faSShawn Lin 	reset_control_assert(pcie->pex_rst);
2787d1f9113fSManikanta Maddireddy 	clk_disable_unprepare(pcie->pex_clk);
2788d1f9113fSManikanta Maddireddy pex_dpd_enable:
2789d1f9113fSManikanta Maddireddy 	pinctrl_pm_select_idle_state(dev);
27902d8c7361SManikanta Maddireddy poweroff:
27912d8c7361SManikanta Maddireddy 	tegra_pcie_power_off(pcie);
27926e0832faSShawn Lin 
27936e0832faSShawn Lin 	return err;
27946e0832faSShawn Lin }
27956e0832faSShawn Lin 
27966e0832faSShawn Lin static const struct dev_pm_ops tegra_pcie_pm_ops = {
27976e0832faSShawn Lin 	RUNTIME_PM_OPS(tegra_pcie_pm_suspend, tegra_pcie_pm_resume, NULL)
27986e0832faSShawn Lin 	NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_pcie_pm_suspend, tegra_pcie_pm_resume)
279919b7858cSBjorn Helgaas };
280019b7858cSBjorn Helgaas 
28016e0832faSShawn Lin static struct platform_driver tegra_pcie_driver = {
28026e0832faSShawn Lin 	.driver = {
28036e0832faSShawn Lin 		.name = "tegra-pcie",
28046e0832faSShawn Lin 		.of_match_table = tegra_pcie_of_match,
28056e0832faSShawn Lin 		.suppress_bind_attrs = true,
28066e0832faSShawn Lin 		.pm = &tegra_pcie_pm_ops,
28076e0832faSShawn Lin 	},
28086e0832faSShawn Lin 	.probe = tegra_pcie_probe,
28096e0832faSShawn Lin 	.remove_new = tegra_pcie_remove,
28106e0832faSShawn Lin };
28116e0832faSShawn Lin module_platform_driver(tegra_pcie_driver);
28126e0832faSShawn Lin