162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCIe host controller driver for Tegra SoCs
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2010, CompuLab, Ltd.
662306a36Sopenharmony_ci * Author: Mike Rapoport <mike@compulab.co.il>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on NVIDIA PCIe driver
962306a36Sopenharmony_ci * Copyright (c) 2008-2009, NVIDIA Corporation.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Bits taken from arch/arm/mach-dove/pcie.c
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Author: Thierry Reding <treding@nvidia.com>
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/clk.h>
1762306a36Sopenharmony_ci#include <linux/debugfs.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2162306a36Sopenharmony_ci#include <linux/interrupt.h>
2262306a36Sopenharmony_ci#include <linux/iopoll.h>
2362306a36Sopenharmony_ci#include <linux/irq.h>
2462306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h>
2562306a36Sopenharmony_ci#include <linux/irqdomain.h>
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <linux/init.h>
2862306a36Sopenharmony_ci#include <linux/module.h>
2962306a36Sopenharmony_ci#include <linux/msi.h>
3062306a36Sopenharmony_ci#include <linux/of_address.h>
3162306a36Sopenharmony_ci#include <linux/of_pci.h>
3262306a36Sopenharmony_ci#include <linux/of_platform.h>
3362306a36Sopenharmony_ci#include <linux/pci.h>
3462306a36Sopenharmony_ci#include <linux/phy/phy.h>
3562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
3662306a36Sopenharmony_ci#include <linux/platform_device.h>
3762306a36Sopenharmony_ci#include <linux/reset.h>
3862306a36Sopenharmony_ci#include <linux/sizes.h>
3962306a36Sopenharmony_ci#include <linux/slab.h>
4062306a36Sopenharmony_ci#include <linux/vmalloc.h>
4162306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include <soc/tegra/cpuidle.h>
4462306a36Sopenharmony_ci#include <soc/tegra/pmc.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include "../pci.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define INT_PCI_MSI_NR (8 * 32)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* register definitions */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define AFI_AXI_BAR0_SZ	0x00
5362306a36Sopenharmony_ci#define AFI_AXI_BAR1_SZ	0x04
5462306a36Sopenharmony_ci#define AFI_AXI_BAR2_SZ	0x08
5562306a36Sopenharmony_ci#define AFI_AXI_BAR3_SZ	0x0c
5662306a36Sopenharmony_ci#define AFI_AXI_BAR4_SZ	0x10
5762306a36Sopenharmony_ci#define AFI_AXI_BAR5_SZ	0x14
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define AFI_AXI_BAR0_START	0x18
6062306a36Sopenharmony_ci#define AFI_AXI_BAR1_START	0x1c
6162306a36Sopenharmony_ci#define AFI_AXI_BAR2_START	0x20
6262306a36Sopenharmony_ci#define AFI_AXI_BAR3_START	0x24
6362306a36Sopenharmony_ci#define AFI_AXI_BAR4_START	0x28
6462306a36Sopenharmony_ci#define AFI_AXI_BAR5_START	0x2c
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define AFI_FPCI_BAR0	0x30
6762306a36Sopenharmony_ci#define AFI_FPCI_BAR1	0x34
6862306a36Sopenharmony_ci#define AFI_FPCI_BAR2	0x38
6962306a36Sopenharmony_ci#define AFI_FPCI_BAR3	0x3c
7062306a36Sopenharmony_ci#define AFI_FPCI_BAR4	0x40
7162306a36Sopenharmony_ci#define AFI_FPCI_BAR5	0x44
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define AFI_CACHE_BAR0_SZ	0x48
7462306a36Sopenharmony_ci#define AFI_CACHE_BAR0_ST	0x4c
7562306a36Sopenharmony_ci#define AFI_CACHE_BAR1_SZ	0x50
7662306a36Sopenharmony_ci#define AFI_CACHE_BAR1_ST	0x54
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define AFI_MSI_BAR_SZ		0x60
7962306a36Sopenharmony_ci#define AFI_MSI_FPCI_BAR_ST	0x64
8062306a36Sopenharmony_ci#define AFI_MSI_AXI_BAR_ST	0x68
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define AFI_MSI_VEC(x)		(0x6c + ((x) * 4))
8362306a36Sopenharmony_ci#define AFI_MSI_EN_VEC(x)	(0x8c + ((x) * 4))
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define AFI_CONFIGURATION		0xac
8662306a36Sopenharmony_ci#define  AFI_CONFIGURATION_EN_FPCI		(1 << 0)
8762306a36Sopenharmony_ci#define  AFI_CONFIGURATION_CLKEN_OVERRIDE	(1 << 31)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define AFI_FPCI_ERROR_MASKS	0xb0
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define AFI_INTR_MASK		0xb4
9262306a36Sopenharmony_ci#define  AFI_INTR_MASK_INT_MASK	(1 << 0)
9362306a36Sopenharmony_ci#define  AFI_INTR_MASK_MSI_MASK	(1 << 8)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define AFI_INTR_CODE			0xb8
9662306a36Sopenharmony_ci#define  AFI_INTR_CODE_MASK		0xf
9762306a36Sopenharmony_ci#define  AFI_INTR_INI_SLAVE_ERROR	1
9862306a36Sopenharmony_ci#define  AFI_INTR_INI_DECODE_ERROR	2
9962306a36Sopenharmony_ci#define  AFI_INTR_TARGET_ABORT		3
10062306a36Sopenharmony_ci#define  AFI_INTR_MASTER_ABORT		4
10162306a36Sopenharmony_ci#define  AFI_INTR_INVALID_WRITE		5
10262306a36Sopenharmony_ci#define  AFI_INTR_LEGACY		6
10362306a36Sopenharmony_ci#define  AFI_INTR_FPCI_DECODE_ERROR	7
10462306a36Sopenharmony_ci#define  AFI_INTR_AXI_DECODE_ERROR	8
10562306a36Sopenharmony_ci#define  AFI_INTR_FPCI_TIMEOUT		9
10662306a36Sopenharmony_ci#define  AFI_INTR_PE_PRSNT_SENSE	10
10762306a36Sopenharmony_ci#define  AFI_INTR_PE_CLKREQ_SENSE	11
10862306a36Sopenharmony_ci#define  AFI_INTR_CLKCLAMP_SENSE	12
10962306a36Sopenharmony_ci#define  AFI_INTR_RDY4PD_SENSE		13
11062306a36Sopenharmony_ci#define  AFI_INTR_P2P_ERROR		14
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define AFI_INTR_SIGNATURE	0xbc
11362306a36Sopenharmony_ci#define AFI_UPPER_FPCI_ADDRESS	0xc0
11462306a36Sopenharmony_ci#define AFI_SM_INTR_ENABLE	0xc4
11562306a36Sopenharmony_ci#define  AFI_SM_INTR_INTA_ASSERT	(1 << 0)
11662306a36Sopenharmony_ci#define  AFI_SM_INTR_INTB_ASSERT	(1 << 1)
11762306a36Sopenharmony_ci#define  AFI_SM_INTR_INTC_ASSERT	(1 << 2)
11862306a36Sopenharmony_ci#define  AFI_SM_INTR_INTD_ASSERT	(1 << 3)
11962306a36Sopenharmony_ci#define  AFI_SM_INTR_INTA_DEASSERT	(1 << 4)
12062306a36Sopenharmony_ci#define  AFI_SM_INTR_INTB_DEASSERT	(1 << 5)
12162306a36Sopenharmony_ci#define  AFI_SM_INTR_INTC_DEASSERT	(1 << 6)
12262306a36Sopenharmony_ci#define  AFI_SM_INTR_INTD_DEASSERT	(1 << 7)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define AFI_AFI_INTR_ENABLE		0xc8
12562306a36Sopenharmony_ci#define  AFI_INTR_EN_INI_SLVERR		(1 << 0)
12662306a36Sopenharmony_ci#define  AFI_INTR_EN_INI_DECERR		(1 << 1)
12762306a36Sopenharmony_ci#define  AFI_INTR_EN_TGT_SLVERR		(1 << 2)
12862306a36Sopenharmony_ci#define  AFI_INTR_EN_TGT_DECERR		(1 << 3)
12962306a36Sopenharmony_ci#define  AFI_INTR_EN_TGT_WRERR		(1 << 4)
13062306a36Sopenharmony_ci#define  AFI_INTR_EN_DFPCI_DECERR	(1 << 5)
13162306a36Sopenharmony_ci#define  AFI_INTR_EN_AXI_DECERR		(1 << 6)
13262306a36Sopenharmony_ci#define  AFI_INTR_EN_FPCI_TIMEOUT	(1 << 7)
13362306a36Sopenharmony_ci#define  AFI_INTR_EN_PRSNT_SENSE	(1 << 8)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define AFI_PCIE_PME		0xf0
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define AFI_PCIE_CONFIG					0x0f8
13862306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_PCIE_DISABLE(x)		(1 << ((x) + 1))
13962306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_PCIE_DISABLE_ALL		0xe
14062306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
14162306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
14262306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
14362306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1	(0x0 << 20)
14462306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401	(0x0 << 20)
14562306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
14662306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222	(0x1 << 20)
14762306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1	(0x1 << 20)
14862306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211	(0x1 << 20)
14962306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411	(0x2 << 20)
15062306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111	(0x2 << 20)
15162306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(x)		(1 << ((x) + 29))
15262306a36Sopenharmony_ci#define  AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL		(0x7 << 29)
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci#define AFI_FUSE			0x104
15562306a36Sopenharmony_ci#define  AFI_FUSE_PCIE_T0_GEN2_DIS	(1 << 2)
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define AFI_PEX0_CTRL			0x110
15862306a36Sopenharmony_ci#define AFI_PEX1_CTRL			0x118
15962306a36Sopenharmony_ci#define  AFI_PEX_CTRL_RST		(1 << 0)
16062306a36Sopenharmony_ci#define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
16162306a36Sopenharmony_ci#define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
16262306a36Sopenharmony_ci#define  AFI_PEX_CTRL_OVERRIDE_EN	(1 << 4)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define AFI_PLLE_CONTROL		0x160
16562306a36Sopenharmony_ci#define  AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
16662306a36Sopenharmony_ci#define  AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define AFI_PEXBIAS_CTRL_0		0x168
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define RP_ECTL_2_R1	0x00000e84
17162306a36Sopenharmony_ci#define  RP_ECTL_2_R1_RX_CTLE_1C_MASK		0xffff
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define RP_ECTL_4_R1	0x00000e8c
17462306a36Sopenharmony_ci#define  RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK	(0xffff << 16)
17562306a36Sopenharmony_ci#define  RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT	16
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci#define RP_ECTL_5_R1	0x00000e90
17862306a36Sopenharmony_ci#define  RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK	0xffffffff
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#define RP_ECTL_6_R1	0x00000e94
18162306a36Sopenharmony_ci#define  RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK	0xffffffff
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define RP_ECTL_2_R2	0x00000ea4
18462306a36Sopenharmony_ci#define  RP_ECTL_2_R2_RX_CTLE_1C_MASK	0xffff
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define RP_ECTL_4_R2	0x00000eac
18762306a36Sopenharmony_ci#define  RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK	(0xffff << 16)
18862306a36Sopenharmony_ci#define  RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT	16
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define RP_ECTL_5_R2	0x00000eb0
19162306a36Sopenharmony_ci#define  RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK	0xffffffff
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define RP_ECTL_6_R2	0x00000eb4
19462306a36Sopenharmony_ci#define  RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK	0xffffffff
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define RP_VEND_XP	0x00000f00
19762306a36Sopenharmony_ci#define  RP_VEND_XP_DL_UP			(1 << 30)
19862306a36Sopenharmony_ci#define  RP_VEND_XP_OPPORTUNISTIC_ACK		(1 << 27)
19962306a36Sopenharmony_ci#define  RP_VEND_XP_OPPORTUNISTIC_UPDATEFC	(1 << 28)
20062306a36Sopenharmony_ci#define  RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK	(0xff << 18)
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#define RP_VEND_CTL0	0x00000f44
20362306a36Sopenharmony_ci#define  RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK	(0xf << 12)
20462306a36Sopenharmony_ci#define  RP_VEND_CTL0_DSK_RST_PULSE_WIDTH	(0x9 << 12)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define RP_VEND_CTL1	0x00000f48
20762306a36Sopenharmony_ci#define  RP_VEND_CTL1_ERPT	(1 << 13)
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define RP_VEND_XP_BIST	0x00000f4c
21062306a36Sopenharmony_ci#define  RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE	(1 << 28)
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci#define RP_VEND_CTL2 0x00000fa8
21362306a36Sopenharmony_ci#define  RP_VEND_CTL2_PCA_ENABLE (1 << 7)
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define RP_PRIV_MISC	0x00000fe0
21662306a36Sopenharmony_ci#define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT		(0xe << 0)
21762306a36Sopenharmony_ci#define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT		(0xf << 0)
21862306a36Sopenharmony_ci#define  RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK	(0x7f << 16)
21962306a36Sopenharmony_ci#define  RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD		(0xf << 16)
22062306a36Sopenharmony_ci#define  RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE		(1 << 23)
22162306a36Sopenharmony_ci#define  RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK	(0x7f << 24)
22262306a36Sopenharmony_ci#define  RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD		(0xf << 24)
22362306a36Sopenharmony_ci#define  RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE		(1 << 31)
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci#define RP_LINK_CONTROL_STATUS			0x00000090
22662306a36Sopenharmony_ci#define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE	0x20000000
22762306a36Sopenharmony_ci#define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#define RP_LINK_CONTROL_STATUS_2		0x000000b0
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci#define PADS_CTL_SEL		0x0000009c
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci#define PADS_CTL		0x000000a0
23462306a36Sopenharmony_ci#define  PADS_CTL_IDDQ_1L	(1 << 0)
23562306a36Sopenharmony_ci#define  PADS_CTL_TX_DATA_EN_1L	(1 << 6)
23662306a36Sopenharmony_ci#define  PADS_CTL_RX_DATA_EN_1L	(1 << 10)
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#define PADS_PLL_CTL_TEGRA20			0x000000b8
23962306a36Sopenharmony_ci#define PADS_PLL_CTL_TEGRA30			0x000000b4
24062306a36Sopenharmony_ci#define  PADS_PLL_CTL_RST_B4SM			(1 << 1)
24162306a36Sopenharmony_ci#define  PADS_PLL_CTL_LOCKDET			(1 << 8)
24262306a36Sopenharmony_ci#define  PADS_PLL_CTL_REFCLK_MASK		(0x3 << 16)
24362306a36Sopenharmony_ci#define  PADS_PLL_CTL_REFCLK_INTERNAL_CML	(0 << 16)
24462306a36Sopenharmony_ci#define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS	(1 << 16)
24562306a36Sopenharmony_ci#define  PADS_PLL_CTL_REFCLK_EXTERNAL		(2 << 16)
24662306a36Sopenharmony_ci#define  PADS_PLL_CTL_TXCLKREF_MASK		(0x1 << 20)
24762306a36Sopenharmony_ci#define  PADS_PLL_CTL_TXCLKREF_DIV10		(0 << 20)
24862306a36Sopenharmony_ci#define  PADS_PLL_CTL_TXCLKREF_DIV5		(1 << 20)
24962306a36Sopenharmony_ci#define  PADS_PLL_CTL_TXCLKREF_BUF_EN		(1 << 22)
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci#define PADS_REFCLK_CFG0			0x000000c8
25262306a36Sopenharmony_ci#define PADS_REFCLK_CFG1			0x000000cc
25362306a36Sopenharmony_ci#define PADS_REFCLK_BIAS			0x000000d0
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
25762306a36Sopenharmony_ci * entries, one entry per PCIe port. These field definitions and desired
25862306a36Sopenharmony_ci * values aren't in the TRM, but do come from NVIDIA.
25962306a36Sopenharmony_ci */
26062306a36Sopenharmony_ci#define PADS_REFCLK_CFG_TERM_SHIFT		2  /* 6:2 */
26162306a36Sopenharmony_ci#define PADS_REFCLK_CFG_E_TERM_SHIFT		7
26262306a36Sopenharmony_ci#define PADS_REFCLK_CFG_PREDI_SHIFT		8  /* 11:8 */
26362306a36Sopenharmony_ci#define PADS_REFCLK_CFG_DRVI_SHIFT		12 /* 15:12 */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#define PME_ACK_TIMEOUT 10000
26662306a36Sopenharmony_ci#define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistruct tegra_msi {
26962306a36Sopenharmony_ci	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
27062306a36Sopenharmony_ci	struct irq_domain *domain;
27162306a36Sopenharmony_ci	struct mutex map_lock;
27262306a36Sopenharmony_ci	spinlock_t mask_lock;
27362306a36Sopenharmony_ci	void *virt;
27462306a36Sopenharmony_ci	dma_addr_t phys;
27562306a36Sopenharmony_ci	int irq;
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/* used to differentiate between Tegra SoC generations */
27962306a36Sopenharmony_cistruct tegra_pcie_port_soc {
28062306a36Sopenharmony_ci	struct {
28162306a36Sopenharmony_ci		u8 turnoff_bit;
28262306a36Sopenharmony_ci		u8 ack_bit;
28362306a36Sopenharmony_ci	} pme;
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct tegra_pcie_soc {
28762306a36Sopenharmony_ci	unsigned int num_ports;
28862306a36Sopenharmony_ci	const struct tegra_pcie_port_soc *ports;
28962306a36Sopenharmony_ci	unsigned int msi_base_shift;
29062306a36Sopenharmony_ci	unsigned long afi_pex2_ctrl;
29162306a36Sopenharmony_ci	u32 pads_pll_ctl;
29262306a36Sopenharmony_ci	u32 tx_ref_sel;
29362306a36Sopenharmony_ci	u32 pads_refclk_cfg0;
29462306a36Sopenharmony_ci	u32 pads_refclk_cfg1;
29562306a36Sopenharmony_ci	u32 update_fc_threshold;
29662306a36Sopenharmony_ci	bool has_pex_clkreq_en;
29762306a36Sopenharmony_ci	bool has_pex_bias_ctrl;
29862306a36Sopenharmony_ci	bool has_intr_prsnt_sense;
29962306a36Sopenharmony_ci	bool has_cml_clk;
30062306a36Sopenharmony_ci	bool has_gen2;
30162306a36Sopenharmony_ci	bool force_pca_enable;
30262306a36Sopenharmony_ci	bool program_uphy;
30362306a36Sopenharmony_ci	bool update_clamp_threshold;
30462306a36Sopenharmony_ci	bool program_deskew_time;
30562306a36Sopenharmony_ci	bool update_fc_timer;
30662306a36Sopenharmony_ci	bool has_cache_bars;
30762306a36Sopenharmony_ci	struct {
30862306a36Sopenharmony_ci		struct {
30962306a36Sopenharmony_ci			u32 rp_ectl_2_r1;
31062306a36Sopenharmony_ci			u32 rp_ectl_4_r1;
31162306a36Sopenharmony_ci			u32 rp_ectl_5_r1;
31262306a36Sopenharmony_ci			u32 rp_ectl_6_r1;
31362306a36Sopenharmony_ci			u32 rp_ectl_2_r2;
31462306a36Sopenharmony_ci			u32 rp_ectl_4_r2;
31562306a36Sopenharmony_ci			u32 rp_ectl_5_r2;
31662306a36Sopenharmony_ci			u32 rp_ectl_6_r2;
31762306a36Sopenharmony_ci		} regs;
31862306a36Sopenharmony_ci		bool enable;
31962306a36Sopenharmony_ci	} ectl;
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistruct tegra_pcie {
32362306a36Sopenharmony_ci	struct device *dev;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	void __iomem *pads;
32662306a36Sopenharmony_ci	void __iomem *afi;
32762306a36Sopenharmony_ci	void __iomem *cfg;
32862306a36Sopenharmony_ci	int irq;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	struct resource cs;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	struct clk *pex_clk;
33362306a36Sopenharmony_ci	struct clk *afi_clk;
33462306a36Sopenharmony_ci	struct clk *pll_e;
33562306a36Sopenharmony_ci	struct clk *cml_clk;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	struct reset_control *pex_rst;
33862306a36Sopenharmony_ci	struct reset_control *afi_rst;
33962306a36Sopenharmony_ci	struct reset_control *pcie_xrst;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	bool legacy_phy;
34262306a36Sopenharmony_ci	struct phy *phy;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	struct tegra_msi msi;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	struct list_head ports;
34762306a36Sopenharmony_ci	u32 xbar_config;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	struct regulator_bulk_data *supplies;
35062306a36Sopenharmony_ci	unsigned int num_supplies;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc;
35362306a36Sopenharmony_ci	struct dentry *debugfs;
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic inline struct tegra_pcie *msi_to_pcie(struct tegra_msi *msi)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	return container_of(msi, struct tegra_pcie, msi);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistruct tegra_pcie_port {
36262306a36Sopenharmony_ci	struct tegra_pcie *pcie;
36362306a36Sopenharmony_ci	struct device_node *np;
36462306a36Sopenharmony_ci	struct list_head list;
36562306a36Sopenharmony_ci	struct resource regs;
36662306a36Sopenharmony_ci	void __iomem *base;
36762306a36Sopenharmony_ci	unsigned int index;
36862306a36Sopenharmony_ci	unsigned int lanes;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	struct phy **phys;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	struct gpio_desc *reset_gpio;
37362306a36Sopenharmony_ci};
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic inline void afi_writel(struct tegra_pcie *pcie, u32 value,
37662306a36Sopenharmony_ci			      unsigned long offset)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	writel(value, pcie->afi + offset);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic inline u32 afi_readl(struct tegra_pcie *pcie, unsigned long offset)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	return readl(pcie->afi + offset);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic inline void pads_writel(struct tegra_pcie *pcie, u32 value,
38762306a36Sopenharmony_ci			       unsigned long offset)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	writel(value, pcie->pads + offset);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	return readl(pcie->pads + offset);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * The configuration space mapping on Tegra is somewhat similar to the ECAM
39962306a36Sopenharmony_ci * defined by PCIe. However it deviates a bit in how the 4 bits for extended
40062306a36Sopenharmony_ci * register accesses are mapped:
40162306a36Sopenharmony_ci *
40262306a36Sopenharmony_ci *    [27:24] extended register number
40362306a36Sopenharmony_ci *    [23:16] bus number
40462306a36Sopenharmony_ci *    [15:11] device number
40562306a36Sopenharmony_ci *    [10: 8] function number
40662306a36Sopenharmony_ci *    [ 7: 0] register number
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * Mapping the whole extended configuration space would require 256 MiB of
40962306a36Sopenharmony_ci * virtual address space, only a small part of which will actually be used.
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci * To work around this, a 4 KiB region is used to generate the required
41262306a36Sopenharmony_ci * configuration transaction with relevant B:D:F and register offset values.
41362306a36Sopenharmony_ci * This is achieved by dynamically programming base address and size of
41462306a36Sopenharmony_ci * AFI_AXI_BAR used for end point config space mapping to make sure that the
41562306a36Sopenharmony_ci * address (access to which generates correct config transaction) falls in
41662306a36Sopenharmony_ci * this 4 KiB region.
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic unsigned int tegra_pcie_conf_offset(u8 bus, unsigned int devfn,
41962306a36Sopenharmony_ci					   unsigned int where)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) |
42262306a36Sopenharmony_ci	       (PCI_FUNC(devfn) << 8) | (where & 0xff);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
42662306a36Sopenharmony_ci					unsigned int devfn,
42762306a36Sopenharmony_ci					int where)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct tegra_pcie *pcie = bus->sysdata;
43062306a36Sopenharmony_ci	void __iomem *addr = NULL;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (bus->number == 0) {
43362306a36Sopenharmony_ci		unsigned int slot = PCI_SLOT(devfn);
43462306a36Sopenharmony_ci		struct tegra_pcie_port *port;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		list_for_each_entry(port, &pcie->ports, list) {
43762306a36Sopenharmony_ci			if (port->index + 1 == slot) {
43862306a36Sopenharmony_ci				addr = port->base + (where & ~3);
43962306a36Sopenharmony_ci				break;
44062306a36Sopenharmony_ci			}
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci	} else {
44362306a36Sopenharmony_ci		unsigned int offset;
44462306a36Sopenharmony_ci		u32 base;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		offset = tegra_pcie_conf_offset(bus->number, devfn, where);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		/* move 4 KiB window to offset within the FPCI region */
44962306a36Sopenharmony_ci		base = 0xfe100000 + ((offset & ~(SZ_4K - 1)) >> 8);
45062306a36Sopenharmony_ci		afi_writel(pcie, base, AFI_FPCI_BAR0);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		/* move to correct offset within the 4 KiB page */
45362306a36Sopenharmony_ci		addr = pcie->cfg + (offset & (SZ_4K - 1));
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return addr;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
46062306a36Sopenharmony_ci				  int where, int size, u32 *value)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	if (bus->number == 0)
46362306a36Sopenharmony_ci		return pci_generic_config_read32(bus, devfn, where, size,
46462306a36Sopenharmony_ci						 value);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return pci_generic_config_read(bus, devfn, where, size, value);
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
47062306a36Sopenharmony_ci				   int where, int size, u32 value)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	if (bus->number == 0)
47362306a36Sopenharmony_ci		return pci_generic_config_write32(bus, devfn, where, size,
47462306a36Sopenharmony_ci						  value);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return pci_generic_config_write(bus, devfn, where, size, value);
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic struct pci_ops tegra_pcie_ops = {
48062306a36Sopenharmony_ci	.map_bus = tegra_pcie_map_bus,
48162306a36Sopenharmony_ci	.read = tegra_pcie_config_read,
48262306a36Sopenharmony_ci	.write = tegra_pcie_config_write,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
48862306a36Sopenharmony_ci	unsigned long ret = 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	switch (port->index) {
49162306a36Sopenharmony_ci	case 0:
49262306a36Sopenharmony_ci		ret = AFI_PEX0_CTRL;
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	case 1:
49662306a36Sopenharmony_ci		ret = AFI_PEX1_CTRL;
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	case 2:
50062306a36Sopenharmony_ci		ret = soc->afi_pex2_ctrl;
50162306a36Sopenharmony_ci		break;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return ret;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void tegra_pcie_port_reset(struct tegra_pcie_port *port)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
51062306a36Sopenharmony_ci	unsigned long value;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* pulse reset signal */
51362306a36Sopenharmony_ci	if (port->reset_gpio) {
51462306a36Sopenharmony_ci		gpiod_set_value(port->reset_gpio, 1);
51562306a36Sopenharmony_ci	} else {
51662306a36Sopenharmony_ci		value = afi_readl(port->pcie, ctrl);
51762306a36Sopenharmony_ci		value &= ~AFI_PEX_CTRL_RST;
51862306a36Sopenharmony_ci		afi_writel(port->pcie, value, ctrl);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	usleep_range(1000, 2000);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (port->reset_gpio) {
52462306a36Sopenharmony_ci		gpiod_set_value(port->reset_gpio, 0);
52562306a36Sopenharmony_ci	} else {
52662306a36Sopenharmony_ci		value = afi_readl(port->pcie, ctrl);
52762306a36Sopenharmony_ci		value |= AFI_PEX_CTRL_RST;
52862306a36Sopenharmony_ci		afi_writel(port->pcie, value, ctrl);
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
53562306a36Sopenharmony_ci	u32 value;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Enable AER capability */
53862306a36Sopenharmony_ci	value = readl(port->base + RP_VEND_CTL1);
53962306a36Sopenharmony_ci	value |= RP_VEND_CTL1_ERPT;
54062306a36Sopenharmony_ci	writel(value, port->base + RP_VEND_CTL1);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* Optimal settings to enhance bandwidth */
54362306a36Sopenharmony_ci	value = readl(port->base + RP_VEND_XP);
54462306a36Sopenharmony_ci	value |= RP_VEND_XP_OPPORTUNISTIC_ACK;
54562306a36Sopenharmony_ci	value |= RP_VEND_XP_OPPORTUNISTIC_UPDATEFC;
54662306a36Sopenharmony_ci	writel(value, port->base + RP_VEND_XP);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/*
54962306a36Sopenharmony_ci	 * LTSSM will wait for DLLP to finish before entering L1 or L2,
55062306a36Sopenharmony_ci	 * to avoid truncation of PM messages which results in receiver errors
55162306a36Sopenharmony_ci	 */
55262306a36Sopenharmony_ci	value = readl(port->base + RP_VEND_XP_BIST);
55362306a36Sopenharmony_ci	value |= RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE;
55462306a36Sopenharmony_ci	writel(value, port->base + RP_VEND_XP_BIST);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	value = readl(port->base + RP_PRIV_MISC);
55762306a36Sopenharmony_ci	value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE;
55862306a36Sopenharmony_ci	value |= RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (soc->update_clamp_threshold) {
56162306a36Sopenharmony_ci		value &= ~(RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK |
56262306a36Sopenharmony_ci				RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK);
56362306a36Sopenharmony_ci		value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD |
56462306a36Sopenharmony_ci			RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	writel(value, port->base + RP_PRIV_MISC);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
57362306a36Sopenharmony_ci	u32 value;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_2_R1);
57662306a36Sopenharmony_ci	value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK;
57762306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_2_r1;
57862306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_2_R1);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_4_R1);
58162306a36Sopenharmony_ci	value &= ~RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK;
58262306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_4_r1 <<
58362306a36Sopenharmony_ci				RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT;
58462306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_4_R1);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_5_R1);
58762306a36Sopenharmony_ci	value &= ~RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK;
58862306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_5_r1;
58962306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_5_R1);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_6_R1);
59262306a36Sopenharmony_ci	value &= ~RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK;
59362306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_6_r1;
59462306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_6_R1);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_2_R2);
59762306a36Sopenharmony_ci	value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK;
59862306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_2_r2;
59962306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_2_R2);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_4_R2);
60262306a36Sopenharmony_ci	value &= ~RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK;
60362306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_4_r2 <<
60462306a36Sopenharmony_ci				RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT;
60562306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_4_R2);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_5_R2);
60862306a36Sopenharmony_ci	value &= ~RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK;
60962306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_5_r2;
61062306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_5_R2);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	value = readl(port->base + RP_ECTL_6_R2);
61362306a36Sopenharmony_ci	value &= ~RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK;
61462306a36Sopenharmony_ci	value |= soc->ectl.regs.rp_ectl_6_r2;
61562306a36Sopenharmony_ci	writel(value, port->base + RP_ECTL_6_R2);
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
62162306a36Sopenharmony_ci	u32 value;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * Sometimes link speed change from Gen2 to Gen1 fails due to
62562306a36Sopenharmony_ci	 * instability in deskew logic on lane-0. Increase the deskew
62662306a36Sopenharmony_ci	 * retry time to resolve this issue.
62762306a36Sopenharmony_ci	 */
62862306a36Sopenharmony_ci	if (soc->program_deskew_time) {
62962306a36Sopenharmony_ci		value = readl(port->base + RP_VEND_CTL0);
63062306a36Sopenharmony_ci		value &= ~RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK;
63162306a36Sopenharmony_ci		value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH;
63262306a36Sopenharmony_ci		writel(value, port->base + RP_VEND_CTL0);
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (soc->update_fc_timer) {
63662306a36Sopenharmony_ci		value = readl(port->base + RP_VEND_XP);
63762306a36Sopenharmony_ci		value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
63862306a36Sopenharmony_ci		value |= soc->update_fc_threshold;
63962306a36Sopenharmony_ci		writel(value, port->base + RP_VEND_XP);
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/*
64362306a36Sopenharmony_ci	 * PCIe link doesn't come up with few legacy PCIe endpoints if
64462306a36Sopenharmony_ci	 * root port advertises both Gen-1 and Gen-2 speeds in Tegra.
64562306a36Sopenharmony_ci	 * Hence, the strategy followed here is to initially advertise
64662306a36Sopenharmony_ci	 * only Gen-1 and after link is up, retrain link to Gen-2 speed
64762306a36Sopenharmony_ci	 */
64862306a36Sopenharmony_ci	value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
64962306a36Sopenharmony_ci	value &= ~PCI_EXP_LNKSTA_CLS;
65062306a36Sopenharmony_ci	value |= PCI_EXP_LNKSTA_CLS_2_5GB;
65162306a36Sopenharmony_ci	writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic void tegra_pcie_port_enable(struct tegra_pcie_port *port)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
65762306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
65862306a36Sopenharmony_ci	unsigned long value;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* enable reference clock */
66162306a36Sopenharmony_ci	value = afi_readl(port->pcie, ctrl);
66262306a36Sopenharmony_ci	value |= AFI_PEX_CTRL_REFCLK_EN;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (soc->has_pex_clkreq_en)
66562306a36Sopenharmony_ci		value |= AFI_PEX_CTRL_CLKREQ_EN;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	value |= AFI_PEX_CTRL_OVERRIDE_EN;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	afi_writel(port->pcie, value, ctrl);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	tegra_pcie_port_reset(port);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (soc->force_pca_enable) {
67462306a36Sopenharmony_ci		value = readl(port->base + RP_VEND_CTL2);
67562306a36Sopenharmony_ci		value |= RP_VEND_CTL2_PCA_ENABLE;
67662306a36Sopenharmony_ci		writel(value, port->base + RP_VEND_CTL2);
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	tegra_pcie_enable_rp_features(port);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (soc->ectl.enable)
68262306a36Sopenharmony_ci		tegra_pcie_program_ectl_settings(port);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	tegra_pcie_apply_sw_fixup(port);
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic void tegra_pcie_port_disable(struct tegra_pcie_port *port)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
69062306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = port->pcie->soc;
69162306a36Sopenharmony_ci	unsigned long value;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* assert port reset */
69462306a36Sopenharmony_ci	value = afi_readl(port->pcie, ctrl);
69562306a36Sopenharmony_ci	value &= ~AFI_PEX_CTRL_RST;
69662306a36Sopenharmony_ci	afi_writel(port->pcie, value, ctrl);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* disable reference clock */
69962306a36Sopenharmony_ci	value = afi_readl(port->pcie, ctrl);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (soc->has_pex_clkreq_en)
70262306a36Sopenharmony_ci		value &= ~AFI_PEX_CTRL_CLKREQ_EN;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	value &= ~AFI_PEX_CTRL_REFCLK_EN;
70562306a36Sopenharmony_ci	afi_writel(port->pcie, value, ctrl);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* disable PCIe port and set CLKREQ# as GPIO to allow PLLE power down */
70862306a36Sopenharmony_ci	value = afi_readl(port->pcie, AFI_PCIE_CONFIG);
70962306a36Sopenharmony_ci	value |= AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
71062306a36Sopenharmony_ci	value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
71162306a36Sopenharmony_ci	afi_writel(port->pcie, value, AFI_PCIE_CONFIG);
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic void tegra_pcie_port_free(struct tegra_pcie_port *port)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct tegra_pcie *pcie = port->pcie;
71762306a36Sopenharmony_ci	struct device *dev = pcie->dev;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	devm_iounmap(dev, port->base);
72062306a36Sopenharmony_ci	devm_release_mem_region(dev, port->regs.start,
72162306a36Sopenharmony_ci				resource_size(&port->regs));
72262306a36Sopenharmony_ci	list_del(&port->list);
72362306a36Sopenharmony_ci	devm_kfree(dev, port);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci/* Tegra PCIE root complex wrongly reports device class */
72762306a36Sopenharmony_cistatic void tegra_pcie_fixup_class(struct pci_dev *dev)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
73262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
73362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
73462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci/* Tegra20 and Tegra30 PCIE requires relaxed ordering */
73762306a36Sopenharmony_cistatic void tegra_pcie_relax_enable(struct pci_dev *dev)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable);
74262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable);
74362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable);
74462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct tegra_pcie *pcie = pdev->bus->sysdata;
74962306a36Sopenharmony_ci	int irq;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	tegra_cpuidle_pcie_irqs_in_use();
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	irq = of_irq_parse_and_map_pci(pdev, slot, pin);
75462306a36Sopenharmony_ci	if (!irq)
75562306a36Sopenharmony_ci		irq = pcie->irq;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	return irq;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic irqreturn_t tegra_pcie_isr(int irq, void *arg)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	static const char * const err_msg[] = {
76362306a36Sopenharmony_ci		"Unknown",
76462306a36Sopenharmony_ci		"AXI slave error",
76562306a36Sopenharmony_ci		"AXI decode error",
76662306a36Sopenharmony_ci		"Target abort",
76762306a36Sopenharmony_ci		"Master abort",
76862306a36Sopenharmony_ci		"Invalid write",
76962306a36Sopenharmony_ci		"Legacy interrupt",
77062306a36Sopenharmony_ci		"Response decoding error",
77162306a36Sopenharmony_ci		"AXI response decoding error",
77262306a36Sopenharmony_ci		"Transaction timeout",
77362306a36Sopenharmony_ci		"Slot present pin change",
77462306a36Sopenharmony_ci		"Slot clock request change",
77562306a36Sopenharmony_ci		"TMS clock ramp change",
77662306a36Sopenharmony_ci		"TMS ready for power down",
77762306a36Sopenharmony_ci		"Peer2Peer error",
77862306a36Sopenharmony_ci	};
77962306a36Sopenharmony_ci	struct tegra_pcie *pcie = arg;
78062306a36Sopenharmony_ci	struct device *dev = pcie->dev;
78162306a36Sopenharmony_ci	u32 code, signature;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
78462306a36Sopenharmony_ci	signature = afi_readl(pcie, AFI_INTR_SIGNATURE);
78562306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_INTR_CODE);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (code == AFI_INTR_LEGACY)
78862306a36Sopenharmony_ci		return IRQ_NONE;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (code >= ARRAY_SIZE(err_msg))
79162306a36Sopenharmony_ci		code = 0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/*
79462306a36Sopenharmony_ci	 * do not pollute kernel log with master abort reports since they
79562306a36Sopenharmony_ci	 * happen a lot during enumeration
79662306a36Sopenharmony_ci	 */
79762306a36Sopenharmony_ci	if (code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_PE_PRSNT_SENSE)
79862306a36Sopenharmony_ci		dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature);
79962306a36Sopenharmony_ci	else
80062306a36Sopenharmony_ci		dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (code == AFI_INTR_TARGET_ABORT || code == AFI_INTR_MASTER_ABORT ||
80362306a36Sopenharmony_ci	    code == AFI_INTR_FPCI_DECODE_ERROR) {
80462306a36Sopenharmony_ci		u32 fpci = afi_readl(pcie, AFI_UPPER_FPCI_ADDRESS) & 0xff;
80562306a36Sopenharmony_ci		u64 address = (u64)fpci << 32 | (signature & 0xfffffffc);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		if (code == AFI_INTR_MASTER_ABORT)
80862306a36Sopenharmony_ci			dev_dbg(dev, "  FPCI address: %10llx\n", address);
80962306a36Sopenharmony_ci		else
81062306a36Sopenharmony_ci			dev_err(dev, "  FPCI address: %10llx\n", address);
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return IRQ_HANDLED;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/*
81762306a36Sopenharmony_ci * FPCI map is as follows:
81862306a36Sopenharmony_ci * - 0xfdfc000000: I/O space
81962306a36Sopenharmony_ci * - 0xfdfe000000: type 0 configuration space
82062306a36Sopenharmony_ci * - 0xfdff000000: type 1 configuration space
82162306a36Sopenharmony_ci * - 0xfe00000000: type 0 extended configuration space
82262306a36Sopenharmony_ci * - 0xfe10000000: type 1 extended configuration space
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_cistatic void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	u32 size;
82762306a36Sopenharmony_ci	struct resource_entry *entry;
82862306a36Sopenharmony_ci	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* Bar 0: type 1 extended configuration space */
83162306a36Sopenharmony_ci	size = resource_size(&pcie->cs);
83262306a36Sopenharmony_ci	afi_writel(pcie, pcie->cs.start, AFI_AXI_BAR0_START);
83362306a36Sopenharmony_ci	afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	resource_list_for_each_entry(entry, &bridge->windows) {
83662306a36Sopenharmony_ci		u32 fpci_bar, axi_address;
83762306a36Sopenharmony_ci		struct resource *res = entry->res;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		size = resource_size(res);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		switch (resource_type(res)) {
84262306a36Sopenharmony_ci		case IORESOURCE_IO:
84362306a36Sopenharmony_ci			/* Bar 1: downstream IO bar */
84462306a36Sopenharmony_ci			fpci_bar = 0xfdfc0000;
84562306a36Sopenharmony_ci			axi_address = pci_pio_to_address(res->start);
84662306a36Sopenharmony_ci			afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
84762306a36Sopenharmony_ci			afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
84862306a36Sopenharmony_ci			afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
84962306a36Sopenharmony_ci			break;
85062306a36Sopenharmony_ci		case IORESOURCE_MEM:
85162306a36Sopenharmony_ci			fpci_bar = (((res->start >> 12) & 0x0fffffff) << 4) | 0x1;
85262306a36Sopenharmony_ci			axi_address = res->start;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci			if (res->flags & IORESOURCE_PREFETCH) {
85562306a36Sopenharmony_ci				/* Bar 2: prefetchable memory BAR */
85662306a36Sopenharmony_ci				afi_writel(pcie, axi_address, AFI_AXI_BAR2_START);
85762306a36Sopenharmony_ci				afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
85862306a36Sopenharmony_ci				afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci			} else {
86162306a36Sopenharmony_ci				/* Bar 3: non prefetchable memory BAR */
86262306a36Sopenharmony_ci				afi_writel(pcie, axi_address, AFI_AXI_BAR3_START);
86362306a36Sopenharmony_ci				afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
86462306a36Sopenharmony_ci				afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3);
86562306a36Sopenharmony_ci			}
86662306a36Sopenharmony_ci			break;
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* NULL out the remaining BARs as they are not used */
87162306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_AXI_BAR4_START);
87262306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_AXI_BAR4_SZ);
87362306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_FPCI_BAR4);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_AXI_BAR5_START);
87662306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
87762306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_FPCI_BAR5);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (pcie->soc->has_cache_bars) {
88062306a36Sopenharmony_ci		/* map all upstream transactions as uncached */
88162306a36Sopenharmony_ci		afi_writel(pcie, 0, AFI_CACHE_BAR0_ST);
88262306a36Sopenharmony_ci		afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
88362306a36Sopenharmony_ci		afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
88462306a36Sopenharmony_ci		afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* MSI translations are setup only when needed */
88862306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
88962306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
89062306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
89162306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cistatic int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
89762306a36Sopenharmony_ci	u32 value;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(timeout);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	while (time_before(jiffies, timeout)) {
90262306a36Sopenharmony_ci		value = pads_readl(pcie, soc->pads_pll_ctl);
90362306a36Sopenharmony_ci		if (value & PADS_PLL_CTL_LOCKDET)
90462306a36Sopenharmony_ci			return 0;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return -ETIMEDOUT;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct device *dev = pcie->dev;
91362306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
91462306a36Sopenharmony_ci	u32 value;
91562306a36Sopenharmony_ci	int err;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	/* initialize internal PHY, enable up to 16 PCIE lanes */
91862306a36Sopenharmony_ci	pads_writel(pcie, 0x0, PADS_CTL_SEL);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* override IDDQ to 1 on all 4 lanes */
92162306a36Sopenharmony_ci	value = pads_readl(pcie, PADS_CTL);
92262306a36Sopenharmony_ci	value |= PADS_CTL_IDDQ_1L;
92362306a36Sopenharmony_ci	pads_writel(pcie, value, PADS_CTL);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/*
92662306a36Sopenharmony_ci	 * Set up PHY PLL inputs select PLLE output as refclock,
92762306a36Sopenharmony_ci	 * set TX ref sel to div10 (not div5).
92862306a36Sopenharmony_ci	 */
92962306a36Sopenharmony_ci	value = pads_readl(pcie, soc->pads_pll_ctl);
93062306a36Sopenharmony_ci	value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
93162306a36Sopenharmony_ci	value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
93262306a36Sopenharmony_ci	pads_writel(pcie, value, soc->pads_pll_ctl);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* reset PLL */
93562306a36Sopenharmony_ci	value = pads_readl(pcie, soc->pads_pll_ctl);
93662306a36Sopenharmony_ci	value &= ~PADS_PLL_CTL_RST_B4SM;
93762306a36Sopenharmony_ci	pads_writel(pcie, value, soc->pads_pll_ctl);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	usleep_range(20, 100);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/* take PLL out of reset  */
94262306a36Sopenharmony_ci	value = pads_readl(pcie, soc->pads_pll_ctl);
94362306a36Sopenharmony_ci	value |= PADS_PLL_CTL_RST_B4SM;
94462306a36Sopenharmony_ci	pads_writel(pcie, value, soc->pads_pll_ctl);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* wait for the PLL to lock */
94762306a36Sopenharmony_ci	err = tegra_pcie_pll_wait(pcie, 500);
94862306a36Sopenharmony_ci	if (err < 0) {
94962306a36Sopenharmony_ci		dev_err(dev, "PLL failed to lock: %d\n", err);
95062306a36Sopenharmony_ci		return err;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* turn off IDDQ override */
95462306a36Sopenharmony_ci	value = pads_readl(pcie, PADS_CTL);
95562306a36Sopenharmony_ci	value &= ~PADS_CTL_IDDQ_1L;
95662306a36Sopenharmony_ci	pads_writel(pcie, value, PADS_CTL);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* enable TX/RX data */
95962306a36Sopenharmony_ci	value = pads_readl(pcie, PADS_CTL);
96062306a36Sopenharmony_ci	value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
96162306a36Sopenharmony_ci	pads_writel(pcie, value, PADS_CTL);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int tegra_pcie_phy_disable(struct tegra_pcie *pcie)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
96962306a36Sopenharmony_ci	u32 value;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* disable TX/RX data */
97262306a36Sopenharmony_ci	value = pads_readl(pcie, PADS_CTL);
97362306a36Sopenharmony_ci	value &= ~(PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
97462306a36Sopenharmony_ci	pads_writel(pcie, value, PADS_CTL);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	/* override IDDQ */
97762306a36Sopenharmony_ci	value = pads_readl(pcie, PADS_CTL);
97862306a36Sopenharmony_ci	value |= PADS_CTL_IDDQ_1L;
97962306a36Sopenharmony_ci	pads_writel(pcie, value, PADS_CTL);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* reset PLL */
98262306a36Sopenharmony_ci	value = pads_readl(pcie, soc->pads_pll_ctl);
98362306a36Sopenharmony_ci	value &= ~PADS_PLL_CTL_RST_B4SM;
98462306a36Sopenharmony_ci	pads_writel(pcie, value, soc->pads_pll_ctl);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	usleep_range(20, 100);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return 0;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct device *dev = port->pcie->dev;
99462306a36Sopenharmony_ci	unsigned int i;
99562306a36Sopenharmony_ci	int err;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	for (i = 0; i < port->lanes; i++) {
99862306a36Sopenharmony_ci		err = phy_power_on(port->phys[i]);
99962306a36Sopenharmony_ci		if (err < 0) {
100062306a36Sopenharmony_ci			dev_err(dev, "failed to power on PHY#%u: %d\n", i, err);
100162306a36Sopenharmony_ci			return err;
100262306a36Sopenharmony_ci		}
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	return 0;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_cistatic int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
100962306a36Sopenharmony_ci{
101062306a36Sopenharmony_ci	struct device *dev = port->pcie->dev;
101162306a36Sopenharmony_ci	unsigned int i;
101262306a36Sopenharmony_ci	int err;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	for (i = 0; i < port->lanes; i++) {
101562306a36Sopenharmony_ci		err = phy_power_off(port->phys[i]);
101662306a36Sopenharmony_ci		if (err < 0) {
101762306a36Sopenharmony_ci			dev_err(dev, "failed to power off PHY#%u: %d\n", i,
101862306a36Sopenharmony_ci				err);
101962306a36Sopenharmony_ci			return err;
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	return 0;
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct device *dev = pcie->dev;
102962306a36Sopenharmony_ci	struct tegra_pcie_port *port;
103062306a36Sopenharmony_ci	int err;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (pcie->legacy_phy) {
103362306a36Sopenharmony_ci		if (pcie->phy)
103462306a36Sopenharmony_ci			err = phy_power_on(pcie->phy);
103562306a36Sopenharmony_ci		else
103662306a36Sopenharmony_ci			err = tegra_pcie_phy_enable(pcie);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		if (err < 0)
103962306a36Sopenharmony_ci			dev_err(dev, "failed to power on PHY: %d\n", err);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		return err;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
104562306a36Sopenharmony_ci		err = tegra_pcie_port_phy_power_on(port);
104662306a36Sopenharmony_ci		if (err < 0) {
104762306a36Sopenharmony_ci			dev_err(dev,
104862306a36Sopenharmony_ci				"failed to power on PCIe port %u PHY: %d\n",
104962306a36Sopenharmony_ci				port->index, err);
105062306a36Sopenharmony_ci			return err;
105162306a36Sopenharmony_ci		}
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return 0;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic int tegra_pcie_phy_power_off(struct tegra_pcie *pcie)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	struct device *dev = pcie->dev;
106062306a36Sopenharmony_ci	struct tegra_pcie_port *port;
106162306a36Sopenharmony_ci	int err;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (pcie->legacy_phy) {
106462306a36Sopenharmony_ci		if (pcie->phy)
106562306a36Sopenharmony_ci			err = phy_power_off(pcie->phy);
106662306a36Sopenharmony_ci		else
106762306a36Sopenharmony_ci			err = tegra_pcie_phy_disable(pcie);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		if (err < 0)
107062306a36Sopenharmony_ci			dev_err(dev, "failed to power off PHY: %d\n", err);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		return err;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
107662306a36Sopenharmony_ci		err = tegra_pcie_port_phy_power_off(port);
107762306a36Sopenharmony_ci		if (err < 0) {
107862306a36Sopenharmony_ci			dev_err(dev,
107962306a36Sopenharmony_ci				"failed to power off PCIe port %u PHY: %d\n",
108062306a36Sopenharmony_ci				port->index, err);
108162306a36Sopenharmony_ci			return err;
108262306a36Sopenharmony_ci		}
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
109162306a36Sopenharmony_ci	struct tegra_pcie_port *port;
109262306a36Sopenharmony_ci	unsigned long value;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* enable PLL power down */
109562306a36Sopenharmony_ci	if (pcie->phy) {
109662306a36Sopenharmony_ci		value = afi_readl(pcie, AFI_PLLE_CONTROL);
109762306a36Sopenharmony_ci		value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
109862306a36Sopenharmony_ci		value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
109962306a36Sopenharmony_ci		afi_writel(pcie, value, AFI_PLLE_CONTROL);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* power down PCIe slot clock bias pad */
110362306a36Sopenharmony_ci	if (soc->has_pex_bias_ctrl)
110462306a36Sopenharmony_ci		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/* configure mode and disable all ports */
110762306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_PCIE_CONFIG);
110862306a36Sopenharmony_ci	value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
110962306a36Sopenharmony_ci	value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
111062306a36Sopenharmony_ci	value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
111362306a36Sopenharmony_ci		value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
111462306a36Sopenharmony_ci		value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_PCIE_CONFIG);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (soc->has_gen2) {
112062306a36Sopenharmony_ci		value = afi_readl(pcie, AFI_FUSE);
112162306a36Sopenharmony_ci		value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
112262306a36Sopenharmony_ci		afi_writel(pcie, value, AFI_FUSE);
112362306a36Sopenharmony_ci	} else {
112462306a36Sopenharmony_ci		value = afi_readl(pcie, AFI_FUSE);
112562306a36Sopenharmony_ci		value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
112662306a36Sopenharmony_ci		afi_writel(pcie, value, AFI_FUSE);
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Disable AFI dynamic clock gating and enable PCIe */
113062306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_CONFIGURATION);
113162306a36Sopenharmony_ci	value |= AFI_CONFIGURATION_EN_FPCI;
113262306a36Sopenharmony_ci	value |= AFI_CONFIGURATION_CLKEN_OVERRIDE;
113362306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_CONFIGURATION);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
113662306a36Sopenharmony_ci		AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
113762306a36Sopenharmony_ci		AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (soc->has_intr_prsnt_sense)
114062306a36Sopenharmony_ci		value |= AFI_INTR_EN_PRSNT_SENSE;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_AFI_INTR_ENABLE);
114362306a36Sopenharmony_ci	afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/* don't enable MSI for now, only when needed */
114662306a36Sopenharmony_ci	afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/* disable all exceptions */
114962306a36Sopenharmony_ci	afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic void tegra_pcie_power_off(struct tegra_pcie *pcie)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	struct device *dev = pcie->dev;
115562306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
115662306a36Sopenharmony_ci	int err;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	reset_control_assert(pcie->afi_rst);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	clk_disable_unprepare(pcie->pll_e);
116162306a36Sopenharmony_ci	if (soc->has_cml_clk)
116262306a36Sopenharmony_ci		clk_disable_unprepare(pcie->cml_clk);
116362306a36Sopenharmony_ci	clk_disable_unprepare(pcie->afi_clk);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (!dev->pm_domain)
116662306a36Sopenharmony_ci		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
116962306a36Sopenharmony_ci	if (err < 0)
117062306a36Sopenharmony_ci		dev_warn(dev, "failed to disable regulators: %d\n", err);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic int tegra_pcie_power_on(struct tegra_pcie *pcie)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	struct device *dev = pcie->dev;
117662306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
117762306a36Sopenharmony_ci	int err;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	reset_control_assert(pcie->pcie_xrst);
118062306a36Sopenharmony_ci	reset_control_assert(pcie->afi_rst);
118162306a36Sopenharmony_ci	reset_control_assert(pcie->pex_rst);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (!dev->pm_domain)
118462306a36Sopenharmony_ci		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* enable regulators */
118762306a36Sopenharmony_ci	err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
118862306a36Sopenharmony_ci	if (err < 0)
118962306a36Sopenharmony_ci		dev_err(dev, "failed to enable regulators: %d\n", err);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (!dev->pm_domain) {
119262306a36Sopenharmony_ci		err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE);
119362306a36Sopenharmony_ci		if (err) {
119462306a36Sopenharmony_ci			dev_err(dev, "failed to power ungate: %d\n", err);
119562306a36Sopenharmony_ci			goto regulator_disable;
119662306a36Sopenharmony_ci		}
119762306a36Sopenharmony_ci		err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE);
119862306a36Sopenharmony_ci		if (err) {
119962306a36Sopenharmony_ci			dev_err(dev, "failed to remove clamp: %d\n", err);
120062306a36Sopenharmony_ci			goto powergate;
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	err = clk_prepare_enable(pcie->afi_clk);
120562306a36Sopenharmony_ci	if (err < 0) {
120662306a36Sopenharmony_ci		dev_err(dev, "failed to enable AFI clock: %d\n", err);
120762306a36Sopenharmony_ci		goto powergate;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (soc->has_cml_clk) {
121162306a36Sopenharmony_ci		err = clk_prepare_enable(pcie->cml_clk);
121262306a36Sopenharmony_ci		if (err < 0) {
121362306a36Sopenharmony_ci			dev_err(dev, "failed to enable CML clock: %d\n", err);
121462306a36Sopenharmony_ci			goto disable_afi_clk;
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	err = clk_prepare_enable(pcie->pll_e);
121962306a36Sopenharmony_ci	if (err < 0) {
122062306a36Sopenharmony_ci		dev_err(dev, "failed to enable PLLE clock: %d\n", err);
122162306a36Sopenharmony_ci		goto disable_cml_clk;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	reset_control_deassert(pcie->afi_rst);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return 0;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cidisable_cml_clk:
122962306a36Sopenharmony_ci	if (soc->has_cml_clk)
123062306a36Sopenharmony_ci		clk_disable_unprepare(pcie->cml_clk);
123162306a36Sopenharmony_cidisable_afi_clk:
123262306a36Sopenharmony_ci	clk_disable_unprepare(pcie->afi_clk);
123362306a36Sopenharmony_cipowergate:
123462306a36Sopenharmony_ci	if (!dev->pm_domain)
123562306a36Sopenharmony_ci		tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
123662306a36Sopenharmony_ciregulator_disable:
123762306a36Sopenharmony_ci	regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	return err;
124062306a36Sopenharmony_ci}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic void tegra_pcie_apply_pad_settings(struct tegra_pcie *pcie)
124362306a36Sopenharmony_ci{
124462306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	/* Configure the reference clock driver */
124762306a36Sopenharmony_ci	pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (soc->num_ports > 2)
125062306a36Sopenharmony_ci		pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct device *dev = pcie->dev;
125662306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	pcie->pex_clk = devm_clk_get(dev, "pex");
125962306a36Sopenharmony_ci	if (IS_ERR(pcie->pex_clk))
126062306a36Sopenharmony_ci		return PTR_ERR(pcie->pex_clk);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	pcie->afi_clk = devm_clk_get(dev, "afi");
126362306a36Sopenharmony_ci	if (IS_ERR(pcie->afi_clk))
126462306a36Sopenharmony_ci		return PTR_ERR(pcie->afi_clk);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	pcie->pll_e = devm_clk_get(dev, "pll_e");
126762306a36Sopenharmony_ci	if (IS_ERR(pcie->pll_e))
126862306a36Sopenharmony_ci		return PTR_ERR(pcie->pll_e);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if (soc->has_cml_clk) {
127162306a36Sopenharmony_ci		pcie->cml_clk = devm_clk_get(dev, "cml");
127262306a36Sopenharmony_ci		if (IS_ERR(pcie->cml_clk))
127362306a36Sopenharmony_ci			return PTR_ERR(pcie->cml_clk);
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	return 0;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic int tegra_pcie_resets_get(struct tegra_pcie *pcie)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct device *dev = pcie->dev;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	pcie->pex_rst = devm_reset_control_get_exclusive(dev, "pex");
128462306a36Sopenharmony_ci	if (IS_ERR(pcie->pex_rst))
128562306a36Sopenharmony_ci		return PTR_ERR(pcie->pex_rst);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	pcie->afi_rst = devm_reset_control_get_exclusive(dev, "afi");
128862306a36Sopenharmony_ci	if (IS_ERR(pcie->afi_rst))
128962306a36Sopenharmony_ci		return PTR_ERR(pcie->afi_rst);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	pcie->pcie_xrst = devm_reset_control_get_exclusive(dev, "pcie_x");
129262306a36Sopenharmony_ci	if (IS_ERR(pcie->pcie_xrst))
129362306a36Sopenharmony_ci		return PTR_ERR(pcie->pcie_xrst);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	return 0;
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct device *dev = pcie->dev;
130162306a36Sopenharmony_ci	int err;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	pcie->phy = devm_phy_optional_get(dev, "pcie");
130462306a36Sopenharmony_ci	if (IS_ERR(pcie->phy)) {
130562306a36Sopenharmony_ci		err = PTR_ERR(pcie->phy);
130662306a36Sopenharmony_ci		dev_err(dev, "failed to get PHY: %d\n", err);
130762306a36Sopenharmony_ci		return err;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	err = phy_init(pcie->phy);
131162306a36Sopenharmony_ci	if (err < 0) {
131262306a36Sopenharmony_ci		dev_err(dev, "failed to initialize PHY: %d\n", err);
131362306a36Sopenharmony_ci		return err;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	pcie->legacy_phy = true;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return 0;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic struct phy *devm_of_phy_optional_get_index(struct device *dev,
132262306a36Sopenharmony_ci						  struct device_node *np,
132362306a36Sopenharmony_ci						  const char *consumer,
132462306a36Sopenharmony_ci						  unsigned int index)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	struct phy *phy;
132762306a36Sopenharmony_ci	char *name;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index);
133062306a36Sopenharmony_ci	if (!name)
133162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	phy = devm_of_phy_optional_get(dev, np, name);
133462306a36Sopenharmony_ci	kfree(name);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	return phy;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic int tegra_pcie_port_get_phys(struct tegra_pcie_port *port)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	struct device *dev = port->pcie->dev;
134262306a36Sopenharmony_ci	struct phy *phy;
134362306a36Sopenharmony_ci	unsigned int i;
134462306a36Sopenharmony_ci	int err;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL);
134762306a36Sopenharmony_ci	if (!port->phys)
134862306a36Sopenharmony_ci		return -ENOMEM;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	for (i = 0; i < port->lanes; i++) {
135162306a36Sopenharmony_ci		phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i);
135262306a36Sopenharmony_ci		if (IS_ERR(phy)) {
135362306a36Sopenharmony_ci			dev_err(dev, "failed to get PHY#%u: %ld\n", i,
135462306a36Sopenharmony_ci				PTR_ERR(phy));
135562306a36Sopenharmony_ci			return PTR_ERR(phy);
135662306a36Sopenharmony_ci		}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci		err = phy_init(phy);
135962306a36Sopenharmony_ci		if (err < 0) {
136062306a36Sopenharmony_ci			dev_err(dev, "failed to initialize PHY#%u: %d\n", i,
136162306a36Sopenharmony_ci				err);
136262306a36Sopenharmony_ci			return err;
136362306a36Sopenharmony_ci		}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci		port->phys[i] = phy;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	return 0;
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic int tegra_pcie_phys_get(struct tegra_pcie *pcie)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
137462306a36Sopenharmony_ci	struct device_node *np = pcie->dev->of_node;
137562306a36Sopenharmony_ci	struct tegra_pcie_port *port;
137662306a36Sopenharmony_ci	int err;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (!soc->has_gen2 || of_property_present(np, "phys"))
137962306a36Sopenharmony_ci		return tegra_pcie_phys_get_legacy(pcie);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
138262306a36Sopenharmony_ci		err = tegra_pcie_port_get_phys(port);
138362306a36Sopenharmony_ci		if (err < 0)
138462306a36Sopenharmony_ci			return err;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return 0;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void tegra_pcie_phys_put(struct tegra_pcie *pcie)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	struct tegra_pcie_port *port;
139362306a36Sopenharmony_ci	struct device *dev = pcie->dev;
139462306a36Sopenharmony_ci	int err, i;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (pcie->legacy_phy) {
139762306a36Sopenharmony_ci		err = phy_exit(pcie->phy);
139862306a36Sopenharmony_ci		if (err < 0)
139962306a36Sopenharmony_ci			dev_err(dev, "failed to teardown PHY: %d\n", err);
140062306a36Sopenharmony_ci		return;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
140462306a36Sopenharmony_ci		for (i = 0; i < port->lanes; i++) {
140562306a36Sopenharmony_ci			err = phy_exit(port->phys[i]);
140662306a36Sopenharmony_ci			if (err < 0)
140762306a36Sopenharmony_ci				dev_err(dev, "failed to teardown PHY#%u: %d\n",
140862306a36Sopenharmony_ci					i, err);
140962306a36Sopenharmony_ci		}
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic int tegra_pcie_get_resources(struct tegra_pcie *pcie)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	struct device *dev = pcie->dev;
141662306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
141762306a36Sopenharmony_ci	struct resource *res;
141862306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
141962306a36Sopenharmony_ci	int err;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	err = tegra_pcie_clocks_get(pcie);
142262306a36Sopenharmony_ci	if (err) {
142362306a36Sopenharmony_ci		dev_err(dev, "failed to get clocks: %d\n", err);
142462306a36Sopenharmony_ci		return err;
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	err = tegra_pcie_resets_get(pcie);
142862306a36Sopenharmony_ci	if (err) {
142962306a36Sopenharmony_ci		dev_err(dev, "failed to get resets: %d\n", err);
143062306a36Sopenharmony_ci		return err;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	if (soc->program_uphy) {
143462306a36Sopenharmony_ci		err = tegra_pcie_phys_get(pcie);
143562306a36Sopenharmony_ci		if (err < 0) {
143662306a36Sopenharmony_ci			dev_err(dev, "failed to get PHYs: %d\n", err);
143762306a36Sopenharmony_ci			return err;
143862306a36Sopenharmony_ci		}
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	pcie->pads = devm_platform_ioremap_resource_byname(pdev, "pads");
144262306a36Sopenharmony_ci	if (IS_ERR(pcie->pads)) {
144362306a36Sopenharmony_ci		err = PTR_ERR(pcie->pads);
144462306a36Sopenharmony_ci		goto phys_put;
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	pcie->afi = devm_platform_ioremap_resource_byname(pdev, "afi");
144862306a36Sopenharmony_ci	if (IS_ERR(pcie->afi)) {
144962306a36Sopenharmony_ci		err = PTR_ERR(pcie->afi);
145062306a36Sopenharmony_ci		goto phys_put;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	/* request configuration space, but remap later, on demand */
145462306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs");
145562306a36Sopenharmony_ci	if (!res) {
145662306a36Sopenharmony_ci		err = -EADDRNOTAVAIL;
145762306a36Sopenharmony_ci		goto phys_put;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	pcie->cs = *res;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	/* constrain configuration space to 4 KiB */
146362306a36Sopenharmony_ci	pcie->cs.end = pcie->cs.start + SZ_4K - 1;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	pcie->cfg = devm_ioremap_resource(dev, &pcie->cs);
146662306a36Sopenharmony_ci	if (IS_ERR(pcie->cfg)) {
146762306a36Sopenharmony_ci		err = PTR_ERR(pcie->cfg);
146862306a36Sopenharmony_ci		goto phys_put;
146962306a36Sopenharmony_ci	}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	/* request interrupt */
147262306a36Sopenharmony_ci	err = platform_get_irq_byname(pdev, "intr");
147362306a36Sopenharmony_ci	if (err < 0)
147462306a36Sopenharmony_ci		goto phys_put;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	pcie->irq = err;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE", pcie);
147962306a36Sopenharmony_ci	if (err) {
148062306a36Sopenharmony_ci		dev_err(dev, "failed to register IRQ: %d\n", err);
148162306a36Sopenharmony_ci		goto phys_put;
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	return 0;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ciphys_put:
148762306a36Sopenharmony_ci	if (soc->program_uphy)
148862306a36Sopenharmony_ci		tegra_pcie_phys_put(pcie);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	return err;
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic int tegra_pcie_put_resources(struct tegra_pcie *pcie)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (pcie->irq > 0)
149862306a36Sopenharmony_ci		free_irq(pcie->irq, pcie);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (soc->program_uphy)
150162306a36Sopenharmony_ci		tegra_pcie_phys_put(pcie);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	return 0;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic void tegra_pcie_pme_turnoff(struct tegra_pcie_port *port)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct tegra_pcie *pcie = port->pcie;
150962306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
151062306a36Sopenharmony_ci	int err;
151162306a36Sopenharmony_ci	u32 val;
151262306a36Sopenharmony_ci	u8 ack_bit;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	val = afi_readl(pcie, AFI_PCIE_PME);
151562306a36Sopenharmony_ci	val |= (0x1 << soc->ports[port->index].pme.turnoff_bit);
151662306a36Sopenharmony_ci	afi_writel(pcie, val, AFI_PCIE_PME);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	ack_bit = soc->ports[port->index].pme.ack_bit;
151962306a36Sopenharmony_ci	err = readl_poll_timeout(pcie->afi + AFI_PCIE_PME, val,
152062306a36Sopenharmony_ci				 val & (0x1 << ack_bit), 1, PME_ACK_TIMEOUT);
152162306a36Sopenharmony_ci	if (err)
152262306a36Sopenharmony_ci		dev_err(pcie->dev, "PME Ack is not received on port: %d\n",
152362306a36Sopenharmony_ci			port->index);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	usleep_range(10000, 11000);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	val = afi_readl(pcie, AFI_PCIE_PME);
152862306a36Sopenharmony_ci	val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit);
152962306a36Sopenharmony_ci	afi_writel(pcie, val, AFI_PCIE_PME);
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_cistatic void tegra_pcie_msi_irq(struct irq_desc *desc)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	struct tegra_pcie *pcie = irq_desc_get_handler_data(desc);
153562306a36Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
153662306a36Sopenharmony_ci	struct tegra_msi *msi = &pcie->msi;
153762306a36Sopenharmony_ci	struct device *dev = pcie->dev;
153862306a36Sopenharmony_ci	unsigned int i;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	chained_irq_enter(chip, desc);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
154362306a36Sopenharmony_ci		unsigned long reg = afi_readl(pcie, AFI_MSI_VEC(i));
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci		while (reg) {
154662306a36Sopenharmony_ci			unsigned int offset = find_first_bit(&reg, 32);
154762306a36Sopenharmony_ci			unsigned int index = i * 32 + offset;
154862306a36Sopenharmony_ci			int ret;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci			ret = generic_handle_domain_irq(msi->domain->parent, index);
155162306a36Sopenharmony_ci			if (ret) {
155262306a36Sopenharmony_ci				/*
155362306a36Sopenharmony_ci				 * that's weird who triggered this?
155462306a36Sopenharmony_ci				 * just clear it
155562306a36Sopenharmony_ci				 */
155662306a36Sopenharmony_ci				dev_info(dev, "unexpected MSI\n");
155762306a36Sopenharmony_ci				afi_writel(pcie, BIT(index % 32), AFI_MSI_VEC(index));
155862306a36Sopenharmony_ci			}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci			/* see if there's any more pending in this vector */
156162306a36Sopenharmony_ci			reg = afi_readl(pcie, AFI_MSI_VEC(i));
156262306a36Sopenharmony_ci		}
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	chained_irq_exit(chip, desc);
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic void tegra_msi_top_irq_ack(struct irq_data *d)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	irq_chip_ack_parent(d);
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_cistatic void tegra_msi_top_irq_mask(struct irq_data *d)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	pci_msi_mask_irq(d);
157662306a36Sopenharmony_ci	irq_chip_mask_parent(d);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic void tegra_msi_top_irq_unmask(struct irq_data *d)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	pci_msi_unmask_irq(d);
158262306a36Sopenharmony_ci	irq_chip_unmask_parent(d);
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic struct irq_chip tegra_msi_top_chip = {
158662306a36Sopenharmony_ci	.name		= "Tegra PCIe MSI",
158762306a36Sopenharmony_ci	.irq_ack	= tegra_msi_top_irq_ack,
158862306a36Sopenharmony_ci	.irq_mask	= tegra_msi_top_irq_mask,
158962306a36Sopenharmony_ci	.irq_unmask	= tegra_msi_top_irq_unmask,
159062306a36Sopenharmony_ci};
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_cistatic void tegra_msi_irq_ack(struct irq_data *d)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
159562306a36Sopenharmony_ci	struct tegra_pcie *pcie = msi_to_pcie(msi);
159662306a36Sopenharmony_ci	unsigned int index = d->hwirq / 32;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	/* clear the interrupt */
159962306a36Sopenharmony_ci	afi_writel(pcie, BIT(d->hwirq % 32), AFI_MSI_VEC(index));
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic void tegra_msi_irq_mask(struct irq_data *d)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
160562306a36Sopenharmony_ci	struct tegra_pcie *pcie = msi_to_pcie(msi);
160662306a36Sopenharmony_ci	unsigned int index = d->hwirq / 32;
160762306a36Sopenharmony_ci	unsigned long flags;
160862306a36Sopenharmony_ci	u32 value;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	spin_lock_irqsave(&msi->mask_lock, flags);
161162306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
161262306a36Sopenharmony_ci	value &= ~BIT(d->hwirq % 32);
161362306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
161462306a36Sopenharmony_ci	spin_unlock_irqrestore(&msi->mask_lock, flags);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_cistatic void tegra_msi_irq_unmask(struct irq_data *d)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	struct tegra_msi *msi = irq_data_get_irq_chip_data(d);
162062306a36Sopenharmony_ci	struct tegra_pcie *pcie = msi_to_pcie(msi);
162162306a36Sopenharmony_ci	unsigned int index = d->hwirq / 32;
162262306a36Sopenharmony_ci	unsigned long flags;
162362306a36Sopenharmony_ci	u32 value;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	spin_lock_irqsave(&msi->mask_lock, flags);
162662306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_MSI_EN_VEC(index));
162762306a36Sopenharmony_ci	value |= BIT(d->hwirq % 32);
162862306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_MSI_EN_VEC(index));
162962306a36Sopenharmony_ci	spin_unlock_irqrestore(&msi->mask_lock, flags);
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic int tegra_msi_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	return -EINVAL;
163562306a36Sopenharmony_ci}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic void tegra_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	struct tegra_msi *msi = irq_data_get_irq_chip_data(data);
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	msg->address_lo = lower_32_bits(msi->phys);
164262306a36Sopenharmony_ci	msg->address_hi = upper_32_bits(msi->phys);
164362306a36Sopenharmony_ci	msg->data = data->hwirq;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_cistatic struct irq_chip tegra_msi_bottom_chip = {
164762306a36Sopenharmony_ci	.name			= "Tegra MSI",
164862306a36Sopenharmony_ci	.irq_ack		= tegra_msi_irq_ack,
164962306a36Sopenharmony_ci	.irq_mask		= tegra_msi_irq_mask,
165062306a36Sopenharmony_ci	.irq_unmask		= tegra_msi_irq_unmask,
165162306a36Sopenharmony_ci	.irq_set_affinity 	= tegra_msi_set_affinity,
165262306a36Sopenharmony_ci	.irq_compose_msi_msg	= tegra_compose_msi_msg,
165362306a36Sopenharmony_ci};
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_cistatic int tegra_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
165662306a36Sopenharmony_ci				  unsigned int nr_irqs, void *args)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct tegra_msi *msi = domain->host_data;
165962306a36Sopenharmony_ci	unsigned int i;
166062306a36Sopenharmony_ci	int hwirq;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	mutex_lock(&msi->map_lock);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	hwirq = bitmap_find_free_region(msi->used, INT_PCI_MSI_NR, order_base_2(nr_irqs));
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	mutex_unlock(&msi->map_lock);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (hwirq < 0)
166962306a36Sopenharmony_ci		return -ENOSPC;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	for (i = 0; i < nr_irqs; i++)
167262306a36Sopenharmony_ci		irq_domain_set_info(domain, virq + i, hwirq + i,
167362306a36Sopenharmony_ci				    &tegra_msi_bottom_chip, domain->host_data,
167462306a36Sopenharmony_ci				    handle_edge_irq, NULL, NULL);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	tegra_cpuidle_pcie_irqs_in_use();
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	return 0;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic void tegra_msi_domain_free(struct irq_domain *domain, unsigned int virq,
168262306a36Sopenharmony_ci				  unsigned int nr_irqs)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
168562306a36Sopenharmony_ci	struct tegra_msi *msi = domain->host_data;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	mutex_lock(&msi->map_lock);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	bitmap_release_region(msi->used, d->hwirq, order_base_2(nr_irqs));
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	mutex_unlock(&msi->map_lock);
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic const struct irq_domain_ops tegra_msi_domain_ops = {
169562306a36Sopenharmony_ci	.alloc = tegra_msi_domain_alloc,
169662306a36Sopenharmony_ci	.free = tegra_msi_domain_free,
169762306a36Sopenharmony_ci};
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic struct msi_domain_info tegra_msi_info = {
170062306a36Sopenharmony_ci	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
170162306a36Sopenharmony_ci		   MSI_FLAG_PCI_MSIX),
170262306a36Sopenharmony_ci	.chip	= &tegra_msi_top_chip,
170362306a36Sopenharmony_ci};
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistatic int tegra_allocate_domains(struct tegra_msi *msi)
170662306a36Sopenharmony_ci{
170762306a36Sopenharmony_ci	struct tegra_pcie *pcie = msi_to_pcie(msi);
170862306a36Sopenharmony_ci	struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
170962306a36Sopenharmony_ci	struct irq_domain *parent;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	parent = irq_domain_create_linear(fwnode, INT_PCI_MSI_NR,
171262306a36Sopenharmony_ci					  &tegra_msi_domain_ops, msi);
171362306a36Sopenharmony_ci	if (!parent) {
171462306a36Sopenharmony_ci		dev_err(pcie->dev, "failed to create IRQ domain\n");
171562306a36Sopenharmony_ci		return -ENOMEM;
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci	irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	msi->domain = pci_msi_create_irq_domain(fwnode, &tegra_msi_info, parent);
172062306a36Sopenharmony_ci	if (!msi->domain) {
172162306a36Sopenharmony_ci		dev_err(pcie->dev, "failed to create MSI domain\n");
172262306a36Sopenharmony_ci		irq_domain_remove(parent);
172362306a36Sopenharmony_ci		return -ENOMEM;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	return 0;
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_cistatic void tegra_free_domains(struct tegra_msi *msi)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	struct irq_domain *parent = msi->domain->parent;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	irq_domain_remove(msi->domain);
173462306a36Sopenharmony_ci	irq_domain_remove(parent);
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(pcie->dev);
174062306a36Sopenharmony_ci	struct tegra_msi *msi = &pcie->msi;
174162306a36Sopenharmony_ci	struct device *dev = pcie->dev;
174262306a36Sopenharmony_ci	int err;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	mutex_init(&msi->map_lock);
174562306a36Sopenharmony_ci	spin_lock_init(&msi->mask_lock);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI)) {
174862306a36Sopenharmony_ci		err = tegra_allocate_domains(msi);
174962306a36Sopenharmony_ci		if (err)
175062306a36Sopenharmony_ci			return err;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	err = platform_get_irq_byname(pdev, "msi");
175462306a36Sopenharmony_ci	if (err < 0)
175562306a36Sopenharmony_ci		goto free_irq_domain;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	msi->irq = err;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	irq_set_chained_handler_and_data(msi->irq, tegra_pcie_msi_irq, pcie);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	/* Though the PCIe controller can address >32-bit address space, to
176262306a36Sopenharmony_ci	 * facilitate endpoints that support only 32-bit MSI target address,
176362306a36Sopenharmony_ci	 * the mask is set to 32-bit to make sure that MSI target address is
176462306a36Sopenharmony_ci	 * always a 32-bit address
176562306a36Sopenharmony_ci	 */
176662306a36Sopenharmony_ci	err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
176762306a36Sopenharmony_ci	if (err < 0) {
176862306a36Sopenharmony_ci		dev_err(dev, "failed to set DMA coherent mask: %d\n", err);
176962306a36Sopenharmony_ci		goto free_irq;
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
177362306a36Sopenharmony_ci				    DMA_ATTR_NO_KERNEL_MAPPING);
177462306a36Sopenharmony_ci	if (!msi->virt) {
177562306a36Sopenharmony_ci		dev_err(dev, "failed to allocate DMA memory for MSI\n");
177662306a36Sopenharmony_ci		err = -ENOMEM;
177762306a36Sopenharmony_ci		goto free_irq;
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	return 0;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cifree_irq:
178362306a36Sopenharmony_ci	irq_set_chained_handler_and_data(msi->irq, NULL, NULL);
178462306a36Sopenharmony_cifree_irq_domain:
178562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI))
178662306a36Sopenharmony_ci		tegra_free_domains(msi);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	return err;
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic void tegra_pcie_enable_msi(struct tegra_pcie *pcie)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
179462306a36Sopenharmony_ci	struct tegra_msi *msi = &pcie->msi;
179562306a36Sopenharmony_ci	u32 reg, msi_state[INT_PCI_MSI_NR / 32];
179662306a36Sopenharmony_ci	int i;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	afi_writel(pcie, msi->phys >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
179962306a36Sopenharmony_ci	afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST);
180062306a36Sopenharmony_ci	/* this register is in 4K increments */
180162306a36Sopenharmony_ci	afi_writel(pcie, 1, AFI_MSI_BAR_SZ);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	/* Restore the MSI allocation state */
180462306a36Sopenharmony_ci	bitmap_to_arr32(msi_state, msi->used, INT_PCI_MSI_NR);
180562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(msi_state); i++)
180662306a36Sopenharmony_ci		afi_writel(pcie, msi_state[i], AFI_MSI_EN_VEC(i));
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* and unmask the MSI interrupt */
180962306a36Sopenharmony_ci	reg = afi_readl(pcie, AFI_INTR_MASK);
181062306a36Sopenharmony_ci	reg |= AFI_INTR_MASK_MSI_MASK;
181162306a36Sopenharmony_ci	afi_writel(pcie, reg, AFI_INTR_MASK);
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic void tegra_pcie_msi_teardown(struct tegra_pcie *pcie)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	struct tegra_msi *msi = &pcie->msi;
181762306a36Sopenharmony_ci	unsigned int i, irq;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys,
182062306a36Sopenharmony_ci		       DMA_ATTR_NO_KERNEL_MAPPING);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	for (i = 0; i < INT_PCI_MSI_NR; i++) {
182362306a36Sopenharmony_ci		irq = irq_find_mapping(msi->domain, i);
182462306a36Sopenharmony_ci		if (irq > 0)
182562306a36Sopenharmony_ci			irq_domain_free_irqs(irq, 1);
182662306a36Sopenharmony_ci	}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	irq_set_chained_handler_and_data(msi->irq, NULL, NULL);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI))
183162306a36Sopenharmony_ci		tegra_free_domains(msi);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	u32 value;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* mask the MSI interrupt */
183962306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_INTR_MASK);
184062306a36Sopenharmony_ci	value &= ~AFI_INTR_MASK_MSI_MASK;
184162306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_INTR_MASK);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	return 0;
184462306a36Sopenharmony_ci}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_cistatic void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	u32 value;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	value = afi_readl(pcie, AFI_INTR_MASK);
185162306a36Sopenharmony_ci	value &= ~AFI_INTR_MASK_INT_MASK;
185262306a36Sopenharmony_ci	afi_writel(pcie, value, AFI_INTR_MASK);
185362306a36Sopenharmony_ci}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_cistatic int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
185662306a36Sopenharmony_ci				      u32 *xbar)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	struct device *dev = pcie->dev;
185962306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
186262306a36Sopenharmony_ci		switch (lanes) {
186362306a36Sopenharmony_ci		case 0x010004:
186462306a36Sopenharmony_ci			dev_info(dev, "4x1, 1x1 configuration\n");
186562306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401;
186662306a36Sopenharmony_ci			return 0;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci		case 0x010102:
186962306a36Sopenharmony_ci			dev_info(dev, "2x1, 1X1, 1x1 configuration\n");
187062306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
187162306a36Sopenharmony_ci			return 0;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci		case 0x010101:
187462306a36Sopenharmony_ci			dev_info(dev, "1x1, 1x1, 1x1 configuration\n");
187562306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111;
187662306a36Sopenharmony_ci			return 0;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci		default:
187962306a36Sopenharmony_ci			dev_info(dev, "wrong configuration updated in DT, "
188062306a36Sopenharmony_ci				 "switching to default 2x1, 1x1, 1x1 "
188162306a36Sopenharmony_ci				 "configuration\n");
188262306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
188362306a36Sopenharmony_ci			return 0;
188462306a36Sopenharmony_ci		}
188562306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
188662306a36Sopenharmony_ci		   of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
188762306a36Sopenharmony_ci		switch (lanes) {
188862306a36Sopenharmony_ci		case 0x0000104:
188962306a36Sopenharmony_ci			dev_info(dev, "4x1, 1x1 configuration\n");
189062306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
189162306a36Sopenharmony_ci			return 0;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci		case 0x0000102:
189462306a36Sopenharmony_ci			dev_info(dev, "2x1, 1x1 configuration\n");
189562306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
189662306a36Sopenharmony_ci			return 0;
189762306a36Sopenharmony_ci		}
189862306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
189962306a36Sopenharmony_ci		switch (lanes) {
190062306a36Sopenharmony_ci		case 0x00000204:
190162306a36Sopenharmony_ci			dev_info(dev, "4x1, 2x1 configuration\n");
190262306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420;
190362306a36Sopenharmony_ci			return 0;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci		case 0x00020202:
190662306a36Sopenharmony_ci			dev_info(dev, "2x3 configuration\n");
190762306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222;
190862306a36Sopenharmony_ci			return 0;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		case 0x00010104:
191162306a36Sopenharmony_ci			dev_info(dev, "4x1, 1x2 configuration\n");
191262306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411;
191362306a36Sopenharmony_ci			return 0;
191462306a36Sopenharmony_ci		}
191562306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) {
191662306a36Sopenharmony_ci		switch (lanes) {
191762306a36Sopenharmony_ci		case 0x00000004:
191862306a36Sopenharmony_ci			dev_info(dev, "single-mode configuration\n");
191962306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE;
192062306a36Sopenharmony_ci			return 0;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci		case 0x00000202:
192362306a36Sopenharmony_ci			dev_info(dev, "dual-mode configuration\n");
192462306a36Sopenharmony_ci			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
192562306a36Sopenharmony_ci			return 0;
192662306a36Sopenharmony_ci		}
192762306a36Sopenharmony_ci	}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	return -EINVAL;
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci/*
193362306a36Sopenharmony_ci * Check whether a given set of supplies is available in a device tree node.
193462306a36Sopenharmony_ci * This is used to check whether the new or the legacy device tree bindings
193562306a36Sopenharmony_ci * should be used.
193662306a36Sopenharmony_ci */
193762306a36Sopenharmony_cistatic bool of_regulator_bulk_available(struct device_node *np,
193862306a36Sopenharmony_ci					struct regulator_bulk_data *supplies,
193962306a36Sopenharmony_ci					unsigned int num_supplies)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	char property[32];
194262306a36Sopenharmony_ci	unsigned int i;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	for (i = 0; i < num_supplies; i++) {
194562306a36Sopenharmony_ci		snprintf(property, 32, "%s-supply", supplies[i].supply);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		if (!of_property_present(np, property))
194862306a36Sopenharmony_ci			return false;
194962306a36Sopenharmony_ci	}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	return true;
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci/*
195562306a36Sopenharmony_ci * Old versions of the device tree binding for this device used a set of power
195662306a36Sopenharmony_ci * supplies that didn't match the hardware inputs. This happened to work for a
195762306a36Sopenharmony_ci * number of cases but is not future proof. However to preserve backwards-
195862306a36Sopenharmony_ci * compatibility with old device trees, this function will try to use the old
195962306a36Sopenharmony_ci * set of supplies.
196062306a36Sopenharmony_ci */
196162306a36Sopenharmony_cistatic int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct device *dev = pcie->dev;
196462306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra30-pcie"))
196762306a36Sopenharmony_ci		pcie->num_supplies = 3;
196862306a36Sopenharmony_ci	else if (of_device_is_compatible(np, "nvidia,tegra20-pcie"))
196962306a36Sopenharmony_ci		pcie->num_supplies = 2;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	if (pcie->num_supplies == 0) {
197262306a36Sopenharmony_ci		dev_err(dev, "device %pOF not supported in legacy mode\n", np);
197362306a36Sopenharmony_ci		return -ENODEV;
197462306a36Sopenharmony_ci	}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
197762306a36Sopenharmony_ci				      sizeof(*pcie->supplies),
197862306a36Sopenharmony_ci				      GFP_KERNEL);
197962306a36Sopenharmony_ci	if (!pcie->supplies)
198062306a36Sopenharmony_ci		return -ENOMEM;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	pcie->supplies[0].supply = "pex-clk";
198362306a36Sopenharmony_ci	pcie->supplies[1].supply = "vdd";
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	if (pcie->num_supplies > 2)
198662306a36Sopenharmony_ci		pcie->supplies[2].supply = "avdd";
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	return devm_regulator_bulk_get(dev, pcie->num_supplies, pcie->supplies);
198962306a36Sopenharmony_ci}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci/*
199262306a36Sopenharmony_ci * Obtains the list of regulators required for a particular generation of the
199362306a36Sopenharmony_ci * IP block.
199462306a36Sopenharmony_ci *
199562306a36Sopenharmony_ci * This would've been nice to do simply by providing static tables for use
199662306a36Sopenharmony_ci * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky
199762306a36Sopenharmony_ci * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB)
199862306a36Sopenharmony_ci * and either seems to be optional depending on which ports are being used.
199962306a36Sopenharmony_ci */
200062306a36Sopenharmony_cistatic int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	struct device *dev = pcie->dev;
200362306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
200462306a36Sopenharmony_ci	unsigned int i = 0;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
200762306a36Sopenharmony_ci		pcie->num_supplies = 4;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
201062306a36Sopenharmony_ci					      sizeof(*pcie->supplies),
201162306a36Sopenharmony_ci					      GFP_KERNEL);
201262306a36Sopenharmony_ci		if (!pcie->supplies)
201362306a36Sopenharmony_ci			return -ENOMEM;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		pcie->supplies[i++].supply = "dvdd-pex";
201662306a36Sopenharmony_ci		pcie->supplies[i++].supply = "hvdd-pex-pll";
201762306a36Sopenharmony_ci		pcie->supplies[i++].supply = "hvdd-pex";
201862306a36Sopenharmony_ci		pcie->supplies[i++].supply = "vddio-pexctl-aud";
201962306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
202062306a36Sopenharmony_ci		pcie->num_supplies = 3;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci		pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
202362306a36Sopenharmony_ci					      sizeof(*pcie->supplies),
202462306a36Sopenharmony_ci					      GFP_KERNEL);
202562306a36Sopenharmony_ci		if (!pcie->supplies)
202662306a36Sopenharmony_ci			return -ENOMEM;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci		pcie->supplies[i++].supply = "hvddio-pex";
202962306a36Sopenharmony_ci		pcie->supplies[i++].supply = "dvddio-pex";
203062306a36Sopenharmony_ci		pcie->supplies[i++].supply = "vddio-pex-ctl";
203162306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
203262306a36Sopenharmony_ci		pcie->num_supplies = 4;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
203562306a36Sopenharmony_ci					      sizeof(*pcie->supplies),
203662306a36Sopenharmony_ci					      GFP_KERNEL);
203762306a36Sopenharmony_ci		if (!pcie->supplies)
203862306a36Sopenharmony_ci			return -ENOMEM;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci		pcie->supplies[i++].supply = "avddio-pex";
204162306a36Sopenharmony_ci		pcie->supplies[i++].supply = "dvddio-pex";
204262306a36Sopenharmony_ci		pcie->supplies[i++].supply = "hvdd-pex";
204362306a36Sopenharmony_ci		pcie->supplies[i++].supply = "vddio-pex-ctl";
204462306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
204562306a36Sopenharmony_ci		bool need_pexa = false, need_pexb = false;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci		/* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */
204862306a36Sopenharmony_ci		if (lane_mask & 0x0f)
204962306a36Sopenharmony_ci			need_pexa = true;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci		/* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */
205262306a36Sopenharmony_ci		if (lane_mask & 0x30)
205362306a36Sopenharmony_ci			need_pexb = true;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		pcie->num_supplies = 4 + (need_pexa ? 2 : 0) +
205662306a36Sopenharmony_ci					 (need_pexb ? 2 : 0);
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
205962306a36Sopenharmony_ci					      sizeof(*pcie->supplies),
206062306a36Sopenharmony_ci					      GFP_KERNEL);
206162306a36Sopenharmony_ci		if (!pcie->supplies)
206262306a36Sopenharmony_ci			return -ENOMEM;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci		pcie->supplies[i++].supply = "avdd-pex-pll";
206562306a36Sopenharmony_ci		pcie->supplies[i++].supply = "hvdd-pex";
206662306a36Sopenharmony_ci		pcie->supplies[i++].supply = "vddio-pex-ctl";
206762306a36Sopenharmony_ci		pcie->supplies[i++].supply = "avdd-plle";
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci		if (need_pexa) {
207062306a36Sopenharmony_ci			pcie->supplies[i++].supply = "avdd-pexa";
207162306a36Sopenharmony_ci			pcie->supplies[i++].supply = "vdd-pexa";
207262306a36Sopenharmony_ci		}
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci		if (need_pexb) {
207562306a36Sopenharmony_ci			pcie->supplies[i++].supply = "avdd-pexb";
207662306a36Sopenharmony_ci			pcie->supplies[i++].supply = "vdd-pexb";
207762306a36Sopenharmony_ci		}
207862306a36Sopenharmony_ci	} else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) {
207962306a36Sopenharmony_ci		pcie->num_supplies = 5;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
208262306a36Sopenharmony_ci					      sizeof(*pcie->supplies),
208362306a36Sopenharmony_ci					      GFP_KERNEL);
208462306a36Sopenharmony_ci		if (!pcie->supplies)
208562306a36Sopenharmony_ci			return -ENOMEM;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		pcie->supplies[0].supply = "avdd-pex";
208862306a36Sopenharmony_ci		pcie->supplies[1].supply = "vdd-pex";
208962306a36Sopenharmony_ci		pcie->supplies[2].supply = "avdd-pex-pll";
209062306a36Sopenharmony_ci		pcie->supplies[3].supply = "avdd-plle";
209162306a36Sopenharmony_ci		pcie->supplies[4].supply = "vddio-pex-clk";
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (of_regulator_bulk_available(dev->of_node, pcie->supplies,
209562306a36Sopenharmony_ci					pcie->num_supplies))
209662306a36Sopenharmony_ci		return devm_regulator_bulk_get(dev, pcie->num_supplies,
209762306a36Sopenharmony_ci					       pcie->supplies);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	/*
210062306a36Sopenharmony_ci	 * If not all regulators are available for this new scheme, assume
210162306a36Sopenharmony_ci	 * that the device tree complies with an older version of the device
210262306a36Sopenharmony_ci	 * tree binding.
210362306a36Sopenharmony_ci	 */
210462306a36Sopenharmony_ci	dev_info(dev, "using legacy DT binding for power supplies\n");
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	devm_kfree(dev, pcie->supplies);
210762306a36Sopenharmony_ci	pcie->num_supplies = 0;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	return tegra_pcie_get_legacy_regulators(pcie);
211062306a36Sopenharmony_ci}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_cistatic int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
211362306a36Sopenharmony_ci{
211462306a36Sopenharmony_ci	struct device *dev = pcie->dev;
211562306a36Sopenharmony_ci	struct device_node *np = dev->of_node, *port;
211662306a36Sopenharmony_ci	const struct tegra_pcie_soc *soc = pcie->soc;
211762306a36Sopenharmony_ci	u32 lanes = 0, mask = 0;
211862306a36Sopenharmony_ci	unsigned int lane = 0;
211962306a36Sopenharmony_ci	int err;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	/* parse root ports */
212262306a36Sopenharmony_ci	for_each_child_of_node(np, port) {
212362306a36Sopenharmony_ci		struct tegra_pcie_port *rp;
212462306a36Sopenharmony_ci		unsigned int index;
212562306a36Sopenharmony_ci		u32 value;
212662306a36Sopenharmony_ci		char *label;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci		err = of_pci_get_devfn(port);
212962306a36Sopenharmony_ci		if (err < 0) {
213062306a36Sopenharmony_ci			dev_err(dev, "failed to parse address: %d\n", err);
213162306a36Sopenharmony_ci			goto err_node_put;
213262306a36Sopenharmony_ci		}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci		index = PCI_SLOT(err);
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci		if (index < 1 || index > soc->num_ports) {
213762306a36Sopenharmony_ci			dev_err(dev, "invalid port number: %d\n", index);
213862306a36Sopenharmony_ci			err = -EINVAL;
213962306a36Sopenharmony_ci			goto err_node_put;
214062306a36Sopenharmony_ci		}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci		index--;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		err = of_property_read_u32(port, "nvidia,num-lanes", &value);
214562306a36Sopenharmony_ci		if (err < 0) {
214662306a36Sopenharmony_ci			dev_err(dev, "failed to parse # of lanes: %d\n",
214762306a36Sopenharmony_ci				err);
214862306a36Sopenharmony_ci			goto err_node_put;
214962306a36Sopenharmony_ci		}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci		if (value > 16) {
215262306a36Sopenharmony_ci			dev_err(dev, "invalid # of lanes: %u\n", value);
215362306a36Sopenharmony_ci			err = -EINVAL;
215462306a36Sopenharmony_ci			goto err_node_put;
215562306a36Sopenharmony_ci		}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		lanes |= value << (index << 3);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci		if (!of_device_is_available(port)) {
216062306a36Sopenharmony_ci			lane += value;
216162306a36Sopenharmony_ci			continue;
216262306a36Sopenharmony_ci		}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		mask |= ((1 << value) - 1) << lane;
216562306a36Sopenharmony_ci		lane += value;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci		rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL);
216862306a36Sopenharmony_ci		if (!rp) {
216962306a36Sopenharmony_ci			err = -ENOMEM;
217062306a36Sopenharmony_ci			goto err_node_put;
217162306a36Sopenharmony_ci		}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci		err = of_address_to_resource(port, 0, &rp->regs);
217462306a36Sopenharmony_ci		if (err < 0) {
217562306a36Sopenharmony_ci			dev_err(dev, "failed to parse address: %d\n", err);
217662306a36Sopenharmony_ci			goto err_node_put;
217762306a36Sopenharmony_ci		}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci		INIT_LIST_HEAD(&rp->list);
218062306a36Sopenharmony_ci		rp->index = index;
218162306a36Sopenharmony_ci		rp->lanes = value;
218262306a36Sopenharmony_ci		rp->pcie = pcie;
218362306a36Sopenharmony_ci		rp->np = port;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci		rp->base = devm_pci_remap_cfg_resource(dev, &rp->regs);
218662306a36Sopenharmony_ci		if (IS_ERR(rp->base)) {
218762306a36Sopenharmony_ci			err = PTR_ERR(rp->base);
218862306a36Sopenharmony_ci			goto err_node_put;
218962306a36Sopenharmony_ci		}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index);
219262306a36Sopenharmony_ci		if (!label) {
219362306a36Sopenharmony_ci			err = -ENOMEM;
219462306a36Sopenharmony_ci			goto err_node_put;
219562306a36Sopenharmony_ci		}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci		/*
219862306a36Sopenharmony_ci		 * Returns -ENOENT if reset-gpios property is not populated
219962306a36Sopenharmony_ci		 * and in this case fall back to using AFI per port register
220062306a36Sopenharmony_ci		 * to toggle PERST# SFIO line.
220162306a36Sopenharmony_ci		 */
220262306a36Sopenharmony_ci		rp->reset_gpio = devm_fwnode_gpiod_get(dev,
220362306a36Sopenharmony_ci						       of_fwnode_handle(port),
220462306a36Sopenharmony_ci						       "reset",
220562306a36Sopenharmony_ci						       GPIOD_OUT_LOW,
220662306a36Sopenharmony_ci						       label);
220762306a36Sopenharmony_ci		if (IS_ERR(rp->reset_gpio)) {
220862306a36Sopenharmony_ci			if (PTR_ERR(rp->reset_gpio) == -ENOENT) {
220962306a36Sopenharmony_ci				rp->reset_gpio = NULL;
221062306a36Sopenharmony_ci			} else {
221162306a36Sopenharmony_ci				dev_err(dev, "failed to get reset GPIO: %ld\n",
221262306a36Sopenharmony_ci					PTR_ERR(rp->reset_gpio));
221362306a36Sopenharmony_ci				err = PTR_ERR(rp->reset_gpio);
221462306a36Sopenharmony_ci				goto err_node_put;
221562306a36Sopenharmony_ci			}
221662306a36Sopenharmony_ci		}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci		list_add_tail(&rp->list, &pcie->ports);
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config);
222262306a36Sopenharmony_ci	if (err < 0) {
222362306a36Sopenharmony_ci		dev_err(dev, "invalid lane configuration\n");
222462306a36Sopenharmony_ci		return err;
222562306a36Sopenharmony_ci	}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	err = tegra_pcie_get_regulators(pcie, mask);
222862306a36Sopenharmony_ci	if (err < 0)
222962306a36Sopenharmony_ci		return err;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	return 0;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_cierr_node_put:
223462306a36Sopenharmony_ci	of_node_put(port);
223562306a36Sopenharmony_ci	return err;
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci/*
223962306a36Sopenharmony_ci * FIXME: If there are no PCIe cards attached, then calling this function
224062306a36Sopenharmony_ci * can result in the increase of the bootup time as there are big timeout
224162306a36Sopenharmony_ci * loops.
224262306a36Sopenharmony_ci */
224362306a36Sopenharmony_ci#define TEGRA_PCIE_LINKUP_TIMEOUT	200	/* up to 1.2 seconds */
224462306a36Sopenharmony_cistatic bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
224562306a36Sopenharmony_ci{
224662306a36Sopenharmony_ci	struct device *dev = port->pcie->dev;
224762306a36Sopenharmony_ci	unsigned int retries = 3;
224862306a36Sopenharmony_ci	unsigned long value;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	/* override presence detection */
225162306a36Sopenharmony_ci	value = readl(port->base + RP_PRIV_MISC);
225262306a36Sopenharmony_ci	value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
225362306a36Sopenharmony_ci	value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
225462306a36Sopenharmony_ci	writel(value, port->base + RP_PRIV_MISC);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	do {
225762306a36Sopenharmony_ci		unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci		do {
226062306a36Sopenharmony_ci			value = readl(port->base + RP_VEND_XP);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci			if (value & RP_VEND_XP_DL_UP)
226362306a36Sopenharmony_ci				break;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci			usleep_range(1000, 2000);
226662306a36Sopenharmony_ci		} while (--timeout);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci		if (!timeout) {
226962306a36Sopenharmony_ci			dev_dbg(dev, "link %u down, retrying\n", port->index);
227062306a36Sopenharmony_ci			goto retry;
227162306a36Sopenharmony_ci		}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		do {
227662306a36Sopenharmony_ci			value = readl(port->base + RP_LINK_CONTROL_STATUS);
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci			if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
227962306a36Sopenharmony_ci				return true;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci			usleep_range(1000, 2000);
228262306a36Sopenharmony_ci		} while (--timeout);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ciretry:
228562306a36Sopenharmony_ci		tegra_pcie_port_reset(port);
228662306a36Sopenharmony_ci	} while (--retries);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	return false;
228962306a36Sopenharmony_ci}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_cistatic void tegra_pcie_change_link_speed(struct tegra_pcie *pcie)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	struct device *dev = pcie->dev;
229462306a36Sopenharmony_ci	struct tegra_pcie_port *port;
229562306a36Sopenharmony_ci	ktime_t deadline;
229662306a36Sopenharmony_ci	u32 value;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list) {
229962306a36Sopenharmony_ci		/*
230062306a36Sopenharmony_ci		 * "Supported Link Speeds Vector" in "Link Capabilities 2"
230162306a36Sopenharmony_ci		 * is not supported by Tegra. tegra_pcie_change_link_speed()
230262306a36Sopenharmony_ci		 * is called only for Tegra chips which support Gen2.
230362306a36Sopenharmony_ci		 * So there no harm if supported link speed is not verified.
230462306a36Sopenharmony_ci		 */
230562306a36Sopenharmony_ci		value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
230662306a36Sopenharmony_ci		value &= ~PCI_EXP_LNKSTA_CLS;
230762306a36Sopenharmony_ci		value |= PCI_EXP_LNKSTA_CLS_5_0GB;
230862306a36Sopenharmony_ci		writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci		/*
231162306a36Sopenharmony_ci		 * Poll until link comes back from recovery to avoid race
231262306a36Sopenharmony_ci		 * condition.
231362306a36Sopenharmony_ci		 */
231462306a36Sopenharmony_ci		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci		while (ktime_before(ktime_get(), deadline)) {
231762306a36Sopenharmony_ci			value = readl(port->base + RP_LINK_CONTROL_STATUS);
231862306a36Sopenharmony_ci			if ((value & PCI_EXP_LNKSTA_LT) == 0)
231962306a36Sopenharmony_ci				break;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci			usleep_range(2000, 3000);
232262306a36Sopenharmony_ci		}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci		if (value & PCI_EXP_LNKSTA_LT)
232562306a36Sopenharmony_ci			dev_warn(dev, "PCIe port %u link is in recovery\n",
232662306a36Sopenharmony_ci				 port->index);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci		/* Retrain the link */
232962306a36Sopenharmony_ci		value = readl(port->base + RP_LINK_CONTROL_STATUS);
233062306a36Sopenharmony_ci		value |= PCI_EXP_LNKCTL_RL;
233162306a36Sopenharmony_ci		writel(value, port->base + RP_LINK_CONTROL_STATUS);
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci		deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci		while (ktime_before(ktime_get(), deadline)) {
233662306a36Sopenharmony_ci			value = readl(port->base + RP_LINK_CONTROL_STATUS);
233762306a36Sopenharmony_ci			if ((value & PCI_EXP_LNKSTA_LT) == 0)
233862306a36Sopenharmony_ci				break;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci			usleep_range(2000, 3000);
234162306a36Sopenharmony_ci		}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci		if (value & PCI_EXP_LNKSTA_LT)
234462306a36Sopenharmony_ci			dev_err(dev, "failed to retrain link of port %u\n",
234562306a36Sopenharmony_ci				port->index);
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_cistatic void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
235062306a36Sopenharmony_ci{
235162306a36Sopenharmony_ci	struct device *dev = pcie->dev;
235262306a36Sopenharmony_ci	struct tegra_pcie_port *port, *tmp;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
235562306a36Sopenharmony_ci		dev_info(dev, "probing port %u, using %u lanes\n",
235662306a36Sopenharmony_ci			 port->index, port->lanes);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci		tegra_pcie_port_enable(port);
235962306a36Sopenharmony_ci	}
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	/* Start LTSSM from Tegra side */
236262306a36Sopenharmony_ci	reset_control_deassert(pcie->pcie_xrst);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
236562306a36Sopenharmony_ci		if (tegra_pcie_port_check_link(port))
236662306a36Sopenharmony_ci			continue;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci		dev_info(dev, "link %u down, ignoring\n", port->index);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci		tegra_pcie_port_disable(port);
237162306a36Sopenharmony_ci		tegra_pcie_port_free(port);
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	if (pcie->soc->has_gen2)
237562306a36Sopenharmony_ci		tegra_pcie_change_link_speed(pcie);
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_cistatic void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	struct tegra_pcie_port *port, *tmp;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	reset_control_assert(pcie->pcie_xrst);
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	list_for_each_entry_safe(port, tmp, &pcie->ports, list)
238562306a36Sopenharmony_ci		tegra_pcie_port_disable(port);
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra20_pcie_ports[] = {
238962306a36Sopenharmony_ci	{ .pme.turnoff_bit = 0, .pme.ack_bit =  5 },
239062306a36Sopenharmony_ci	{ .pme.turnoff_bit = 8, .pme.ack_bit = 10 },
239162306a36Sopenharmony_ci};
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_cistatic const struct tegra_pcie_soc tegra20_pcie = {
239462306a36Sopenharmony_ci	.num_ports = 2,
239562306a36Sopenharmony_ci	.ports = tegra20_pcie_ports,
239662306a36Sopenharmony_ci	.msi_base_shift = 0,
239762306a36Sopenharmony_ci	.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
239862306a36Sopenharmony_ci	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
239962306a36Sopenharmony_ci	.pads_refclk_cfg0 = 0xfa5cfa5c,
240062306a36Sopenharmony_ci	.has_pex_clkreq_en = false,
240162306a36Sopenharmony_ci	.has_pex_bias_ctrl = false,
240262306a36Sopenharmony_ci	.has_intr_prsnt_sense = false,
240362306a36Sopenharmony_ci	.has_cml_clk = false,
240462306a36Sopenharmony_ci	.has_gen2 = false,
240562306a36Sopenharmony_ci	.force_pca_enable = false,
240662306a36Sopenharmony_ci	.program_uphy = true,
240762306a36Sopenharmony_ci	.update_clamp_threshold = false,
240862306a36Sopenharmony_ci	.program_deskew_time = false,
240962306a36Sopenharmony_ci	.update_fc_timer = false,
241062306a36Sopenharmony_ci	.has_cache_bars = true,
241162306a36Sopenharmony_ci	.ectl.enable = false,
241262306a36Sopenharmony_ci};
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra30_pcie_ports[] = {
241562306a36Sopenharmony_ci	{ .pme.turnoff_bit =  0, .pme.ack_bit =  5 },
241662306a36Sopenharmony_ci	{ .pme.turnoff_bit =  8, .pme.ack_bit = 10 },
241762306a36Sopenharmony_ci	{ .pme.turnoff_bit = 16, .pme.ack_bit = 18 },
241862306a36Sopenharmony_ci};
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_cistatic const struct tegra_pcie_soc tegra30_pcie = {
242162306a36Sopenharmony_ci	.num_ports = 3,
242262306a36Sopenharmony_ci	.ports = tegra30_pcie_ports,
242362306a36Sopenharmony_ci	.msi_base_shift = 8,
242462306a36Sopenharmony_ci	.afi_pex2_ctrl = 0x128,
242562306a36Sopenharmony_ci	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
242662306a36Sopenharmony_ci	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
242762306a36Sopenharmony_ci	.pads_refclk_cfg0 = 0xfa5cfa5c,
242862306a36Sopenharmony_ci	.pads_refclk_cfg1 = 0xfa5cfa5c,
242962306a36Sopenharmony_ci	.has_pex_clkreq_en = true,
243062306a36Sopenharmony_ci	.has_pex_bias_ctrl = true,
243162306a36Sopenharmony_ci	.has_intr_prsnt_sense = true,
243262306a36Sopenharmony_ci	.has_cml_clk = true,
243362306a36Sopenharmony_ci	.has_gen2 = false,
243462306a36Sopenharmony_ci	.force_pca_enable = false,
243562306a36Sopenharmony_ci	.program_uphy = true,
243662306a36Sopenharmony_ci	.update_clamp_threshold = false,
243762306a36Sopenharmony_ci	.program_deskew_time = false,
243862306a36Sopenharmony_ci	.update_fc_timer = false,
243962306a36Sopenharmony_ci	.has_cache_bars = false,
244062306a36Sopenharmony_ci	.ectl.enable = false,
244162306a36Sopenharmony_ci};
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_cistatic const struct tegra_pcie_soc tegra124_pcie = {
244462306a36Sopenharmony_ci	.num_ports = 2,
244562306a36Sopenharmony_ci	.ports = tegra20_pcie_ports,
244662306a36Sopenharmony_ci	.msi_base_shift = 8,
244762306a36Sopenharmony_ci	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
244862306a36Sopenharmony_ci	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
244962306a36Sopenharmony_ci	.pads_refclk_cfg0 = 0x44ac44ac,
245062306a36Sopenharmony_ci	.has_pex_clkreq_en = true,
245162306a36Sopenharmony_ci	.has_pex_bias_ctrl = true,
245262306a36Sopenharmony_ci	.has_intr_prsnt_sense = true,
245362306a36Sopenharmony_ci	.has_cml_clk = true,
245462306a36Sopenharmony_ci	.has_gen2 = true,
245562306a36Sopenharmony_ci	.force_pca_enable = false,
245662306a36Sopenharmony_ci	.program_uphy = true,
245762306a36Sopenharmony_ci	.update_clamp_threshold = true,
245862306a36Sopenharmony_ci	.program_deskew_time = false,
245962306a36Sopenharmony_ci	.update_fc_timer = false,
246062306a36Sopenharmony_ci	.has_cache_bars = false,
246162306a36Sopenharmony_ci	.ectl.enable = false,
246262306a36Sopenharmony_ci};
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_cistatic const struct tegra_pcie_soc tegra210_pcie = {
246562306a36Sopenharmony_ci	.num_ports = 2,
246662306a36Sopenharmony_ci	.ports = tegra20_pcie_ports,
246762306a36Sopenharmony_ci	.msi_base_shift = 8,
246862306a36Sopenharmony_ci	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
246962306a36Sopenharmony_ci	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
247062306a36Sopenharmony_ci	.pads_refclk_cfg0 = 0x90b890b8,
247162306a36Sopenharmony_ci	/* FC threshold is bit[25:18] */
247262306a36Sopenharmony_ci	.update_fc_threshold = 0x01800000,
247362306a36Sopenharmony_ci	.has_pex_clkreq_en = true,
247462306a36Sopenharmony_ci	.has_pex_bias_ctrl = true,
247562306a36Sopenharmony_ci	.has_intr_prsnt_sense = true,
247662306a36Sopenharmony_ci	.has_cml_clk = true,
247762306a36Sopenharmony_ci	.has_gen2 = true,
247862306a36Sopenharmony_ci	.force_pca_enable = true,
247962306a36Sopenharmony_ci	.program_uphy = true,
248062306a36Sopenharmony_ci	.update_clamp_threshold = true,
248162306a36Sopenharmony_ci	.program_deskew_time = true,
248262306a36Sopenharmony_ci	.update_fc_timer = true,
248362306a36Sopenharmony_ci	.has_cache_bars = false,
248462306a36Sopenharmony_ci	.ectl = {
248562306a36Sopenharmony_ci		.regs = {
248662306a36Sopenharmony_ci			.rp_ectl_2_r1 = 0x0000000f,
248762306a36Sopenharmony_ci			.rp_ectl_4_r1 = 0x00000067,
248862306a36Sopenharmony_ci			.rp_ectl_5_r1 = 0x55010000,
248962306a36Sopenharmony_ci			.rp_ectl_6_r1 = 0x00000001,
249062306a36Sopenharmony_ci			.rp_ectl_2_r2 = 0x0000008f,
249162306a36Sopenharmony_ci			.rp_ectl_4_r2 = 0x000000c7,
249262306a36Sopenharmony_ci			.rp_ectl_5_r2 = 0x55010000,
249362306a36Sopenharmony_ci			.rp_ectl_6_r2 = 0x00000001,
249462306a36Sopenharmony_ci		},
249562306a36Sopenharmony_ci		.enable = true,
249662306a36Sopenharmony_ci	},
249762306a36Sopenharmony_ci};
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra186_pcie_ports[] = {
250062306a36Sopenharmony_ci	{ .pme.turnoff_bit =  0, .pme.ack_bit =  5 },
250162306a36Sopenharmony_ci	{ .pme.turnoff_bit =  8, .pme.ack_bit = 10 },
250262306a36Sopenharmony_ci	{ .pme.turnoff_bit = 12, .pme.ack_bit = 14 },
250362306a36Sopenharmony_ci};
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_cistatic const struct tegra_pcie_soc tegra186_pcie = {
250662306a36Sopenharmony_ci	.num_ports = 3,
250762306a36Sopenharmony_ci	.ports = tegra186_pcie_ports,
250862306a36Sopenharmony_ci	.msi_base_shift = 8,
250962306a36Sopenharmony_ci	.afi_pex2_ctrl = 0x19c,
251062306a36Sopenharmony_ci	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
251162306a36Sopenharmony_ci	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
251262306a36Sopenharmony_ci	.pads_refclk_cfg0 = 0x80b880b8,
251362306a36Sopenharmony_ci	.pads_refclk_cfg1 = 0x000480b8,
251462306a36Sopenharmony_ci	.has_pex_clkreq_en = true,
251562306a36Sopenharmony_ci	.has_pex_bias_ctrl = true,
251662306a36Sopenharmony_ci	.has_intr_prsnt_sense = true,
251762306a36Sopenharmony_ci	.has_cml_clk = false,
251862306a36Sopenharmony_ci	.has_gen2 = true,
251962306a36Sopenharmony_ci	.force_pca_enable = false,
252062306a36Sopenharmony_ci	.program_uphy = false,
252162306a36Sopenharmony_ci	.update_clamp_threshold = false,
252262306a36Sopenharmony_ci	.program_deskew_time = false,
252362306a36Sopenharmony_ci	.update_fc_timer = false,
252462306a36Sopenharmony_ci	.has_cache_bars = false,
252562306a36Sopenharmony_ci	.ectl.enable = false,
252662306a36Sopenharmony_ci};
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_cistatic const struct of_device_id tegra_pcie_of_match[] = {
252962306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
253062306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
253162306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
253262306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
253362306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie },
253462306a36Sopenharmony_ci	{ },
253562306a36Sopenharmony_ci};
253662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_cistatic void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	struct tegra_pcie *pcie = s->private;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (list_empty(&pcie->ports))
254362306a36Sopenharmony_ci		return NULL;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	seq_puts(s, "Index  Status\n");
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	return seq_list_start(&pcie->ports, *pos);
254862306a36Sopenharmony_ci}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_cistatic void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos)
255162306a36Sopenharmony_ci{
255262306a36Sopenharmony_ci	struct tegra_pcie *pcie = s->private;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	return seq_list_next(v, &pcie->ports, pos);
255562306a36Sopenharmony_ci}
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_cistatic void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v)
255862306a36Sopenharmony_ci{
255962306a36Sopenharmony_ci}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_cistatic int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
256262306a36Sopenharmony_ci{
256362306a36Sopenharmony_ci	bool up = false, active = false;
256462306a36Sopenharmony_ci	struct tegra_pcie_port *port;
256562306a36Sopenharmony_ci	unsigned int value;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	port = list_entry(v, struct tegra_pcie_port, list);
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	value = readl(port->base + RP_VEND_XP);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	if (value & RP_VEND_XP_DL_UP)
257262306a36Sopenharmony_ci		up = true;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	value = readl(port->base + RP_LINK_CONTROL_STATUS);
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
257762306a36Sopenharmony_ci		active = true;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	seq_printf(s, "%2u     ", port->index);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	if (up)
258262306a36Sopenharmony_ci		seq_puts(s, "up");
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (active) {
258562306a36Sopenharmony_ci		if (up)
258662306a36Sopenharmony_ci			seq_puts(s, ", ");
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci		seq_puts(s, "active");
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	seq_puts(s, "\n");
259262306a36Sopenharmony_ci	return 0;
259362306a36Sopenharmony_ci}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_cistatic const struct seq_operations tegra_pcie_ports_sops = {
259662306a36Sopenharmony_ci	.start = tegra_pcie_ports_seq_start,
259762306a36Sopenharmony_ci	.next = tegra_pcie_ports_seq_next,
259862306a36Sopenharmony_ci	.stop = tegra_pcie_ports_seq_stop,
259962306a36Sopenharmony_ci	.show = tegra_pcie_ports_seq_show,
260062306a36Sopenharmony_ci};
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports);
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_cistatic void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
260562306a36Sopenharmony_ci{
260662306a36Sopenharmony_ci	debugfs_remove_recursive(pcie->debugfs);
260762306a36Sopenharmony_ci	pcie->debugfs = NULL;
260862306a36Sopenharmony_ci}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_cistatic void tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	pcie->debugfs = debugfs_create_dir("pcie", NULL);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie,
261562306a36Sopenharmony_ci			    &tegra_pcie_ports_fops);
261662306a36Sopenharmony_ci}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_cistatic int tegra_pcie_probe(struct platform_device *pdev)
261962306a36Sopenharmony_ci{
262062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
262162306a36Sopenharmony_ci	struct pci_host_bridge *host;
262262306a36Sopenharmony_ci	struct tegra_pcie *pcie;
262362306a36Sopenharmony_ci	int err;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
262662306a36Sopenharmony_ci	if (!host)
262762306a36Sopenharmony_ci		return -ENOMEM;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	pcie = pci_host_bridge_priv(host);
263062306a36Sopenharmony_ci	host->sysdata = pcie;
263162306a36Sopenharmony_ci	platform_set_drvdata(pdev, pcie);
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	pcie->soc = of_device_get_match_data(dev);
263462306a36Sopenharmony_ci	INIT_LIST_HEAD(&pcie->ports);
263562306a36Sopenharmony_ci	pcie->dev = dev;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	err = tegra_pcie_parse_dt(pcie);
263862306a36Sopenharmony_ci	if (err < 0)
263962306a36Sopenharmony_ci		return err;
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	err = tegra_pcie_get_resources(pcie);
264262306a36Sopenharmony_ci	if (err < 0) {
264362306a36Sopenharmony_ci		dev_err(dev, "failed to request resources: %d\n", err);
264462306a36Sopenharmony_ci		return err;
264562306a36Sopenharmony_ci	}
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	err = tegra_pcie_msi_setup(pcie);
264862306a36Sopenharmony_ci	if (err < 0) {
264962306a36Sopenharmony_ci		dev_err(dev, "failed to enable MSI support: %d\n", err);
265062306a36Sopenharmony_ci		goto put_resources;
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	pm_runtime_enable(pcie->dev);
265462306a36Sopenharmony_ci	err = pm_runtime_get_sync(pcie->dev);
265562306a36Sopenharmony_ci	if (err < 0) {
265662306a36Sopenharmony_ci		dev_err(dev, "fail to enable pcie controller: %d\n", err);
265762306a36Sopenharmony_ci		goto pm_runtime_put;
265862306a36Sopenharmony_ci	}
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	host->ops = &tegra_pcie_ops;
266162306a36Sopenharmony_ci	host->map_irq = tegra_pcie_map_irq;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	err = pci_host_probe(host);
266462306a36Sopenharmony_ci	if (err < 0) {
266562306a36Sopenharmony_ci		dev_err(dev, "failed to register host: %d\n", err);
266662306a36Sopenharmony_ci		goto pm_runtime_put;
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_DEBUG_FS))
267062306a36Sopenharmony_ci		tegra_pcie_debugfs_init(pcie);
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	return 0;
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_cipm_runtime_put:
267562306a36Sopenharmony_ci	pm_runtime_put_sync(pcie->dev);
267662306a36Sopenharmony_ci	pm_runtime_disable(pcie->dev);
267762306a36Sopenharmony_ci	tegra_pcie_msi_teardown(pcie);
267862306a36Sopenharmony_ciput_resources:
267962306a36Sopenharmony_ci	tegra_pcie_put_resources(pcie);
268062306a36Sopenharmony_ci	return err;
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_cistatic void tegra_pcie_remove(struct platform_device *pdev)
268462306a36Sopenharmony_ci{
268562306a36Sopenharmony_ci	struct tegra_pcie *pcie = platform_get_drvdata(pdev);
268662306a36Sopenharmony_ci	struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
268762306a36Sopenharmony_ci	struct tegra_pcie_port *port, *tmp;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_DEBUG_FS))
269062306a36Sopenharmony_ci		tegra_pcie_debugfs_exit(pcie);
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	pci_stop_root_bus(host->bus);
269362306a36Sopenharmony_ci	pci_remove_root_bus(host->bus);
269462306a36Sopenharmony_ci	pm_runtime_put_sync(pcie->dev);
269562306a36Sopenharmony_ci	pm_runtime_disable(pcie->dev);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI))
269862306a36Sopenharmony_ci		tegra_pcie_msi_teardown(pcie);
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	tegra_pcie_put_resources(pcie);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	list_for_each_entry_safe(port, tmp, &pcie->ports, list)
270362306a36Sopenharmony_ci		tegra_pcie_port_free(port);
270462306a36Sopenharmony_ci}
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_cistatic int tegra_pcie_pm_suspend(struct device *dev)
270762306a36Sopenharmony_ci{
270862306a36Sopenharmony_ci	struct tegra_pcie *pcie = dev_get_drvdata(dev);
270962306a36Sopenharmony_ci	struct tegra_pcie_port *port;
271062306a36Sopenharmony_ci	int err;
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	list_for_each_entry(port, &pcie->ports, list)
271362306a36Sopenharmony_ci		tegra_pcie_pme_turnoff(port);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	tegra_pcie_disable_ports(pcie);
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	/*
271862306a36Sopenharmony_ci	 * AFI_INTR is unmasked in tegra_pcie_enable_controller(), mask it to
271962306a36Sopenharmony_ci	 * avoid unwanted interrupts raised by AFI after pex_rst is asserted.
272062306a36Sopenharmony_ci	 */
272162306a36Sopenharmony_ci	tegra_pcie_disable_interrupts(pcie);
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (pcie->soc->program_uphy) {
272462306a36Sopenharmony_ci		err = tegra_pcie_phy_power_off(pcie);
272562306a36Sopenharmony_ci		if (err < 0)
272662306a36Sopenharmony_ci			dev_err(dev, "failed to power off PHY(s): %d\n", err);
272762306a36Sopenharmony_ci	}
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	reset_control_assert(pcie->pex_rst);
273062306a36Sopenharmony_ci	clk_disable_unprepare(pcie->pex_clk);
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI))
273362306a36Sopenharmony_ci		tegra_pcie_disable_msi(pcie);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	pinctrl_pm_select_idle_state(dev);
273662306a36Sopenharmony_ci	tegra_pcie_power_off(pcie);
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	return 0;
273962306a36Sopenharmony_ci}
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_cistatic int tegra_pcie_pm_resume(struct device *dev)
274262306a36Sopenharmony_ci{
274362306a36Sopenharmony_ci	struct tegra_pcie *pcie = dev_get_drvdata(dev);
274462306a36Sopenharmony_ci	int err;
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	err = tegra_pcie_power_on(pcie);
274762306a36Sopenharmony_ci	if (err) {
274862306a36Sopenharmony_ci		dev_err(dev, "tegra pcie power on fail: %d\n", err);
274962306a36Sopenharmony_ci		return err;
275062306a36Sopenharmony_ci	}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	err = pinctrl_pm_select_default_state(dev);
275362306a36Sopenharmony_ci	if (err < 0) {
275462306a36Sopenharmony_ci		dev_err(dev, "failed to disable PCIe IO DPD: %d\n", err);
275562306a36Sopenharmony_ci		goto poweroff;
275662306a36Sopenharmony_ci	}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	tegra_pcie_enable_controller(pcie);
275962306a36Sopenharmony_ci	tegra_pcie_setup_translations(pcie);
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI))
276262306a36Sopenharmony_ci		tegra_pcie_enable_msi(pcie);
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	err = clk_prepare_enable(pcie->pex_clk);
276562306a36Sopenharmony_ci	if (err) {
276662306a36Sopenharmony_ci		dev_err(dev, "failed to enable PEX clock: %d\n", err);
276762306a36Sopenharmony_ci		goto pex_dpd_enable;
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	reset_control_deassert(pcie->pex_rst);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	if (pcie->soc->program_uphy) {
277362306a36Sopenharmony_ci		err = tegra_pcie_phy_power_on(pcie);
277462306a36Sopenharmony_ci		if (err < 0) {
277562306a36Sopenharmony_ci			dev_err(dev, "failed to power on PHY(s): %d\n", err);
277662306a36Sopenharmony_ci			goto disable_pex_clk;
277762306a36Sopenharmony_ci		}
277862306a36Sopenharmony_ci	}
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	tegra_pcie_apply_pad_settings(pcie);
278162306a36Sopenharmony_ci	tegra_pcie_enable_ports(pcie);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	return 0;
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_cidisable_pex_clk:
278662306a36Sopenharmony_ci	reset_control_assert(pcie->pex_rst);
278762306a36Sopenharmony_ci	clk_disable_unprepare(pcie->pex_clk);
278862306a36Sopenharmony_cipex_dpd_enable:
278962306a36Sopenharmony_ci	pinctrl_pm_select_idle_state(dev);
279062306a36Sopenharmony_cipoweroff:
279162306a36Sopenharmony_ci	tegra_pcie_power_off(pcie);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	return err;
279462306a36Sopenharmony_ci}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_cistatic const struct dev_pm_ops tegra_pcie_pm_ops = {
279762306a36Sopenharmony_ci	RUNTIME_PM_OPS(tegra_pcie_pm_suspend, tegra_pcie_pm_resume, NULL)
279862306a36Sopenharmony_ci	NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_pcie_pm_suspend, tegra_pcie_pm_resume)
279962306a36Sopenharmony_ci};
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_cistatic struct platform_driver tegra_pcie_driver = {
280262306a36Sopenharmony_ci	.driver = {
280362306a36Sopenharmony_ci		.name = "tegra-pcie",
280462306a36Sopenharmony_ci		.of_match_table = tegra_pcie_of_match,
280562306a36Sopenharmony_ci		.suppress_bind_attrs = true,
280662306a36Sopenharmony_ci		.pm = &tegra_pcie_pm_ops,
280762306a36Sopenharmony_ci	},
280862306a36Sopenharmony_ci	.probe = tegra_pcie_probe,
280962306a36Sopenharmony_ci	.remove_new = tegra_pcie_remove,
281062306a36Sopenharmony_ci};
281162306a36Sopenharmony_cimodule_platform_driver(tegra_pcie_driver);
2812