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