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(®, 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