18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCIe host controller driver for Tegra SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010, CompuLab, Ltd. 68c2ecf20Sopenharmony_ci * Author: Mike Rapoport <mike@compulab.co.il> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Based on NVIDIA PCIe driver 98c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009, NVIDIA Corporation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Bits taken from arch/arm/mach-dove/pcie.c 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Author: Thierry Reding <treding@nvidia.com> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/export.h> 208c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 238c2ecf20Sopenharmony_ci#include <linux/irq.h> 248c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/msi.h> 298c2ecf20Sopenharmony_ci#include <linux/of_address.h> 308c2ecf20Sopenharmony_ci#include <linux/of_pci.h> 318c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 328c2ecf20Sopenharmony_ci#include <linux/pci.h> 338c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 348c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 358c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 368c2ecf20Sopenharmony_ci#include <linux/reset.h> 378c2ecf20Sopenharmony_ci#include <linux/sizes.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 408c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <soc/tegra/cpuidle.h> 438c2ecf20Sopenharmony_ci#include <soc/tegra/pmc.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include "../pci.h" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define INT_PCI_MSI_NR (8 * 32) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* register definitions */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define AFI_AXI_BAR0_SZ 0x00 528c2ecf20Sopenharmony_ci#define AFI_AXI_BAR1_SZ 0x04 538c2ecf20Sopenharmony_ci#define AFI_AXI_BAR2_SZ 0x08 548c2ecf20Sopenharmony_ci#define AFI_AXI_BAR3_SZ 0x0c 558c2ecf20Sopenharmony_ci#define AFI_AXI_BAR4_SZ 0x10 568c2ecf20Sopenharmony_ci#define AFI_AXI_BAR5_SZ 0x14 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define AFI_AXI_BAR0_START 0x18 598c2ecf20Sopenharmony_ci#define AFI_AXI_BAR1_START 0x1c 608c2ecf20Sopenharmony_ci#define AFI_AXI_BAR2_START 0x20 618c2ecf20Sopenharmony_ci#define AFI_AXI_BAR3_START 0x24 628c2ecf20Sopenharmony_ci#define AFI_AXI_BAR4_START 0x28 638c2ecf20Sopenharmony_ci#define AFI_AXI_BAR5_START 0x2c 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR0 0x30 668c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR1 0x34 678c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR2 0x38 688c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR3 0x3c 698c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR4 0x40 708c2ecf20Sopenharmony_ci#define AFI_FPCI_BAR5 0x44 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define AFI_CACHE_BAR0_SZ 0x48 738c2ecf20Sopenharmony_ci#define AFI_CACHE_BAR0_ST 0x4c 748c2ecf20Sopenharmony_ci#define AFI_CACHE_BAR1_SZ 0x50 758c2ecf20Sopenharmony_ci#define AFI_CACHE_BAR1_ST 0x54 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define AFI_MSI_BAR_SZ 0x60 788c2ecf20Sopenharmony_ci#define AFI_MSI_FPCI_BAR_ST 0x64 798c2ecf20Sopenharmony_ci#define AFI_MSI_AXI_BAR_ST 0x68 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define AFI_MSI_VEC0 0x6c 828c2ecf20Sopenharmony_ci#define AFI_MSI_VEC1 0x70 838c2ecf20Sopenharmony_ci#define AFI_MSI_VEC2 0x74 848c2ecf20Sopenharmony_ci#define AFI_MSI_VEC3 0x78 858c2ecf20Sopenharmony_ci#define AFI_MSI_VEC4 0x7c 868c2ecf20Sopenharmony_ci#define AFI_MSI_VEC5 0x80 878c2ecf20Sopenharmony_ci#define AFI_MSI_VEC6 0x84 888c2ecf20Sopenharmony_ci#define AFI_MSI_VEC7 0x88 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC0 0x8c 918c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC1 0x90 928c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC2 0x94 938c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC3 0x98 948c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC4 0x9c 958c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC5 0xa0 968c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC6 0xa4 978c2ecf20Sopenharmony_ci#define AFI_MSI_EN_VEC7 0xa8 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define AFI_CONFIGURATION 0xac 1008c2ecf20Sopenharmony_ci#define AFI_CONFIGURATION_EN_FPCI (1 << 0) 1018c2ecf20Sopenharmony_ci#define AFI_CONFIGURATION_CLKEN_OVERRIDE (1 << 31) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define AFI_FPCI_ERROR_MASKS 0xb0 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define AFI_INTR_MASK 0xb4 1068c2ecf20Sopenharmony_ci#define AFI_INTR_MASK_INT_MASK (1 << 0) 1078c2ecf20Sopenharmony_ci#define AFI_INTR_MASK_MSI_MASK (1 << 8) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define AFI_INTR_CODE 0xb8 1108c2ecf20Sopenharmony_ci#define AFI_INTR_CODE_MASK 0xf 1118c2ecf20Sopenharmony_ci#define AFI_INTR_INI_SLAVE_ERROR 1 1128c2ecf20Sopenharmony_ci#define AFI_INTR_INI_DECODE_ERROR 2 1138c2ecf20Sopenharmony_ci#define AFI_INTR_TARGET_ABORT 3 1148c2ecf20Sopenharmony_ci#define AFI_INTR_MASTER_ABORT 4 1158c2ecf20Sopenharmony_ci#define AFI_INTR_INVALID_WRITE 5 1168c2ecf20Sopenharmony_ci#define AFI_INTR_LEGACY 6 1178c2ecf20Sopenharmony_ci#define AFI_INTR_FPCI_DECODE_ERROR 7 1188c2ecf20Sopenharmony_ci#define AFI_INTR_AXI_DECODE_ERROR 8 1198c2ecf20Sopenharmony_ci#define AFI_INTR_FPCI_TIMEOUT 9 1208c2ecf20Sopenharmony_ci#define AFI_INTR_PE_PRSNT_SENSE 10 1218c2ecf20Sopenharmony_ci#define AFI_INTR_PE_CLKREQ_SENSE 11 1228c2ecf20Sopenharmony_ci#define AFI_INTR_CLKCLAMP_SENSE 12 1238c2ecf20Sopenharmony_ci#define AFI_INTR_RDY4PD_SENSE 13 1248c2ecf20Sopenharmony_ci#define AFI_INTR_P2P_ERROR 14 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define AFI_INTR_SIGNATURE 0xbc 1278c2ecf20Sopenharmony_ci#define AFI_UPPER_FPCI_ADDRESS 0xc0 1288c2ecf20Sopenharmony_ci#define AFI_SM_INTR_ENABLE 0xc4 1298c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTA_ASSERT (1 << 0) 1308c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTB_ASSERT (1 << 1) 1318c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTC_ASSERT (1 << 2) 1328c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTD_ASSERT (1 << 3) 1338c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTA_DEASSERT (1 << 4) 1348c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTB_DEASSERT (1 << 5) 1358c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTC_DEASSERT (1 << 6) 1368c2ecf20Sopenharmony_ci#define AFI_SM_INTR_INTD_DEASSERT (1 << 7) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define AFI_AFI_INTR_ENABLE 0xc8 1398c2ecf20Sopenharmony_ci#define AFI_INTR_EN_INI_SLVERR (1 << 0) 1408c2ecf20Sopenharmony_ci#define AFI_INTR_EN_INI_DECERR (1 << 1) 1418c2ecf20Sopenharmony_ci#define AFI_INTR_EN_TGT_SLVERR (1 << 2) 1428c2ecf20Sopenharmony_ci#define AFI_INTR_EN_TGT_DECERR (1 << 3) 1438c2ecf20Sopenharmony_ci#define AFI_INTR_EN_TGT_WRERR (1 << 4) 1448c2ecf20Sopenharmony_ci#define AFI_INTR_EN_DFPCI_DECERR (1 << 5) 1458c2ecf20Sopenharmony_ci#define AFI_INTR_EN_AXI_DECERR (1 << 6) 1468c2ecf20Sopenharmony_ci#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7) 1478c2ecf20Sopenharmony_ci#define AFI_INTR_EN_PRSNT_SENSE (1 << 8) 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define AFI_PCIE_PME 0xf0 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG 0x0f8 1528c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1)) 1538c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0xe 1548c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) 1558c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) 1568c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) 1578c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20) 1588c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401 (0x0 << 20) 1598c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) 1608c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) 1618c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) 1628c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20) 1638c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) 1648c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20) 1658c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(x) (1 << ((x) + 29)) 1668c2ecf20Sopenharmony_ci#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL (0x7 << 29) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define AFI_FUSE 0x104 1698c2ecf20Sopenharmony_ci#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define AFI_PEX0_CTRL 0x110 1728c2ecf20Sopenharmony_ci#define AFI_PEX1_CTRL 0x118 1738c2ecf20Sopenharmony_ci#define AFI_PEX_CTRL_RST (1 << 0) 1748c2ecf20Sopenharmony_ci#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) 1758c2ecf20Sopenharmony_ci#define AFI_PEX_CTRL_REFCLK_EN (1 << 3) 1768c2ecf20Sopenharmony_ci#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4) 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define AFI_PLLE_CONTROL 0x160 1798c2ecf20Sopenharmony_ci#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9) 1808c2ecf20Sopenharmony_ci#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define AFI_PEXBIAS_CTRL_0 0x168 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define RP_ECTL_2_R1 0x00000e84 1858c2ecf20Sopenharmony_ci#define RP_ECTL_2_R1_RX_CTLE_1C_MASK 0xffff 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#define RP_ECTL_4_R1 0x00000e8c 1888c2ecf20Sopenharmony_ci#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK (0xffff << 16) 1898c2ecf20Sopenharmony_ci#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT 16 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define RP_ECTL_5_R1 0x00000e90 1928c2ecf20Sopenharmony_ci#define RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK 0xffffffff 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define RP_ECTL_6_R1 0x00000e94 1958c2ecf20Sopenharmony_ci#define RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK 0xffffffff 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define RP_ECTL_2_R2 0x00000ea4 1988c2ecf20Sopenharmony_ci#define RP_ECTL_2_R2_RX_CTLE_1C_MASK 0xffff 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define RP_ECTL_4_R2 0x00000eac 2018c2ecf20Sopenharmony_ci#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK (0xffff << 16) 2028c2ecf20Sopenharmony_ci#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT 16 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define RP_ECTL_5_R2 0x00000eb0 2058c2ecf20Sopenharmony_ci#define RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK 0xffffffff 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define RP_ECTL_6_R2 0x00000eb4 2088c2ecf20Sopenharmony_ci#define RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK 0xffffffff 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#define RP_VEND_XP 0x00000f00 2118c2ecf20Sopenharmony_ci#define RP_VEND_XP_DL_UP (1 << 30) 2128c2ecf20Sopenharmony_ci#define RP_VEND_XP_OPPORTUNISTIC_ACK (1 << 27) 2138c2ecf20Sopenharmony_ci#define RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28) 2148c2ecf20Sopenharmony_ci#define RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK (0xff << 18) 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#define RP_VEND_CTL0 0x00000f44 2178c2ecf20Sopenharmony_ci#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12) 2188c2ecf20Sopenharmony_ci#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH (0x9 << 12) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#define RP_VEND_CTL1 0x00000f48 2218c2ecf20Sopenharmony_ci#define RP_VEND_CTL1_ERPT (1 << 13) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci#define RP_VEND_XP_BIST 0x00000f4c 2248c2ecf20Sopenharmony_ci#define RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE (1 << 28) 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define RP_VEND_CTL2 0x00000fa8 2278c2ecf20Sopenharmony_ci#define RP_VEND_CTL2_PCA_ENABLE (1 << 7) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define RP_PRIV_MISC 0x00000fe0 2308c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0) 2318c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0) 2328c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK (0x7f << 16) 2338c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD (0xf << 16) 2348c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE (1 << 23) 2358c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK (0x7f << 24) 2368c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xf << 24) 2378c2ecf20Sopenharmony_ci#define RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE (1 << 31) 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#define RP_LINK_CONTROL_STATUS 0x00000090 2408c2ecf20Sopenharmony_ci#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 2418c2ecf20Sopenharmony_ci#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci#define RP_LINK_CONTROL_STATUS_2 0x000000b0 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#define PADS_CTL_SEL 0x0000009c 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define PADS_CTL 0x000000a0 2488c2ecf20Sopenharmony_ci#define PADS_CTL_IDDQ_1L (1 << 0) 2498c2ecf20Sopenharmony_ci#define PADS_CTL_TX_DATA_EN_1L (1 << 6) 2508c2ecf20Sopenharmony_ci#define PADS_CTL_RX_DATA_EN_1L (1 << 10) 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TEGRA20 0x000000b8 2538c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TEGRA30 0x000000b4 2548c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_RST_B4SM (1 << 1) 2558c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_LOCKDET (1 << 8) 2568c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_REFCLK_MASK (0x3 << 16) 2578c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_REFCLK_INTERNAL_CML (0 << 16) 2588c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_REFCLK_INTERNAL_CMOS (1 << 16) 2598c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_REFCLK_EXTERNAL (2 << 16) 2608c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TXCLKREF_MASK (0x1 << 20) 2618c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TXCLKREF_DIV10 (0 << 20) 2628c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TXCLKREF_DIV5 (1 << 20) 2638c2ecf20Sopenharmony_ci#define PADS_PLL_CTL_TXCLKREF_BUF_EN (1 << 22) 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG0 0x000000c8 2668c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG1 0x000000cc 2678c2ecf20Sopenharmony_ci#define PADS_REFCLK_BIAS 0x000000d0 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* 2708c2ecf20Sopenharmony_ci * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit 2718c2ecf20Sopenharmony_ci * entries, one entry per PCIe port. These field definitions and desired 2728c2ecf20Sopenharmony_ci * values aren't in the TRM, but do come from NVIDIA. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG_TERM_SHIFT 2 /* 6:2 */ 2758c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG_E_TERM_SHIFT 7 2768c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG_PREDI_SHIFT 8 /* 11:8 */ 2778c2ecf20Sopenharmony_ci#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */ 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#define PME_ACK_TIMEOUT 10000 2808c2ecf20Sopenharmony_ci#define LINK_RETRAIN_TIMEOUT 100000 /* in usec */ 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistruct tegra_msi { 2838c2ecf20Sopenharmony_ci struct msi_controller chip; 2848c2ecf20Sopenharmony_ci DECLARE_BITMAP(used, INT_PCI_MSI_NR); 2858c2ecf20Sopenharmony_ci struct irq_domain *domain; 2868c2ecf20Sopenharmony_ci struct mutex lock; 2878c2ecf20Sopenharmony_ci void *virt; 2888c2ecf20Sopenharmony_ci dma_addr_t phys; 2898c2ecf20Sopenharmony_ci int irq; 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* used to differentiate between Tegra SoC generations */ 2938c2ecf20Sopenharmony_cistruct tegra_pcie_port_soc { 2948c2ecf20Sopenharmony_ci struct { 2958c2ecf20Sopenharmony_ci u8 turnoff_bit; 2968c2ecf20Sopenharmony_ci u8 ack_bit; 2978c2ecf20Sopenharmony_ci } pme; 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistruct tegra_pcie_soc { 3018c2ecf20Sopenharmony_ci unsigned int num_ports; 3028c2ecf20Sopenharmony_ci const struct tegra_pcie_port_soc *ports; 3038c2ecf20Sopenharmony_ci unsigned int msi_base_shift; 3048c2ecf20Sopenharmony_ci unsigned long afi_pex2_ctrl; 3058c2ecf20Sopenharmony_ci u32 pads_pll_ctl; 3068c2ecf20Sopenharmony_ci u32 tx_ref_sel; 3078c2ecf20Sopenharmony_ci u32 pads_refclk_cfg0; 3088c2ecf20Sopenharmony_ci u32 pads_refclk_cfg1; 3098c2ecf20Sopenharmony_ci u32 update_fc_threshold; 3108c2ecf20Sopenharmony_ci bool has_pex_clkreq_en; 3118c2ecf20Sopenharmony_ci bool has_pex_bias_ctrl; 3128c2ecf20Sopenharmony_ci bool has_intr_prsnt_sense; 3138c2ecf20Sopenharmony_ci bool has_cml_clk; 3148c2ecf20Sopenharmony_ci bool has_gen2; 3158c2ecf20Sopenharmony_ci bool force_pca_enable; 3168c2ecf20Sopenharmony_ci bool program_uphy; 3178c2ecf20Sopenharmony_ci bool update_clamp_threshold; 3188c2ecf20Sopenharmony_ci bool program_deskew_time; 3198c2ecf20Sopenharmony_ci bool update_fc_timer; 3208c2ecf20Sopenharmony_ci bool has_cache_bars; 3218c2ecf20Sopenharmony_ci struct { 3228c2ecf20Sopenharmony_ci struct { 3238c2ecf20Sopenharmony_ci u32 rp_ectl_2_r1; 3248c2ecf20Sopenharmony_ci u32 rp_ectl_4_r1; 3258c2ecf20Sopenharmony_ci u32 rp_ectl_5_r1; 3268c2ecf20Sopenharmony_ci u32 rp_ectl_6_r1; 3278c2ecf20Sopenharmony_ci u32 rp_ectl_2_r2; 3288c2ecf20Sopenharmony_ci u32 rp_ectl_4_r2; 3298c2ecf20Sopenharmony_ci u32 rp_ectl_5_r2; 3308c2ecf20Sopenharmony_ci u32 rp_ectl_6_r2; 3318c2ecf20Sopenharmony_ci } regs; 3328c2ecf20Sopenharmony_ci bool enable; 3338c2ecf20Sopenharmony_ci } ectl; 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci return container_of(chip, struct tegra_msi, chip); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistruct tegra_pcie { 3428c2ecf20Sopenharmony_ci struct device *dev; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci void __iomem *pads; 3458c2ecf20Sopenharmony_ci void __iomem *afi; 3468c2ecf20Sopenharmony_ci void __iomem *cfg; 3478c2ecf20Sopenharmony_ci int irq; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci struct resource cs; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci struct clk *pex_clk; 3528c2ecf20Sopenharmony_ci struct clk *afi_clk; 3538c2ecf20Sopenharmony_ci struct clk *pll_e; 3548c2ecf20Sopenharmony_ci struct clk *cml_clk; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci struct reset_control *pex_rst; 3578c2ecf20Sopenharmony_ci struct reset_control *afi_rst; 3588c2ecf20Sopenharmony_ci struct reset_control *pcie_xrst; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci bool legacy_phy; 3618c2ecf20Sopenharmony_ci struct phy *phy; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci struct tegra_msi msi; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci struct list_head ports; 3668c2ecf20Sopenharmony_ci u32 xbar_config; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci struct regulator_bulk_data *supplies; 3698c2ecf20Sopenharmony_ci unsigned int num_supplies; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc; 3728c2ecf20Sopenharmony_ci struct dentry *debugfs; 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistruct tegra_pcie_port { 3768c2ecf20Sopenharmony_ci struct tegra_pcie *pcie; 3778c2ecf20Sopenharmony_ci struct device_node *np; 3788c2ecf20Sopenharmony_ci struct list_head list; 3798c2ecf20Sopenharmony_ci struct resource regs; 3808c2ecf20Sopenharmony_ci void __iomem *base; 3818c2ecf20Sopenharmony_ci unsigned int index; 3828c2ecf20Sopenharmony_ci unsigned int lanes; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci struct phy **phys; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistruct tegra_pcie_bus { 3908c2ecf20Sopenharmony_ci struct list_head list; 3918c2ecf20Sopenharmony_ci unsigned int nr; 3928c2ecf20Sopenharmony_ci}; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic inline void afi_writel(struct tegra_pcie *pcie, u32 value, 3958c2ecf20Sopenharmony_ci unsigned long offset) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci writel(value, pcie->afi + offset); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic inline u32 afi_readl(struct tegra_pcie *pcie, unsigned long offset) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci return readl(pcie->afi + offset); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic inline void pads_writel(struct tegra_pcie *pcie, u32 value, 4068c2ecf20Sopenharmony_ci unsigned long offset) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci writel(value, pcie->pads + offset); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return readl(pcie->pads + offset); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* 4178c2ecf20Sopenharmony_ci * The configuration space mapping on Tegra is somewhat similar to the ECAM 4188c2ecf20Sopenharmony_ci * defined by PCIe. However it deviates a bit in how the 4 bits for extended 4198c2ecf20Sopenharmony_ci * register accesses are mapped: 4208c2ecf20Sopenharmony_ci * 4218c2ecf20Sopenharmony_ci * [27:24] extended register number 4228c2ecf20Sopenharmony_ci * [23:16] bus number 4238c2ecf20Sopenharmony_ci * [15:11] device number 4248c2ecf20Sopenharmony_ci * [10: 8] function number 4258c2ecf20Sopenharmony_ci * [ 7: 0] register number 4268c2ecf20Sopenharmony_ci * 4278c2ecf20Sopenharmony_ci * Mapping the whole extended configuration space would require 256 MiB of 4288c2ecf20Sopenharmony_ci * virtual address space, only a small part of which will actually be used. 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * To work around this, a 4 KiB region is used to generate the required 4318c2ecf20Sopenharmony_ci * configuration transaction with relevant B:D:F and register offset values. 4328c2ecf20Sopenharmony_ci * This is achieved by dynamically programming base address and size of 4338c2ecf20Sopenharmony_ci * AFI_AXI_BAR used for end point config space mapping to make sure that the 4348c2ecf20Sopenharmony_ci * address (access to which generates correct config transaction) falls in 4358c2ecf20Sopenharmony_ci * this 4 KiB region. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_cistatic unsigned int tegra_pcie_conf_offset(u8 bus, unsigned int devfn, 4388c2ecf20Sopenharmony_ci unsigned int where) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) | 4418c2ecf20Sopenharmony_ci (PCI_FUNC(devfn) << 8) | (where & 0xff); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, 4458c2ecf20Sopenharmony_ci unsigned int devfn, 4468c2ecf20Sopenharmony_ci int where) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = bus->sysdata; 4498c2ecf20Sopenharmony_ci void __iomem *addr = NULL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (bus->number == 0) { 4528c2ecf20Sopenharmony_ci unsigned int slot = PCI_SLOT(devfn); 4538c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 4568c2ecf20Sopenharmony_ci if (port->index + 1 == slot) { 4578c2ecf20Sopenharmony_ci addr = port->base + (where & ~3); 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci unsigned int offset; 4638c2ecf20Sopenharmony_ci u32 base; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci offset = tegra_pcie_conf_offset(bus->number, devfn, where); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* move 4 KiB window to offset within the FPCI region */ 4688c2ecf20Sopenharmony_ci base = 0xfe100000 + ((offset & ~(SZ_4K - 1)) >> 8); 4698c2ecf20Sopenharmony_ci afi_writel(pcie, base, AFI_FPCI_BAR0); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* move to correct offset within the 4 KiB page */ 4728c2ecf20Sopenharmony_ci addr = pcie->cfg + (offset & (SZ_4K - 1)); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return addr; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn, 4798c2ecf20Sopenharmony_ci int where, int size, u32 *value) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci if (bus->number == 0) 4828c2ecf20Sopenharmony_ci return pci_generic_config_read32(bus, devfn, where, size, 4838c2ecf20Sopenharmony_ci value); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return pci_generic_config_read(bus, devfn, where, size, value); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn, 4898c2ecf20Sopenharmony_ci int where, int size, u32 value) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci if (bus->number == 0) 4928c2ecf20Sopenharmony_ci return pci_generic_config_write32(bus, devfn, where, size, 4938c2ecf20Sopenharmony_ci value); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return pci_generic_config_write(bus, devfn, where, size, value); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic struct pci_ops tegra_pcie_ops = { 4998c2ecf20Sopenharmony_ci .map_bus = tegra_pcie_map_bus, 5008c2ecf20Sopenharmony_ci .read = tegra_pcie_config_read, 5018c2ecf20Sopenharmony_ci .write = tegra_pcie_config_write, 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 5078c2ecf20Sopenharmony_ci unsigned long ret = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci switch (port->index) { 5108c2ecf20Sopenharmony_ci case 0: 5118c2ecf20Sopenharmony_ci ret = AFI_PEX0_CTRL; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci case 1: 5158c2ecf20Sopenharmony_ci ret = AFI_PEX1_CTRL; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci case 2: 5198c2ecf20Sopenharmony_ci ret = soc->afi_pex2_ctrl; 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void tegra_pcie_port_reset(struct tegra_pcie_port *port) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); 5298c2ecf20Sopenharmony_ci unsigned long value; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* pulse reset signal */ 5328c2ecf20Sopenharmony_ci if (port->reset_gpio) { 5338c2ecf20Sopenharmony_ci gpiod_set_value(port->reset_gpio, 1); 5348c2ecf20Sopenharmony_ci } else { 5358c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, ctrl); 5368c2ecf20Sopenharmony_ci value &= ~AFI_PEX_CTRL_RST; 5378c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, ctrl); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (port->reset_gpio) { 5438c2ecf20Sopenharmony_ci gpiod_set_value(port->reset_gpio, 0); 5448c2ecf20Sopenharmony_ci } else { 5458c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, ctrl); 5468c2ecf20Sopenharmony_ci value |= AFI_PEX_CTRL_RST; 5478c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, ctrl); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 5548c2ecf20Sopenharmony_ci u32 value; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Enable AER capability */ 5578c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_CTL1); 5588c2ecf20Sopenharmony_ci value |= RP_VEND_CTL1_ERPT; 5598c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_CTL1); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Optimal settings to enhance bandwidth */ 5628c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_XP); 5638c2ecf20Sopenharmony_ci value |= RP_VEND_XP_OPPORTUNISTIC_ACK; 5648c2ecf20Sopenharmony_ci value |= RP_VEND_XP_OPPORTUNISTIC_UPDATEFC; 5658c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_XP); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * LTSSM will wait for DLLP to finish before entering L1 or L2, 5698c2ecf20Sopenharmony_ci * to avoid truncation of PM messages which results in receiver errors 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_XP_BIST); 5728c2ecf20Sopenharmony_ci value |= RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE; 5738c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_XP_BIST); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci value = readl(port->base + RP_PRIV_MISC); 5768c2ecf20Sopenharmony_ci value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE; 5778c2ecf20Sopenharmony_ci value |= RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (soc->update_clamp_threshold) { 5808c2ecf20Sopenharmony_ci value &= ~(RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK | 5818c2ecf20Sopenharmony_ci RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK); 5828c2ecf20Sopenharmony_ci value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD | 5838c2ecf20Sopenharmony_ci RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci writel(value, port->base + RP_PRIV_MISC); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 5928c2ecf20Sopenharmony_ci u32 value; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_2_R1); 5958c2ecf20Sopenharmony_ci value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK; 5968c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_2_r1; 5978c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_2_R1); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_4_R1); 6008c2ecf20Sopenharmony_ci value &= ~RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK; 6018c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_4_r1 << 6028c2ecf20Sopenharmony_ci RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT; 6038c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_4_R1); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_5_R1); 6068c2ecf20Sopenharmony_ci value &= ~RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK; 6078c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_5_r1; 6088c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_5_R1); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_6_R1); 6118c2ecf20Sopenharmony_ci value &= ~RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK; 6128c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_6_r1; 6138c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_6_R1); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_2_R2); 6168c2ecf20Sopenharmony_ci value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK; 6178c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_2_r2; 6188c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_2_R2); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_4_R2); 6218c2ecf20Sopenharmony_ci value &= ~RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK; 6228c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_4_r2 << 6238c2ecf20Sopenharmony_ci RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT; 6248c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_4_R2); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_5_R2); 6278c2ecf20Sopenharmony_ci value &= ~RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK; 6288c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_5_r2; 6298c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_5_R2); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci value = readl(port->base + RP_ECTL_6_R2); 6328c2ecf20Sopenharmony_ci value &= ~RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK; 6338c2ecf20Sopenharmony_ci value |= soc->ectl.regs.rp_ectl_6_r2; 6348c2ecf20Sopenharmony_ci writel(value, port->base + RP_ECTL_6_R2); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 6408c2ecf20Sopenharmony_ci u32 value; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* 6438c2ecf20Sopenharmony_ci * Sometimes link speed change from Gen2 to Gen1 fails due to 6448c2ecf20Sopenharmony_ci * instability in deskew logic on lane-0. Increase the deskew 6458c2ecf20Sopenharmony_ci * retry time to resolve this issue. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci if (soc->program_deskew_time) { 6488c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_CTL0); 6498c2ecf20Sopenharmony_ci value &= ~RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK; 6508c2ecf20Sopenharmony_ci value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH; 6518c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_CTL0); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (soc->update_fc_timer) { 6558c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_XP); 6568c2ecf20Sopenharmony_ci value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK; 6578c2ecf20Sopenharmony_ci value |= soc->update_fc_threshold; 6588c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_XP); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * PCIe link doesn't come up with few legacy PCIe endpoints if 6638c2ecf20Sopenharmony_ci * root port advertises both Gen-1 and Gen-2 speeds in Tegra. 6648c2ecf20Sopenharmony_ci * Hence, the strategy followed here is to initially advertise 6658c2ecf20Sopenharmony_ci * only Gen-1 and after link is up, retrain link to Gen-2 speed 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS_2); 6688c2ecf20Sopenharmony_ci value &= ~PCI_EXP_LNKSTA_CLS; 6698c2ecf20Sopenharmony_ci value |= PCI_EXP_LNKSTA_CLS_2_5GB; 6708c2ecf20Sopenharmony_ci writel(value, port->base + RP_LINK_CONTROL_STATUS_2); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void tegra_pcie_port_enable(struct tegra_pcie_port *port) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); 6768c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 6778c2ecf20Sopenharmony_ci unsigned long value; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* enable reference clock */ 6808c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, ctrl); 6818c2ecf20Sopenharmony_ci value |= AFI_PEX_CTRL_REFCLK_EN; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (soc->has_pex_clkreq_en) 6848c2ecf20Sopenharmony_ci value |= AFI_PEX_CTRL_CLKREQ_EN; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci value |= AFI_PEX_CTRL_OVERRIDE_EN; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, ctrl); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci tegra_pcie_port_reset(port); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (soc->force_pca_enable) { 6938c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_CTL2); 6948c2ecf20Sopenharmony_ci value |= RP_VEND_CTL2_PCA_ENABLE; 6958c2ecf20Sopenharmony_ci writel(value, port->base + RP_VEND_CTL2); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci tegra_pcie_enable_rp_features(port); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (soc->ectl.enable) 7018c2ecf20Sopenharmony_ci tegra_pcie_program_ectl_settings(port); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci tegra_pcie_apply_sw_fixup(port); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic void tegra_pcie_port_disable(struct tegra_pcie_port *port) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); 7098c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = port->pcie->soc; 7108c2ecf20Sopenharmony_ci unsigned long value; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* assert port reset */ 7138c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, ctrl); 7148c2ecf20Sopenharmony_ci value &= ~AFI_PEX_CTRL_RST; 7158c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, ctrl); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* disable reference clock */ 7188c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, ctrl); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (soc->has_pex_clkreq_en) 7218c2ecf20Sopenharmony_ci value &= ~AFI_PEX_CTRL_CLKREQ_EN; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci value &= ~AFI_PEX_CTRL_REFCLK_EN; 7248c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, ctrl); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* disable PCIe port and set CLKREQ# as GPIO to allow PLLE power down */ 7278c2ecf20Sopenharmony_ci value = afi_readl(port->pcie, AFI_PCIE_CONFIG); 7288c2ecf20Sopenharmony_ci value |= AFI_PCIE_CONFIG_PCIE_DISABLE(port->index); 7298c2ecf20Sopenharmony_ci value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index); 7308c2ecf20Sopenharmony_ci afi_writel(port->pcie, value, AFI_PCIE_CONFIG); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void tegra_pcie_port_free(struct tegra_pcie_port *port) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = port->pcie; 7368c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci devm_iounmap(dev, port->base); 7398c2ecf20Sopenharmony_ci devm_release_mem_region(dev, port->regs.start, 7408c2ecf20Sopenharmony_ci resource_size(&port->regs)); 7418c2ecf20Sopenharmony_ci list_del(&port->list); 7428c2ecf20Sopenharmony_ci devm_kfree(dev, port); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci/* Tegra PCIE root complex wrongly reports device class */ 7468c2ecf20Sopenharmony_cistatic void tegra_pcie_fixup_class(struct pci_dev *dev) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci dev->class = PCI_CLASS_BRIDGE_PCI << 8; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class); 7518c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class); 7528c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class); 7538c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/* Tegra20 and Tegra30 PCIE requires relaxed ordering */ 7568c2ecf20Sopenharmony_cistatic void tegra_pcie_relax_enable(struct pci_dev *dev) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable); 7618c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable); 7628c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable); 7638c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = pdev->bus->sysdata; 7688c2ecf20Sopenharmony_ci int irq; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci tegra_cpuidle_pcie_irqs_in_use(); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci irq = of_irq_parse_and_map_pci(pdev, slot, pin); 7738c2ecf20Sopenharmony_ci if (!irq) 7748c2ecf20Sopenharmony_ci irq = pcie->irq; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return irq; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic irqreturn_t tegra_pcie_isr(int irq, void *arg) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci const char *err_msg[] = { 7828c2ecf20Sopenharmony_ci "Unknown", 7838c2ecf20Sopenharmony_ci "AXI slave error", 7848c2ecf20Sopenharmony_ci "AXI decode error", 7858c2ecf20Sopenharmony_ci "Target abort", 7868c2ecf20Sopenharmony_ci "Master abort", 7878c2ecf20Sopenharmony_ci "Invalid write", 7888c2ecf20Sopenharmony_ci "Legacy interrupt", 7898c2ecf20Sopenharmony_ci "Response decoding error", 7908c2ecf20Sopenharmony_ci "AXI response decoding error", 7918c2ecf20Sopenharmony_ci "Transaction timeout", 7928c2ecf20Sopenharmony_ci "Slot present pin change", 7938c2ecf20Sopenharmony_ci "Slot clock request change", 7948c2ecf20Sopenharmony_ci "TMS clock ramp change", 7958c2ecf20Sopenharmony_ci "TMS ready for power down", 7968c2ecf20Sopenharmony_ci "Peer2Peer error", 7978c2ecf20Sopenharmony_ci }; 7988c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = arg; 7998c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 8008c2ecf20Sopenharmony_ci u32 code, signature; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK; 8038c2ecf20Sopenharmony_ci signature = afi_readl(pcie, AFI_INTR_SIGNATURE); 8048c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_INTR_CODE); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (code == AFI_INTR_LEGACY) 8078c2ecf20Sopenharmony_ci return IRQ_NONE; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (code >= ARRAY_SIZE(err_msg)) 8108c2ecf20Sopenharmony_ci code = 0; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* 8138c2ecf20Sopenharmony_ci * do not pollute kernel log with master abort reports since they 8148c2ecf20Sopenharmony_ci * happen a lot during enumeration 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci if (code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_PE_PRSNT_SENSE) 8178c2ecf20Sopenharmony_ci dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature); 8188c2ecf20Sopenharmony_ci else 8198c2ecf20Sopenharmony_ci dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (code == AFI_INTR_TARGET_ABORT || code == AFI_INTR_MASTER_ABORT || 8228c2ecf20Sopenharmony_ci code == AFI_INTR_FPCI_DECODE_ERROR) { 8238c2ecf20Sopenharmony_ci u32 fpci = afi_readl(pcie, AFI_UPPER_FPCI_ADDRESS) & 0xff; 8248c2ecf20Sopenharmony_ci u64 address = (u64)fpci << 32 | (signature & 0xfffffffc); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (code == AFI_INTR_MASTER_ABORT) 8278c2ecf20Sopenharmony_ci dev_dbg(dev, " FPCI address: %10llx\n", address); 8288c2ecf20Sopenharmony_ci else 8298c2ecf20Sopenharmony_ci dev_err(dev, " FPCI address: %10llx\n", address); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/* 8368c2ecf20Sopenharmony_ci * FPCI map is as follows: 8378c2ecf20Sopenharmony_ci * - 0xfdfc000000: I/O space 8388c2ecf20Sopenharmony_ci * - 0xfdfe000000: type 0 configuration space 8398c2ecf20Sopenharmony_ci * - 0xfdff000000: type 1 configuration space 8408c2ecf20Sopenharmony_ci * - 0xfe00000000: type 0 extended configuration space 8418c2ecf20Sopenharmony_ci * - 0xfe10000000: type 1 extended configuration space 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_cistatic void tegra_pcie_setup_translations(struct tegra_pcie *pcie) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci u32 size; 8468c2ecf20Sopenharmony_ci struct resource_entry *entry; 8478c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* Bar 0: type 1 extended configuration space */ 8508c2ecf20Sopenharmony_ci size = resource_size(&pcie->cs); 8518c2ecf20Sopenharmony_ci afi_writel(pcie, pcie->cs.start, AFI_AXI_BAR0_START); 8528c2ecf20Sopenharmony_ci afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci resource_list_for_each_entry(entry, &bridge->windows) { 8558c2ecf20Sopenharmony_ci u32 fpci_bar, axi_address; 8568c2ecf20Sopenharmony_ci struct resource *res = entry->res; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci size = resource_size(res); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci switch (resource_type(res)) { 8618c2ecf20Sopenharmony_ci case IORESOURCE_IO: 8628c2ecf20Sopenharmony_ci /* Bar 1: downstream IO bar */ 8638c2ecf20Sopenharmony_ci fpci_bar = 0xfdfc0000; 8648c2ecf20Sopenharmony_ci axi_address = pci_pio_to_address(res->start); 8658c2ecf20Sopenharmony_ci afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); 8668c2ecf20Sopenharmony_ci afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); 8678c2ecf20Sopenharmony_ci afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci case IORESOURCE_MEM: 8708c2ecf20Sopenharmony_ci fpci_bar = (((res->start >> 12) & 0x0fffffff) << 4) | 0x1; 8718c2ecf20Sopenharmony_ci axi_address = res->start; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_PREFETCH) { 8748c2ecf20Sopenharmony_ci /* Bar 2: prefetchable memory BAR */ 8758c2ecf20Sopenharmony_ci afi_writel(pcie, axi_address, AFI_AXI_BAR2_START); 8768c2ecf20Sopenharmony_ci afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ); 8778c2ecf20Sopenharmony_ci afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci } else { 8808c2ecf20Sopenharmony_ci /* Bar 3: non prefetchable memory BAR */ 8818c2ecf20Sopenharmony_ci afi_writel(pcie, axi_address, AFI_AXI_BAR3_START); 8828c2ecf20Sopenharmony_ci afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ); 8838c2ecf20Sopenharmony_ci afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* NULL out the remaining BARs as they are not used */ 8908c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_AXI_BAR4_START); 8918c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_AXI_BAR4_SZ); 8928c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_FPCI_BAR4); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_AXI_BAR5_START); 8958c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_AXI_BAR5_SZ); 8968c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_FPCI_BAR5); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (pcie->soc->has_cache_bars) { 8998c2ecf20Sopenharmony_ci /* map all upstream transactions as uncached */ 9008c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_CACHE_BAR0_ST); 9018c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ); 9028c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_CACHE_BAR1_ST); 9038c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* MSI translations are setup only when needed */ 9078c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST); 9088c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_BAR_SZ); 9098c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST); 9108c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_BAR_SZ); 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 9168c2ecf20Sopenharmony_ci u32 value; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(timeout); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 9218c2ecf20Sopenharmony_ci value = pads_readl(pcie, soc->pads_pll_ctl); 9228c2ecf20Sopenharmony_ci if (value & PADS_PLL_CTL_LOCKDET) 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int tegra_pcie_phy_enable(struct tegra_pcie *pcie) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 9328c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 9338c2ecf20Sopenharmony_ci u32 value; 9348c2ecf20Sopenharmony_ci int err; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* initialize internal PHY, enable up to 16 PCIE lanes */ 9378c2ecf20Sopenharmony_ci pads_writel(pcie, 0x0, PADS_CTL_SEL); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* override IDDQ to 1 on all 4 lanes */ 9408c2ecf20Sopenharmony_ci value = pads_readl(pcie, PADS_CTL); 9418c2ecf20Sopenharmony_ci value |= PADS_CTL_IDDQ_1L; 9428c2ecf20Sopenharmony_ci pads_writel(pcie, value, PADS_CTL); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * Set up PHY PLL inputs select PLLE output as refclock, 9468c2ecf20Sopenharmony_ci * set TX ref sel to div10 (not div5). 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci value = pads_readl(pcie, soc->pads_pll_ctl); 9498c2ecf20Sopenharmony_ci value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK); 9508c2ecf20Sopenharmony_ci value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel; 9518c2ecf20Sopenharmony_ci pads_writel(pcie, value, soc->pads_pll_ctl); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* reset PLL */ 9548c2ecf20Sopenharmony_ci value = pads_readl(pcie, soc->pads_pll_ctl); 9558c2ecf20Sopenharmony_ci value &= ~PADS_PLL_CTL_RST_B4SM; 9568c2ecf20Sopenharmony_ci pads_writel(pcie, value, soc->pads_pll_ctl); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci usleep_range(20, 100); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* take PLL out of reset */ 9618c2ecf20Sopenharmony_ci value = pads_readl(pcie, soc->pads_pll_ctl); 9628c2ecf20Sopenharmony_ci value |= PADS_PLL_CTL_RST_B4SM; 9638c2ecf20Sopenharmony_ci pads_writel(pcie, value, soc->pads_pll_ctl); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* wait for the PLL to lock */ 9668c2ecf20Sopenharmony_ci err = tegra_pcie_pll_wait(pcie, 500); 9678c2ecf20Sopenharmony_ci if (err < 0) { 9688c2ecf20Sopenharmony_ci dev_err(dev, "PLL failed to lock: %d\n", err); 9698c2ecf20Sopenharmony_ci return err; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* turn off IDDQ override */ 9738c2ecf20Sopenharmony_ci value = pads_readl(pcie, PADS_CTL); 9748c2ecf20Sopenharmony_ci value &= ~PADS_CTL_IDDQ_1L; 9758c2ecf20Sopenharmony_ci pads_writel(pcie, value, PADS_CTL); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* enable TX/RX data */ 9788c2ecf20Sopenharmony_ci value = pads_readl(pcie, PADS_CTL); 9798c2ecf20Sopenharmony_ci value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L; 9808c2ecf20Sopenharmony_ci pads_writel(pcie, value, PADS_CTL); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return 0; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int tegra_pcie_phy_disable(struct tegra_pcie *pcie) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 9888c2ecf20Sopenharmony_ci u32 value; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* disable TX/RX data */ 9918c2ecf20Sopenharmony_ci value = pads_readl(pcie, PADS_CTL); 9928c2ecf20Sopenharmony_ci value &= ~(PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L); 9938c2ecf20Sopenharmony_ci pads_writel(pcie, value, PADS_CTL); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* override IDDQ */ 9968c2ecf20Sopenharmony_ci value = pads_readl(pcie, PADS_CTL); 9978c2ecf20Sopenharmony_ci value |= PADS_CTL_IDDQ_1L; 9988c2ecf20Sopenharmony_ci pads_writel(pcie, value, PADS_CTL); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* reset PLL */ 10018c2ecf20Sopenharmony_ci value = pads_readl(pcie, soc->pads_pll_ctl); 10028c2ecf20Sopenharmony_ci value &= ~PADS_PLL_CTL_RST_B4SM; 10038c2ecf20Sopenharmony_ci pads_writel(pcie, value, soc->pads_pll_ctl); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci usleep_range(20, 100); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return 0; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct device *dev = port->pcie->dev; 10138c2ecf20Sopenharmony_ci unsigned int i; 10148c2ecf20Sopenharmony_ci int err; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci for (i = 0; i < port->lanes; i++) { 10178c2ecf20Sopenharmony_ci err = phy_power_on(port->phys[i]); 10188c2ecf20Sopenharmony_ci if (err < 0) { 10198c2ecf20Sopenharmony_ci dev_err(dev, "failed to power on PHY#%u: %d\n", i, err); 10208c2ecf20Sopenharmony_ci return err; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci struct device *dev = port->pcie->dev; 10308c2ecf20Sopenharmony_ci unsigned int i; 10318c2ecf20Sopenharmony_ci int err; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci for (i = 0; i < port->lanes; i++) { 10348c2ecf20Sopenharmony_ci err = phy_power_off(port->phys[i]); 10358c2ecf20Sopenharmony_ci if (err < 0) { 10368c2ecf20Sopenharmony_ci dev_err(dev, "failed to power off PHY#%u: %d\n", i, 10378c2ecf20Sopenharmony_ci err); 10388c2ecf20Sopenharmony_ci return err; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 10488c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 10498c2ecf20Sopenharmony_ci int err; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (pcie->legacy_phy) { 10528c2ecf20Sopenharmony_ci if (pcie->phy) 10538c2ecf20Sopenharmony_ci err = phy_power_on(pcie->phy); 10548c2ecf20Sopenharmony_ci else 10558c2ecf20Sopenharmony_ci err = tegra_pcie_phy_enable(pcie); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (err < 0) 10588c2ecf20Sopenharmony_ci dev_err(dev, "failed to power on PHY: %d\n", err); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci return err; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 10648c2ecf20Sopenharmony_ci err = tegra_pcie_port_phy_power_on(port); 10658c2ecf20Sopenharmony_ci if (err < 0) { 10668c2ecf20Sopenharmony_ci dev_err(dev, 10678c2ecf20Sopenharmony_ci "failed to power on PCIe port %u PHY: %d\n", 10688c2ecf20Sopenharmony_ci port->index, err); 10698c2ecf20Sopenharmony_ci return err; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 10798c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 10808c2ecf20Sopenharmony_ci int err; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (pcie->legacy_phy) { 10838c2ecf20Sopenharmony_ci if (pcie->phy) 10848c2ecf20Sopenharmony_ci err = phy_power_off(pcie->phy); 10858c2ecf20Sopenharmony_ci else 10868c2ecf20Sopenharmony_ci err = tegra_pcie_phy_disable(pcie); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (err < 0) 10898c2ecf20Sopenharmony_ci dev_err(dev, "failed to power off PHY: %d\n", err); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return err; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 10958c2ecf20Sopenharmony_ci err = tegra_pcie_port_phy_power_off(port); 10968c2ecf20Sopenharmony_ci if (err < 0) { 10978c2ecf20Sopenharmony_ci dev_err(dev, 10988c2ecf20Sopenharmony_ci "failed to power off PCIe port %u PHY: %d\n", 10998c2ecf20Sopenharmony_ci port->index, err); 11008c2ecf20Sopenharmony_ci return err; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci return 0; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void tegra_pcie_enable_controller(struct tegra_pcie *pcie) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 11108c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 11118c2ecf20Sopenharmony_ci unsigned long value; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* enable PLL power down */ 11148c2ecf20Sopenharmony_ci if (pcie->phy) { 11158c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_PLLE_CONTROL); 11168c2ecf20Sopenharmony_ci value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; 11178c2ecf20Sopenharmony_ci value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; 11188c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_PLLE_CONTROL); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* power down PCIe slot clock bias pad */ 11228c2ecf20Sopenharmony_ci if (soc->has_pex_bias_ctrl) 11238c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* configure mode and disable all ports */ 11268c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_PCIE_CONFIG); 11278c2ecf20Sopenharmony_ci value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; 11288c2ecf20Sopenharmony_ci value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config; 11298c2ecf20Sopenharmony_ci value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 11328c2ecf20Sopenharmony_ci value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index); 11338c2ecf20Sopenharmony_ci value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_PCIE_CONFIG); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (soc->has_gen2) { 11398c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_FUSE); 11408c2ecf20Sopenharmony_ci value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; 11418c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_FUSE); 11428c2ecf20Sopenharmony_ci } else { 11438c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_FUSE); 11448c2ecf20Sopenharmony_ci value |= AFI_FUSE_PCIE_T0_GEN2_DIS; 11458c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_FUSE); 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* Disable AFI dynamic clock gating and enable PCIe */ 11498c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_CONFIGURATION); 11508c2ecf20Sopenharmony_ci value |= AFI_CONFIGURATION_EN_FPCI; 11518c2ecf20Sopenharmony_ci value |= AFI_CONFIGURATION_CLKEN_OVERRIDE; 11528c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_CONFIGURATION); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR | 11558c2ecf20Sopenharmony_ci AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR | 11568c2ecf20Sopenharmony_ci AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (soc->has_intr_prsnt_sense) 11598c2ecf20Sopenharmony_ci value |= AFI_INTR_EN_PRSNT_SENSE; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_AFI_INTR_ENABLE); 11628c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* don't enable MSI for now, only when needed */ 11658c2ecf20Sopenharmony_ci afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* disable all exceptions */ 11688c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS); 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic void tegra_pcie_power_off(struct tegra_pcie *pcie) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 11748c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 11758c2ecf20Sopenharmony_ci int err; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci reset_control_assert(pcie->afi_rst); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->pll_e); 11808c2ecf20Sopenharmony_ci if (soc->has_cml_clk) 11818c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->cml_clk); 11828c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->afi_clk); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (!dev->pm_domain) 11858c2ecf20Sopenharmony_ci tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); 11888c2ecf20Sopenharmony_ci if (err < 0) 11898c2ecf20Sopenharmony_ci dev_warn(dev, "failed to disable regulators: %d\n", err); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int tegra_pcie_power_on(struct tegra_pcie *pcie) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 11958c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 11968c2ecf20Sopenharmony_ci int err; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci reset_control_assert(pcie->pcie_xrst); 11998c2ecf20Sopenharmony_ci reset_control_assert(pcie->afi_rst); 12008c2ecf20Sopenharmony_ci reset_control_assert(pcie->pex_rst); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (!dev->pm_domain) 12038c2ecf20Sopenharmony_ci tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* enable regulators */ 12068c2ecf20Sopenharmony_ci err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); 12078c2ecf20Sopenharmony_ci if (err < 0) 12088c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable regulators: %d\n", err); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!dev->pm_domain) { 12118c2ecf20Sopenharmony_ci err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE); 12128c2ecf20Sopenharmony_ci if (err) { 12138c2ecf20Sopenharmony_ci dev_err(dev, "failed to power ungate: %d\n", err); 12148c2ecf20Sopenharmony_ci goto regulator_disable; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE); 12178c2ecf20Sopenharmony_ci if (err) { 12188c2ecf20Sopenharmony_ci dev_err(dev, "failed to remove clamp: %d\n", err); 12198c2ecf20Sopenharmony_ci goto powergate; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci err = clk_prepare_enable(pcie->afi_clk); 12248c2ecf20Sopenharmony_ci if (err < 0) { 12258c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable AFI clock: %d\n", err); 12268c2ecf20Sopenharmony_ci goto powergate; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (soc->has_cml_clk) { 12308c2ecf20Sopenharmony_ci err = clk_prepare_enable(pcie->cml_clk); 12318c2ecf20Sopenharmony_ci if (err < 0) { 12328c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable CML clock: %d\n", err); 12338c2ecf20Sopenharmony_ci goto disable_afi_clk; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci err = clk_prepare_enable(pcie->pll_e); 12388c2ecf20Sopenharmony_ci if (err < 0) { 12398c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable PLLE clock: %d\n", err); 12408c2ecf20Sopenharmony_ci goto disable_cml_clk; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci reset_control_deassert(pcie->afi_rst); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cidisable_cml_clk: 12488c2ecf20Sopenharmony_ci if (soc->has_cml_clk) 12498c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->cml_clk); 12508c2ecf20Sopenharmony_cidisable_afi_clk: 12518c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->afi_clk); 12528c2ecf20Sopenharmony_cipowergate: 12538c2ecf20Sopenharmony_ci if (!dev->pm_domain) 12548c2ecf20Sopenharmony_ci tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); 12558c2ecf20Sopenharmony_ciregulator_disable: 12568c2ecf20Sopenharmony_ci regulator_bulk_disable(pcie->num_supplies, pcie->supplies); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci return err; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic void tegra_pcie_apply_pad_settings(struct tegra_pcie *pcie) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* Configure the reference clock driver */ 12668c2ecf20Sopenharmony_ci pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (soc->num_ports > 2) 12698c2ecf20Sopenharmony_ci pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int tegra_pcie_clocks_get(struct tegra_pcie *pcie) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 12758c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci pcie->pex_clk = devm_clk_get(dev, "pex"); 12788c2ecf20Sopenharmony_ci if (IS_ERR(pcie->pex_clk)) 12798c2ecf20Sopenharmony_ci return PTR_ERR(pcie->pex_clk); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci pcie->afi_clk = devm_clk_get(dev, "afi"); 12828c2ecf20Sopenharmony_ci if (IS_ERR(pcie->afi_clk)) 12838c2ecf20Sopenharmony_ci return PTR_ERR(pcie->afi_clk); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci pcie->pll_e = devm_clk_get(dev, "pll_e"); 12868c2ecf20Sopenharmony_ci if (IS_ERR(pcie->pll_e)) 12878c2ecf20Sopenharmony_ci return PTR_ERR(pcie->pll_e); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (soc->has_cml_clk) { 12908c2ecf20Sopenharmony_ci pcie->cml_clk = devm_clk_get(dev, "cml"); 12918c2ecf20Sopenharmony_ci if (IS_ERR(pcie->cml_clk)) 12928c2ecf20Sopenharmony_ci return PTR_ERR(pcie->cml_clk); 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return 0; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int tegra_pcie_resets_get(struct tegra_pcie *pcie) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci pcie->pex_rst = devm_reset_control_get_exclusive(dev, "pex"); 13038c2ecf20Sopenharmony_ci if (IS_ERR(pcie->pex_rst)) 13048c2ecf20Sopenharmony_ci return PTR_ERR(pcie->pex_rst); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci pcie->afi_rst = devm_reset_control_get_exclusive(dev, "afi"); 13078c2ecf20Sopenharmony_ci if (IS_ERR(pcie->afi_rst)) 13088c2ecf20Sopenharmony_ci return PTR_ERR(pcie->afi_rst); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci pcie->pcie_xrst = devm_reset_control_get_exclusive(dev, "pcie_x"); 13118c2ecf20Sopenharmony_ci if (IS_ERR(pcie->pcie_xrst)) 13128c2ecf20Sopenharmony_ci return PTR_ERR(pcie->pcie_xrst); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 13208c2ecf20Sopenharmony_ci int err; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci pcie->phy = devm_phy_optional_get(dev, "pcie"); 13238c2ecf20Sopenharmony_ci if (IS_ERR(pcie->phy)) { 13248c2ecf20Sopenharmony_ci err = PTR_ERR(pcie->phy); 13258c2ecf20Sopenharmony_ci dev_err(dev, "failed to get PHY: %d\n", err); 13268c2ecf20Sopenharmony_ci return err; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci err = phy_init(pcie->phy); 13308c2ecf20Sopenharmony_ci if (err < 0) { 13318c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize PHY: %d\n", err); 13328c2ecf20Sopenharmony_ci return err; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci pcie->legacy_phy = true; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return 0; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic struct phy *devm_of_phy_optional_get_index(struct device *dev, 13418c2ecf20Sopenharmony_ci struct device_node *np, 13428c2ecf20Sopenharmony_ci const char *consumer, 13438c2ecf20Sopenharmony_ci unsigned int index) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct phy *phy; 13468c2ecf20Sopenharmony_ci char *name; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index); 13498c2ecf20Sopenharmony_ci if (!name) 13508c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci phy = devm_of_phy_get(dev, np, name); 13538c2ecf20Sopenharmony_ci kfree(name); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (PTR_ERR(phy) == -ENODEV) 13568c2ecf20Sopenharmony_ci phy = NULL; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci return phy; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic int tegra_pcie_port_get_phys(struct tegra_pcie_port *port) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct device *dev = port->pcie->dev; 13648c2ecf20Sopenharmony_ci struct phy *phy; 13658c2ecf20Sopenharmony_ci unsigned int i; 13668c2ecf20Sopenharmony_ci int err; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL); 13698c2ecf20Sopenharmony_ci if (!port->phys) 13708c2ecf20Sopenharmony_ci return -ENOMEM; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci for (i = 0; i < port->lanes; i++) { 13738c2ecf20Sopenharmony_ci phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i); 13748c2ecf20Sopenharmony_ci if (IS_ERR(phy)) { 13758c2ecf20Sopenharmony_ci dev_err(dev, "failed to get PHY#%u: %ld\n", i, 13768c2ecf20Sopenharmony_ci PTR_ERR(phy)); 13778c2ecf20Sopenharmony_ci return PTR_ERR(phy); 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci err = phy_init(phy); 13818c2ecf20Sopenharmony_ci if (err < 0) { 13828c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize PHY#%u: %d\n", i, 13838c2ecf20Sopenharmony_ci err); 13848c2ecf20Sopenharmony_ci return err; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci port->phys[i] = phy; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci return 0; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_cistatic int tegra_pcie_phys_get(struct tegra_pcie *pcie) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 13968c2ecf20Sopenharmony_ci struct device_node *np = pcie->dev->of_node; 13978c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 13988c2ecf20Sopenharmony_ci int err; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!soc->has_gen2 || of_find_property(np, "phys", NULL) != NULL) 14018c2ecf20Sopenharmony_ci return tegra_pcie_phys_get_legacy(pcie); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 14048c2ecf20Sopenharmony_ci err = tegra_pcie_port_get_phys(port); 14058c2ecf20Sopenharmony_ci if (err < 0) 14068c2ecf20Sopenharmony_ci return err; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci return 0; 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic void tegra_pcie_phys_put(struct tegra_pcie *pcie) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 14158c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 14168c2ecf20Sopenharmony_ci int err, i; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (pcie->legacy_phy) { 14198c2ecf20Sopenharmony_ci err = phy_exit(pcie->phy); 14208c2ecf20Sopenharmony_ci if (err < 0) 14218c2ecf20Sopenharmony_ci dev_err(dev, "failed to teardown PHY: %d\n", err); 14228c2ecf20Sopenharmony_ci return; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 14268c2ecf20Sopenharmony_ci for (i = 0; i < port->lanes; i++) { 14278c2ecf20Sopenharmony_ci err = phy_exit(port->phys[i]); 14288c2ecf20Sopenharmony_ci if (err < 0) 14298c2ecf20Sopenharmony_ci dev_err(dev, "failed to teardown PHY#%u: %d\n", 14308c2ecf20Sopenharmony_ci i, err); 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic int tegra_pcie_get_resources(struct tegra_pcie *pcie) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 14398c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 14408c2ecf20Sopenharmony_ci struct resource *res; 14418c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 14428c2ecf20Sopenharmony_ci int err; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci err = tegra_pcie_clocks_get(pcie); 14458c2ecf20Sopenharmony_ci if (err) { 14468c2ecf20Sopenharmony_ci dev_err(dev, "failed to get clocks: %d\n", err); 14478c2ecf20Sopenharmony_ci return err; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci err = tegra_pcie_resets_get(pcie); 14518c2ecf20Sopenharmony_ci if (err) { 14528c2ecf20Sopenharmony_ci dev_err(dev, "failed to get resets: %d\n", err); 14538c2ecf20Sopenharmony_ci return err; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (soc->program_uphy) { 14578c2ecf20Sopenharmony_ci err = tegra_pcie_phys_get(pcie); 14588c2ecf20Sopenharmony_ci if (err < 0) { 14598c2ecf20Sopenharmony_ci dev_err(dev, "failed to get PHYs: %d\n", err); 14608c2ecf20Sopenharmony_ci return err; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci pcie->pads = devm_platform_ioremap_resource_byname(pdev, "pads"); 14658c2ecf20Sopenharmony_ci if (IS_ERR(pcie->pads)) { 14668c2ecf20Sopenharmony_ci err = PTR_ERR(pcie->pads); 14678c2ecf20Sopenharmony_ci goto phys_put; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci pcie->afi = devm_platform_ioremap_resource_byname(pdev, "afi"); 14718c2ecf20Sopenharmony_ci if (IS_ERR(pcie->afi)) { 14728c2ecf20Sopenharmony_ci err = PTR_ERR(pcie->afi); 14738c2ecf20Sopenharmony_ci goto phys_put; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* request configuration space, but remap later, on demand */ 14778c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs"); 14788c2ecf20Sopenharmony_ci if (!res) { 14798c2ecf20Sopenharmony_ci err = -EADDRNOTAVAIL; 14808c2ecf20Sopenharmony_ci goto phys_put; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci pcie->cs = *res; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* constrain configuration space to 4 KiB */ 14868c2ecf20Sopenharmony_ci pcie->cs.end = pcie->cs.start + SZ_4K - 1; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci pcie->cfg = devm_ioremap_resource(dev, &pcie->cs); 14898c2ecf20Sopenharmony_ci if (IS_ERR(pcie->cfg)) { 14908c2ecf20Sopenharmony_ci err = PTR_ERR(pcie->cfg); 14918c2ecf20Sopenharmony_ci goto phys_put; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* request interrupt */ 14958c2ecf20Sopenharmony_ci err = platform_get_irq_byname(pdev, "intr"); 14968c2ecf20Sopenharmony_ci if (err < 0) 14978c2ecf20Sopenharmony_ci goto phys_put; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci pcie->irq = err; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE", pcie); 15028c2ecf20Sopenharmony_ci if (err) { 15038c2ecf20Sopenharmony_ci dev_err(dev, "failed to register IRQ: %d\n", err); 15048c2ecf20Sopenharmony_ci goto phys_put; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return 0; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ciphys_put: 15108c2ecf20Sopenharmony_ci if (soc->program_uphy) 15118c2ecf20Sopenharmony_ci tegra_pcie_phys_put(pcie); 15128c2ecf20Sopenharmony_ci return err; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic int tegra_pcie_put_resources(struct tegra_pcie *pcie) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (pcie->irq > 0) 15208c2ecf20Sopenharmony_ci free_irq(pcie->irq, pcie); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (soc->program_uphy) 15238c2ecf20Sopenharmony_ci tegra_pcie_phys_put(pcie); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci return 0; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void tegra_pcie_pme_turnoff(struct tegra_pcie_port *port) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = port->pcie; 15318c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 15328c2ecf20Sopenharmony_ci int err; 15338c2ecf20Sopenharmony_ci u32 val; 15348c2ecf20Sopenharmony_ci u8 ack_bit; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci val = afi_readl(pcie, AFI_PCIE_PME); 15378c2ecf20Sopenharmony_ci val |= (0x1 << soc->ports[port->index].pme.turnoff_bit); 15388c2ecf20Sopenharmony_ci afi_writel(pcie, val, AFI_PCIE_PME); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci ack_bit = soc->ports[port->index].pme.ack_bit; 15418c2ecf20Sopenharmony_ci err = readl_poll_timeout(pcie->afi + AFI_PCIE_PME, val, 15428c2ecf20Sopenharmony_ci val & (0x1 << ack_bit), 1, PME_ACK_TIMEOUT); 15438c2ecf20Sopenharmony_ci if (err) 15448c2ecf20Sopenharmony_ci dev_err(pcie->dev, "PME Ack is not received on port: %d\n", 15458c2ecf20Sopenharmony_ci port->index); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci val = afi_readl(pcie, AFI_PCIE_PME); 15508c2ecf20Sopenharmony_ci val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit); 15518c2ecf20Sopenharmony_ci afi_writel(pcie, val, AFI_PCIE_PME); 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_cistatic int tegra_msi_alloc(struct tegra_msi *chip) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci int msi; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci mutex_lock(&chip->lock); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci msi = find_first_zero_bit(chip->used, INT_PCI_MSI_NR); 15618c2ecf20Sopenharmony_ci if (msi < INT_PCI_MSI_NR) 15628c2ecf20Sopenharmony_ci set_bit(msi, chip->used); 15638c2ecf20Sopenharmony_ci else 15648c2ecf20Sopenharmony_ci msi = -ENOSPC; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci mutex_unlock(&chip->lock); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci return msi; 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_cistatic void tegra_msi_free(struct tegra_msi *chip, unsigned long irq) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci struct device *dev = chip->chip.dev; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci mutex_lock(&chip->lock); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (!test_bit(irq, chip->used)) 15788c2ecf20Sopenharmony_ci dev_err(dev, "trying to free unused MSI#%lu\n", irq); 15798c2ecf20Sopenharmony_ci else 15808c2ecf20Sopenharmony_ci clear_bit(irq, chip->used); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci mutex_unlock(&chip->lock); 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_cistatic irqreturn_t tegra_pcie_msi_irq(int irq, void *data) 15868c2ecf20Sopenharmony_ci{ 15878c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = data; 15888c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 15898c2ecf20Sopenharmony_ci struct tegra_msi *msi = &pcie->msi; 15908c2ecf20Sopenharmony_ci unsigned int i, processed = 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 15938c2ecf20Sopenharmony_ci unsigned long reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci while (reg) { 15968c2ecf20Sopenharmony_ci unsigned int offset = find_first_bit(®, 32); 15978c2ecf20Sopenharmony_ci unsigned int index = i * 32 + offset; 15988c2ecf20Sopenharmony_ci unsigned int irq; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* clear the interrupt */ 16018c2ecf20Sopenharmony_ci afi_writel(pcie, 1 << offset, AFI_MSI_VEC0 + i * 4); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci irq = irq_find_mapping(msi->domain, index); 16048c2ecf20Sopenharmony_ci if (irq) { 16058c2ecf20Sopenharmony_ci if (test_bit(index, msi->used)) 16068c2ecf20Sopenharmony_ci generic_handle_irq(irq); 16078c2ecf20Sopenharmony_ci else 16088c2ecf20Sopenharmony_ci dev_info(dev, "unhandled MSI\n"); 16098c2ecf20Sopenharmony_ci } else { 16108c2ecf20Sopenharmony_ci /* 16118c2ecf20Sopenharmony_ci * that's weird who triggered this? 16128c2ecf20Sopenharmony_ci * just clear it 16138c2ecf20Sopenharmony_ci */ 16148c2ecf20Sopenharmony_ci dev_info(dev, "unexpected MSI\n"); 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* see if there's any more pending in this vector */ 16188c2ecf20Sopenharmony_ci reg = afi_readl(pcie, AFI_MSI_VEC0 + i * 4); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci processed++; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return processed > 0 ? IRQ_HANDLED : IRQ_NONE; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_cistatic int tegra_msi_setup_irq(struct msi_controller *chip, 16288c2ecf20Sopenharmony_ci struct pci_dev *pdev, struct msi_desc *desc) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci struct tegra_msi *msi = to_tegra_msi(chip); 16318c2ecf20Sopenharmony_ci struct msi_msg msg; 16328c2ecf20Sopenharmony_ci unsigned int irq; 16338c2ecf20Sopenharmony_ci int hwirq; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci hwirq = tegra_msi_alloc(msi); 16368c2ecf20Sopenharmony_ci if (hwirq < 0) 16378c2ecf20Sopenharmony_ci return hwirq; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci irq = irq_create_mapping(msi->domain, hwirq); 16408c2ecf20Sopenharmony_ci if (!irq) { 16418c2ecf20Sopenharmony_ci tegra_msi_free(msi, hwirq); 16428c2ecf20Sopenharmony_ci return -EINVAL; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci irq_set_msi_desc(irq, desc); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci msg.address_lo = lower_32_bits(msi->phys); 16488c2ecf20Sopenharmony_ci msg.address_hi = upper_32_bits(msi->phys); 16498c2ecf20Sopenharmony_ci msg.data = hwirq; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci pci_write_msi_msg(irq, &msg); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci return 0; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic void tegra_msi_teardown_irq(struct msi_controller *chip, 16578c2ecf20Sopenharmony_ci unsigned int irq) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct tegra_msi *msi = to_tegra_msi(chip); 16608c2ecf20Sopenharmony_ci struct irq_data *d = irq_get_irq_data(irq); 16618c2ecf20Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci irq_dispose_mapping(irq); 16648c2ecf20Sopenharmony_ci tegra_msi_free(msi, hwirq); 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic struct irq_chip tegra_msi_irq_chip = { 16688c2ecf20Sopenharmony_ci .name = "Tegra PCIe MSI", 16698c2ecf20Sopenharmony_ci .irq_enable = pci_msi_unmask_irq, 16708c2ecf20Sopenharmony_ci .irq_disable = pci_msi_mask_irq, 16718c2ecf20Sopenharmony_ci .irq_mask = pci_msi_mask_irq, 16728c2ecf20Sopenharmony_ci .irq_unmask = pci_msi_unmask_irq, 16738c2ecf20Sopenharmony_ci}; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cistatic int tegra_msi_map(struct irq_domain *domain, unsigned int irq, 16768c2ecf20Sopenharmony_ci irq_hw_number_t hwirq) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &tegra_msi_irq_chip, handle_simple_irq); 16798c2ecf20Sopenharmony_ci irq_set_chip_data(irq, domain->host_data); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci tegra_cpuidle_pcie_irqs_in_use(); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci return 0; 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic const struct irq_domain_ops msi_domain_ops = { 16878c2ecf20Sopenharmony_ci .map = tegra_msi_map, 16888c2ecf20Sopenharmony_ci}; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_cistatic int tegra_pcie_msi_setup(struct tegra_pcie *pcie) 16918c2ecf20Sopenharmony_ci{ 16928c2ecf20Sopenharmony_ci struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 16938c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(pcie->dev); 16948c2ecf20Sopenharmony_ci struct tegra_msi *msi = &pcie->msi; 16958c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 16968c2ecf20Sopenharmony_ci int err; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci mutex_init(&msi->lock); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci msi->chip.dev = dev; 17018c2ecf20Sopenharmony_ci msi->chip.setup_irq = tegra_msi_setup_irq; 17028c2ecf20Sopenharmony_ci msi->chip.teardown_irq = tegra_msi_teardown_irq; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci msi->domain = irq_domain_add_linear(dev->of_node, INT_PCI_MSI_NR, 17058c2ecf20Sopenharmony_ci &msi_domain_ops, &msi->chip); 17068c2ecf20Sopenharmony_ci if (!msi->domain) { 17078c2ecf20Sopenharmony_ci dev_err(dev, "failed to create IRQ domain\n"); 17088c2ecf20Sopenharmony_ci return -ENOMEM; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci err = platform_get_irq_byname(pdev, "msi"); 17128c2ecf20Sopenharmony_ci if (err < 0) 17138c2ecf20Sopenharmony_ci goto free_irq_domain; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci msi->irq = err; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci err = request_irq(msi->irq, tegra_pcie_msi_irq, IRQF_NO_THREAD, 17188c2ecf20Sopenharmony_ci tegra_msi_irq_chip.name, pcie); 17198c2ecf20Sopenharmony_ci if (err < 0) { 17208c2ecf20Sopenharmony_ci dev_err(dev, "failed to request IRQ: %d\n", err); 17218c2ecf20Sopenharmony_ci goto free_irq_domain; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* Though the PCIe controller can address >32-bit address space, to 17258c2ecf20Sopenharmony_ci * facilitate endpoints that support only 32-bit MSI target address, 17268c2ecf20Sopenharmony_ci * the mask is set to 32-bit to make sure that MSI target address is 17278c2ecf20Sopenharmony_ci * always a 32-bit address 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_ci err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 17308c2ecf20Sopenharmony_ci if (err < 0) { 17318c2ecf20Sopenharmony_ci dev_err(dev, "failed to set DMA coherent mask: %d\n", err); 17328c2ecf20Sopenharmony_ci goto free_irq; 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL, 17368c2ecf20Sopenharmony_ci DMA_ATTR_NO_KERNEL_MAPPING); 17378c2ecf20Sopenharmony_ci if (!msi->virt) { 17388c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate DMA memory for MSI\n"); 17398c2ecf20Sopenharmony_ci err = -ENOMEM; 17408c2ecf20Sopenharmony_ci goto free_irq; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci host->msi = &msi->chip; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci return 0; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cifree_irq: 17488c2ecf20Sopenharmony_ci free_irq(msi->irq, pcie); 17498c2ecf20Sopenharmony_cifree_irq_domain: 17508c2ecf20Sopenharmony_ci irq_domain_remove(msi->domain); 17518c2ecf20Sopenharmony_ci return err; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic void tegra_pcie_enable_msi(struct tegra_pcie *pcie) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 17578c2ecf20Sopenharmony_ci struct tegra_msi *msi = &pcie->msi; 17588c2ecf20Sopenharmony_ci u32 reg; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci afi_writel(pcie, msi->phys >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST); 17618c2ecf20Sopenharmony_ci afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST); 17628c2ecf20Sopenharmony_ci /* this register is in 4K increments */ 17638c2ecf20Sopenharmony_ci afi_writel(pcie, 1, AFI_MSI_BAR_SZ); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* enable all MSI vectors */ 17668c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC0); 17678c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC1); 17688c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC2); 17698c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC3); 17708c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC4); 17718c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC5); 17728c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC6); 17738c2ecf20Sopenharmony_ci afi_writel(pcie, 0xffffffff, AFI_MSI_EN_VEC7); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci /* and unmask the MSI interrupt */ 17768c2ecf20Sopenharmony_ci reg = afi_readl(pcie, AFI_INTR_MASK); 17778c2ecf20Sopenharmony_ci reg |= AFI_INTR_MASK_MSI_MASK; 17788c2ecf20Sopenharmony_ci afi_writel(pcie, reg, AFI_INTR_MASK); 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic void tegra_pcie_msi_teardown(struct tegra_pcie *pcie) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci struct tegra_msi *msi = &pcie->msi; 17848c2ecf20Sopenharmony_ci unsigned int i, irq; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys, 17878c2ecf20Sopenharmony_ci DMA_ATTR_NO_KERNEL_MAPPING); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (msi->irq > 0) 17908c2ecf20Sopenharmony_ci free_irq(msi->irq, pcie); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci for (i = 0; i < INT_PCI_MSI_NR; i++) { 17938c2ecf20Sopenharmony_ci irq = irq_find_mapping(msi->domain, i); 17948c2ecf20Sopenharmony_ci if (irq > 0) 17958c2ecf20Sopenharmony_ci irq_dispose_mapping(irq); 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci irq_domain_remove(msi->domain); 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic int tegra_pcie_disable_msi(struct tegra_pcie *pcie) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci u32 value; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* mask the MSI interrupt */ 18068c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_INTR_MASK); 18078c2ecf20Sopenharmony_ci value &= ~AFI_INTR_MASK_MSI_MASK; 18088c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_INTR_MASK); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci /* disable all MSI vectors */ 18118c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC0); 18128c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC1); 18138c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC2); 18148c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC3); 18158c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC4); 18168c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC5); 18178c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC6); 18188c2ecf20Sopenharmony_ci afi_writel(pcie, 0, AFI_MSI_EN_VEC7); 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci return 0; 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci u32 value; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci value = afi_readl(pcie, AFI_INTR_MASK); 18288c2ecf20Sopenharmony_ci value &= ~AFI_INTR_MASK_INT_MASK; 18298c2ecf20Sopenharmony_ci afi_writel(pcie, value, AFI_INTR_MASK); 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_cistatic int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, 18338c2ecf20Sopenharmony_ci u32 *xbar) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 18368c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { 18398c2ecf20Sopenharmony_ci switch (lanes) { 18408c2ecf20Sopenharmony_ci case 0x010004: 18418c2ecf20Sopenharmony_ci dev_info(dev, "4x1, 1x1 configuration\n"); 18428c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401; 18438c2ecf20Sopenharmony_ci return 0; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci case 0x010102: 18468c2ecf20Sopenharmony_ci dev_info(dev, "2x1, 1X1, 1x1 configuration\n"); 18478c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; 18488c2ecf20Sopenharmony_ci return 0; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci case 0x010101: 18518c2ecf20Sopenharmony_ci dev_info(dev, "1x1, 1x1, 1x1 configuration\n"); 18528c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111; 18538c2ecf20Sopenharmony_ci return 0; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci default: 18568c2ecf20Sopenharmony_ci dev_info(dev, "wrong configuration updated in DT, " 18578c2ecf20Sopenharmony_ci "switching to default 2x1, 1x1, 1x1 " 18588c2ecf20Sopenharmony_ci "configuration\n"); 18598c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || 18638c2ecf20Sopenharmony_ci of_device_is_compatible(np, "nvidia,tegra210-pcie")) { 18648c2ecf20Sopenharmony_ci switch (lanes) { 18658c2ecf20Sopenharmony_ci case 0x0000104: 18668c2ecf20Sopenharmony_ci dev_info(dev, "4x1, 1x1 configuration\n"); 18678c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1; 18688c2ecf20Sopenharmony_ci return 0; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci case 0x0000102: 18718c2ecf20Sopenharmony_ci dev_info(dev, "2x1, 1x1 configuration\n"); 18728c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1; 18738c2ecf20Sopenharmony_ci return 0; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { 18768c2ecf20Sopenharmony_ci switch (lanes) { 18778c2ecf20Sopenharmony_ci case 0x00000204: 18788c2ecf20Sopenharmony_ci dev_info(dev, "4x1, 2x1 configuration\n"); 18798c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420; 18808c2ecf20Sopenharmony_ci return 0; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci case 0x00020202: 18838c2ecf20Sopenharmony_ci dev_info(dev, "2x3 configuration\n"); 18848c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222; 18858c2ecf20Sopenharmony_ci return 0; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci case 0x00010104: 18888c2ecf20Sopenharmony_ci dev_info(dev, "4x1, 1x2 configuration\n"); 18898c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411; 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { 18938c2ecf20Sopenharmony_ci switch (lanes) { 18948c2ecf20Sopenharmony_ci case 0x00000004: 18958c2ecf20Sopenharmony_ci dev_info(dev, "single-mode configuration\n"); 18968c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE; 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci case 0x00000202: 19008c2ecf20Sopenharmony_ci dev_info(dev, "dual-mode configuration\n"); 19018c2ecf20Sopenharmony_ci *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL; 19028c2ecf20Sopenharmony_ci return 0; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci return -EINVAL; 19078c2ecf20Sopenharmony_ci} 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci/* 19108c2ecf20Sopenharmony_ci * Check whether a given set of supplies is available in a device tree node. 19118c2ecf20Sopenharmony_ci * This is used to check whether the new or the legacy device tree bindings 19128c2ecf20Sopenharmony_ci * should be used. 19138c2ecf20Sopenharmony_ci */ 19148c2ecf20Sopenharmony_cistatic bool of_regulator_bulk_available(struct device_node *np, 19158c2ecf20Sopenharmony_ci struct regulator_bulk_data *supplies, 19168c2ecf20Sopenharmony_ci unsigned int num_supplies) 19178c2ecf20Sopenharmony_ci{ 19188c2ecf20Sopenharmony_ci char property[32]; 19198c2ecf20Sopenharmony_ci unsigned int i; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci for (i = 0; i < num_supplies; i++) { 19228c2ecf20Sopenharmony_ci snprintf(property, 32, "%s-supply", supplies[i].supply); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (of_find_property(np, property, NULL) == NULL) 19258c2ecf20Sopenharmony_ci return false; 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci return true; 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci/* 19328c2ecf20Sopenharmony_ci * Old versions of the device tree binding for this device used a set of power 19338c2ecf20Sopenharmony_ci * supplies that didn't match the hardware inputs. This happened to work for a 19348c2ecf20Sopenharmony_ci * number of cases but is not future proof. However to preserve backwards- 19358c2ecf20Sopenharmony_ci * compatibility with old device trees, this function will try to use the old 19368c2ecf20Sopenharmony_ci * set of supplies. 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_cistatic int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 19418c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) 19448c2ecf20Sopenharmony_ci pcie->num_supplies = 3; 19458c2ecf20Sopenharmony_ci else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) 19468c2ecf20Sopenharmony_ci pcie->num_supplies = 2; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci if (pcie->num_supplies == 0) { 19498c2ecf20Sopenharmony_ci dev_err(dev, "device %pOF not supported in legacy mode\n", np); 19508c2ecf20Sopenharmony_ci return -ENODEV; 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, 19548c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 19558c2ecf20Sopenharmony_ci GFP_KERNEL); 19568c2ecf20Sopenharmony_ci if (!pcie->supplies) 19578c2ecf20Sopenharmony_ci return -ENOMEM; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci pcie->supplies[0].supply = "pex-clk"; 19608c2ecf20Sopenharmony_ci pcie->supplies[1].supply = "vdd"; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (pcie->num_supplies > 2) 19638c2ecf20Sopenharmony_ci pcie->supplies[2].supply = "avdd"; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(dev, pcie->num_supplies, pcie->supplies); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci/* 19698c2ecf20Sopenharmony_ci * Obtains the list of regulators required for a particular generation of the 19708c2ecf20Sopenharmony_ci * IP block. 19718c2ecf20Sopenharmony_ci * 19728c2ecf20Sopenharmony_ci * This would've been nice to do simply by providing static tables for use 19738c2ecf20Sopenharmony_ci * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky 19748c2ecf20Sopenharmony_ci * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) 19758c2ecf20Sopenharmony_ci * and either seems to be optional depending on which ports are being used. 19768c2ecf20Sopenharmony_ci */ 19778c2ecf20Sopenharmony_cistatic int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 19808c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 19818c2ecf20Sopenharmony_ci unsigned int i = 0; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { 19848c2ecf20Sopenharmony_ci pcie->num_supplies = 4; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, 19878c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 19888c2ecf20Sopenharmony_ci GFP_KERNEL); 19898c2ecf20Sopenharmony_ci if (!pcie->supplies) 19908c2ecf20Sopenharmony_ci return -ENOMEM; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "dvdd-pex"; 19938c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "hvdd-pex-pll"; 19948c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "hvdd-pex"; 19958c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vddio-pexctl-aud"; 19968c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { 19978c2ecf20Sopenharmony_ci pcie->num_supplies = 3; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, 20008c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 20018c2ecf20Sopenharmony_ci GFP_KERNEL); 20028c2ecf20Sopenharmony_ci if (!pcie->supplies) 20038c2ecf20Sopenharmony_ci return -ENOMEM; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "hvddio-pex"; 20068c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "dvddio-pex"; 20078c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vddio-pex-ctl"; 20088c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { 20098c2ecf20Sopenharmony_ci pcie->num_supplies = 4; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, 20128c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 20138c2ecf20Sopenharmony_ci GFP_KERNEL); 20148c2ecf20Sopenharmony_ci if (!pcie->supplies) 20158c2ecf20Sopenharmony_ci return -ENOMEM; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "avddio-pex"; 20188c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "dvddio-pex"; 20198c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "hvdd-pex"; 20208c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vddio-pex-ctl"; 20218c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { 20228c2ecf20Sopenharmony_ci bool need_pexa = false, need_pexb = false; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */ 20258c2ecf20Sopenharmony_ci if (lane_mask & 0x0f) 20268c2ecf20Sopenharmony_ci need_pexa = true; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */ 20298c2ecf20Sopenharmony_ci if (lane_mask & 0x30) 20308c2ecf20Sopenharmony_ci need_pexb = true; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + 20338c2ecf20Sopenharmony_ci (need_pexb ? 2 : 0); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, 20368c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 20378c2ecf20Sopenharmony_ci GFP_KERNEL); 20388c2ecf20Sopenharmony_ci if (!pcie->supplies) 20398c2ecf20Sopenharmony_ci return -ENOMEM; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "avdd-pex-pll"; 20428c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "hvdd-pex"; 20438c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vddio-pex-ctl"; 20448c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "avdd-plle"; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci if (need_pexa) { 20478c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "avdd-pexa"; 20488c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vdd-pexa"; 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (need_pexb) { 20528c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "avdd-pexb"; 20538c2ecf20Sopenharmony_ci pcie->supplies[i++].supply = "vdd-pexb"; 20548c2ecf20Sopenharmony_ci } 20558c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { 20568c2ecf20Sopenharmony_ci pcie->num_supplies = 5; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, 20598c2ecf20Sopenharmony_ci sizeof(*pcie->supplies), 20608c2ecf20Sopenharmony_ci GFP_KERNEL); 20618c2ecf20Sopenharmony_ci if (!pcie->supplies) 20628c2ecf20Sopenharmony_ci return -ENOMEM; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci pcie->supplies[0].supply = "avdd-pex"; 20658c2ecf20Sopenharmony_ci pcie->supplies[1].supply = "vdd-pex"; 20668c2ecf20Sopenharmony_ci pcie->supplies[2].supply = "avdd-pex-pll"; 20678c2ecf20Sopenharmony_ci pcie->supplies[3].supply = "avdd-plle"; 20688c2ecf20Sopenharmony_ci pcie->supplies[4].supply = "vddio-pex-clk"; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (of_regulator_bulk_available(dev->of_node, pcie->supplies, 20728c2ecf20Sopenharmony_ci pcie->num_supplies)) 20738c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(dev, pcie->num_supplies, 20748c2ecf20Sopenharmony_ci pcie->supplies); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci /* 20778c2ecf20Sopenharmony_ci * If not all regulators are available for this new scheme, assume 20788c2ecf20Sopenharmony_ci * that the device tree complies with an older version of the device 20798c2ecf20Sopenharmony_ci * tree binding. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_ci dev_info(dev, "using legacy DT binding for power supplies\n"); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci devm_kfree(dev, pcie->supplies); 20848c2ecf20Sopenharmony_ci pcie->num_supplies = 0; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci return tegra_pcie_get_legacy_regulators(pcie); 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic int tegra_pcie_parse_dt(struct tegra_pcie *pcie) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 20928c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node, *port; 20938c2ecf20Sopenharmony_ci const struct tegra_pcie_soc *soc = pcie->soc; 20948c2ecf20Sopenharmony_ci u32 lanes = 0, mask = 0; 20958c2ecf20Sopenharmony_ci unsigned int lane = 0; 20968c2ecf20Sopenharmony_ci int err; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* parse root ports */ 20998c2ecf20Sopenharmony_ci for_each_child_of_node(np, port) { 21008c2ecf20Sopenharmony_ci struct tegra_pcie_port *rp; 21018c2ecf20Sopenharmony_ci unsigned int index; 21028c2ecf20Sopenharmony_ci u32 value; 21038c2ecf20Sopenharmony_ci char *label; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci err = of_pci_get_devfn(port); 21068c2ecf20Sopenharmony_ci if (err < 0) { 21078c2ecf20Sopenharmony_ci dev_err(dev, "failed to parse address: %d\n", err); 21088c2ecf20Sopenharmony_ci goto err_node_put; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci index = PCI_SLOT(err); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (index < 1 || index > soc->num_ports) { 21148c2ecf20Sopenharmony_ci dev_err(dev, "invalid port number: %d\n", index); 21158c2ecf20Sopenharmony_ci err = -EINVAL; 21168c2ecf20Sopenharmony_ci goto err_node_put; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci index--; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci err = of_property_read_u32(port, "nvidia,num-lanes", &value); 21228c2ecf20Sopenharmony_ci if (err < 0) { 21238c2ecf20Sopenharmony_ci dev_err(dev, "failed to parse # of lanes: %d\n", 21248c2ecf20Sopenharmony_ci err); 21258c2ecf20Sopenharmony_ci goto err_node_put; 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci if (value > 16) { 21298c2ecf20Sopenharmony_ci dev_err(dev, "invalid # of lanes: %u\n", value); 21308c2ecf20Sopenharmony_ci err = -EINVAL; 21318c2ecf20Sopenharmony_ci goto err_node_put; 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci lanes |= value << (index << 3); 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci if (!of_device_is_available(port)) { 21378c2ecf20Sopenharmony_ci lane += value; 21388c2ecf20Sopenharmony_ci continue; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci mask |= ((1 << value) - 1) << lane; 21428c2ecf20Sopenharmony_ci lane += value; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL); 21458c2ecf20Sopenharmony_ci if (!rp) { 21468c2ecf20Sopenharmony_ci err = -ENOMEM; 21478c2ecf20Sopenharmony_ci goto err_node_put; 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci err = of_address_to_resource(port, 0, &rp->regs); 21518c2ecf20Sopenharmony_ci if (err < 0) { 21528c2ecf20Sopenharmony_ci dev_err(dev, "failed to parse address: %d\n", err); 21538c2ecf20Sopenharmony_ci goto err_node_put; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rp->list); 21578c2ecf20Sopenharmony_ci rp->index = index; 21588c2ecf20Sopenharmony_ci rp->lanes = value; 21598c2ecf20Sopenharmony_ci rp->pcie = pcie; 21608c2ecf20Sopenharmony_ci rp->np = port; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci rp->base = devm_pci_remap_cfg_resource(dev, &rp->regs); 21638c2ecf20Sopenharmony_ci if (IS_ERR(rp->base)) { 21648c2ecf20Sopenharmony_ci err = PTR_ERR(rp->base); 21658c2ecf20Sopenharmony_ci goto err_node_put; 21668c2ecf20Sopenharmony_ci } 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index); 21698c2ecf20Sopenharmony_ci if (!label) { 21708c2ecf20Sopenharmony_ci err = -ENOMEM; 21718c2ecf20Sopenharmony_ci goto err_node_put; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci /* 21758c2ecf20Sopenharmony_ci * Returns -ENOENT if reset-gpios property is not populated 21768c2ecf20Sopenharmony_ci * and in this case fall back to using AFI per port register 21778c2ecf20Sopenharmony_ci * to toggle PERST# SFIO line. 21788c2ecf20Sopenharmony_ci */ 21798c2ecf20Sopenharmony_ci rp->reset_gpio = devm_gpiod_get_from_of_node(dev, port, 21808c2ecf20Sopenharmony_ci "reset-gpios", 0, 21818c2ecf20Sopenharmony_ci GPIOD_OUT_LOW, 21828c2ecf20Sopenharmony_ci label); 21838c2ecf20Sopenharmony_ci if (IS_ERR(rp->reset_gpio)) { 21848c2ecf20Sopenharmony_ci if (PTR_ERR(rp->reset_gpio) == -ENOENT) { 21858c2ecf20Sopenharmony_ci rp->reset_gpio = NULL; 21868c2ecf20Sopenharmony_ci } else { 21878c2ecf20Sopenharmony_ci dev_err(dev, "failed to get reset GPIO: %ld\n", 21888c2ecf20Sopenharmony_ci PTR_ERR(rp->reset_gpio)); 21898c2ecf20Sopenharmony_ci err = PTR_ERR(rp->reset_gpio); 21908c2ecf20Sopenharmony_ci goto err_node_put; 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci list_add_tail(&rp->list, &pcie->ports); 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config); 21988c2ecf20Sopenharmony_ci if (err < 0) { 21998c2ecf20Sopenharmony_ci dev_err(dev, "invalid lane configuration\n"); 22008c2ecf20Sopenharmony_ci return err; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci err = tegra_pcie_get_regulators(pcie, mask); 22048c2ecf20Sopenharmony_ci if (err < 0) 22058c2ecf20Sopenharmony_ci return err; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci return 0; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_cierr_node_put: 22108c2ecf20Sopenharmony_ci of_node_put(port); 22118c2ecf20Sopenharmony_ci return err; 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci/* 22158c2ecf20Sopenharmony_ci * FIXME: If there are no PCIe cards attached, then calling this function 22168c2ecf20Sopenharmony_ci * can result in the increase of the bootup time as there are big timeout 22178c2ecf20Sopenharmony_ci * loops. 22188c2ecf20Sopenharmony_ci */ 22198c2ecf20Sopenharmony_ci#define TEGRA_PCIE_LINKUP_TIMEOUT 200 /* up to 1.2 seconds */ 22208c2ecf20Sopenharmony_cistatic bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci struct device *dev = port->pcie->dev; 22238c2ecf20Sopenharmony_ci unsigned int retries = 3; 22248c2ecf20Sopenharmony_ci unsigned long value; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* override presence detection */ 22278c2ecf20Sopenharmony_ci value = readl(port->base + RP_PRIV_MISC); 22288c2ecf20Sopenharmony_ci value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT; 22298c2ecf20Sopenharmony_ci value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT; 22308c2ecf20Sopenharmony_ci writel(value, port->base + RP_PRIV_MISC); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci do { 22338c2ecf20Sopenharmony_ci unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci do { 22368c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_XP); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if (value & RP_VEND_XP_DL_UP) 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 22428c2ecf20Sopenharmony_ci } while (--timeout); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if (!timeout) { 22458c2ecf20Sopenharmony_ci dev_dbg(dev, "link %u down, retrying\n", port->index); 22468c2ecf20Sopenharmony_ci goto retry; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci timeout = TEGRA_PCIE_LINKUP_TIMEOUT; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci do { 22528c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) 22558c2ecf20Sopenharmony_ci return true; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 22588c2ecf20Sopenharmony_ci } while (--timeout); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ciretry: 22618c2ecf20Sopenharmony_ci tegra_pcie_port_reset(port); 22628c2ecf20Sopenharmony_ci } while (--retries); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci return false; 22658c2ecf20Sopenharmony_ci} 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_cistatic void tegra_pcie_change_link_speed(struct tegra_pcie *pcie) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 22708c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 22718c2ecf20Sopenharmony_ci ktime_t deadline; 22728c2ecf20Sopenharmony_ci u32 value; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) { 22758c2ecf20Sopenharmony_ci /* 22768c2ecf20Sopenharmony_ci * "Supported Link Speeds Vector" in "Link Capabilities 2" 22778c2ecf20Sopenharmony_ci * is not supported by Tegra. tegra_pcie_change_link_speed() 22788c2ecf20Sopenharmony_ci * is called only for Tegra chips which support Gen2. 22798c2ecf20Sopenharmony_ci * So there no harm if supported link speed is not verified. 22808c2ecf20Sopenharmony_ci */ 22818c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS_2); 22828c2ecf20Sopenharmony_ci value &= ~PCI_EXP_LNKSTA_CLS; 22838c2ecf20Sopenharmony_ci value |= PCI_EXP_LNKSTA_CLS_5_0GB; 22848c2ecf20Sopenharmony_ci writel(value, port->base + RP_LINK_CONTROL_STATUS_2); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci /* 22878c2ecf20Sopenharmony_ci * Poll until link comes back from recovery to avoid race 22888c2ecf20Sopenharmony_ci * condition. 22898c2ecf20Sopenharmony_ci */ 22908c2ecf20Sopenharmony_ci deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT); 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci while (ktime_before(ktime_get(), deadline)) { 22938c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS); 22948c2ecf20Sopenharmony_ci if ((value & PCI_EXP_LNKSTA_LT) == 0) 22958c2ecf20Sopenharmony_ci break; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci usleep_range(2000, 3000); 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci if (value & PCI_EXP_LNKSTA_LT) 23018c2ecf20Sopenharmony_ci dev_warn(dev, "PCIe port %u link is in recovery\n", 23028c2ecf20Sopenharmony_ci port->index); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci /* Retrain the link */ 23058c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS); 23068c2ecf20Sopenharmony_ci value |= PCI_EXP_LNKCTL_RL; 23078c2ecf20Sopenharmony_ci writel(value, port->base + RP_LINK_CONTROL_STATUS); 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci while (ktime_before(ktime_get(), deadline)) { 23128c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS); 23138c2ecf20Sopenharmony_ci if ((value & PCI_EXP_LNKSTA_LT) == 0) 23148c2ecf20Sopenharmony_ci break; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci usleep_range(2000, 3000); 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (value & PCI_EXP_LNKSTA_LT) 23208c2ecf20Sopenharmony_ci dev_err(dev, "failed to retrain link of port %u\n", 23218c2ecf20Sopenharmony_ci port->index); 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_cistatic void tegra_pcie_enable_ports(struct tegra_pcie *pcie) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 23288c2ecf20Sopenharmony_ci struct tegra_pcie_port *port, *tmp; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci list_for_each_entry_safe(port, tmp, &pcie->ports, list) { 23318c2ecf20Sopenharmony_ci dev_info(dev, "probing port %u, using %u lanes\n", 23328c2ecf20Sopenharmony_ci port->index, port->lanes); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci tegra_pcie_port_enable(port); 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* Start LTSSM from Tegra side */ 23388c2ecf20Sopenharmony_ci reset_control_deassert(pcie->pcie_xrst); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci list_for_each_entry_safe(port, tmp, &pcie->ports, list) { 23418c2ecf20Sopenharmony_ci if (tegra_pcie_port_check_link(port)) 23428c2ecf20Sopenharmony_ci continue; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci dev_info(dev, "link %u down, ignoring\n", port->index); 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci tegra_pcie_port_disable(port); 23478c2ecf20Sopenharmony_ci tegra_pcie_port_free(port); 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (pcie->soc->has_gen2) 23518c2ecf20Sopenharmony_ci tegra_pcie_change_link_speed(pcie); 23528c2ecf20Sopenharmony_ci} 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_cistatic void tegra_pcie_disable_ports(struct tegra_pcie *pcie) 23558c2ecf20Sopenharmony_ci{ 23568c2ecf20Sopenharmony_ci struct tegra_pcie_port *port, *tmp; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci reset_control_assert(pcie->pcie_xrst); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci list_for_each_entry_safe(port, tmp, &pcie->ports, list) 23618c2ecf20Sopenharmony_ci tegra_pcie_port_disable(port); 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra20_pcie_ports[] = { 23658c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 0, .pme.ack_bit = 5 }, 23668c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 8, .pme.ack_bit = 10 }, 23678c2ecf20Sopenharmony_ci}; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cistatic const struct tegra_pcie_soc tegra20_pcie = { 23708c2ecf20Sopenharmony_ci .num_ports = 2, 23718c2ecf20Sopenharmony_ci .ports = tegra20_pcie_ports, 23728c2ecf20Sopenharmony_ci .msi_base_shift = 0, 23738c2ecf20Sopenharmony_ci .pads_pll_ctl = PADS_PLL_CTL_TEGRA20, 23748c2ecf20Sopenharmony_ci .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10, 23758c2ecf20Sopenharmony_ci .pads_refclk_cfg0 = 0xfa5cfa5c, 23768c2ecf20Sopenharmony_ci .has_pex_clkreq_en = false, 23778c2ecf20Sopenharmony_ci .has_pex_bias_ctrl = false, 23788c2ecf20Sopenharmony_ci .has_intr_prsnt_sense = false, 23798c2ecf20Sopenharmony_ci .has_cml_clk = false, 23808c2ecf20Sopenharmony_ci .has_gen2 = false, 23818c2ecf20Sopenharmony_ci .force_pca_enable = false, 23828c2ecf20Sopenharmony_ci .program_uphy = true, 23838c2ecf20Sopenharmony_ci .update_clamp_threshold = false, 23848c2ecf20Sopenharmony_ci .program_deskew_time = false, 23858c2ecf20Sopenharmony_ci .update_fc_timer = false, 23868c2ecf20Sopenharmony_ci .has_cache_bars = true, 23878c2ecf20Sopenharmony_ci .ectl.enable = false, 23888c2ecf20Sopenharmony_ci}; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra30_pcie_ports[] = { 23918c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 0, .pme.ack_bit = 5 }, 23928c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 8, .pme.ack_bit = 10 }, 23938c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 16, .pme.ack_bit = 18 }, 23948c2ecf20Sopenharmony_ci}; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_cistatic const struct tegra_pcie_soc tegra30_pcie = { 23978c2ecf20Sopenharmony_ci .num_ports = 3, 23988c2ecf20Sopenharmony_ci .ports = tegra30_pcie_ports, 23998c2ecf20Sopenharmony_ci .msi_base_shift = 8, 24008c2ecf20Sopenharmony_ci .afi_pex2_ctrl = 0x128, 24018c2ecf20Sopenharmony_ci .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, 24028c2ecf20Sopenharmony_ci .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, 24038c2ecf20Sopenharmony_ci .pads_refclk_cfg0 = 0xfa5cfa5c, 24048c2ecf20Sopenharmony_ci .pads_refclk_cfg1 = 0xfa5cfa5c, 24058c2ecf20Sopenharmony_ci .has_pex_clkreq_en = true, 24068c2ecf20Sopenharmony_ci .has_pex_bias_ctrl = true, 24078c2ecf20Sopenharmony_ci .has_intr_prsnt_sense = true, 24088c2ecf20Sopenharmony_ci .has_cml_clk = true, 24098c2ecf20Sopenharmony_ci .has_gen2 = false, 24108c2ecf20Sopenharmony_ci .force_pca_enable = false, 24118c2ecf20Sopenharmony_ci .program_uphy = true, 24128c2ecf20Sopenharmony_ci .update_clamp_threshold = false, 24138c2ecf20Sopenharmony_ci .program_deskew_time = false, 24148c2ecf20Sopenharmony_ci .update_fc_timer = false, 24158c2ecf20Sopenharmony_ci .has_cache_bars = false, 24168c2ecf20Sopenharmony_ci .ectl.enable = false, 24178c2ecf20Sopenharmony_ci}; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_cistatic const struct tegra_pcie_soc tegra124_pcie = { 24208c2ecf20Sopenharmony_ci .num_ports = 2, 24218c2ecf20Sopenharmony_ci .ports = tegra20_pcie_ports, 24228c2ecf20Sopenharmony_ci .msi_base_shift = 8, 24238c2ecf20Sopenharmony_ci .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, 24248c2ecf20Sopenharmony_ci .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, 24258c2ecf20Sopenharmony_ci .pads_refclk_cfg0 = 0x44ac44ac, 24268c2ecf20Sopenharmony_ci .has_pex_clkreq_en = true, 24278c2ecf20Sopenharmony_ci .has_pex_bias_ctrl = true, 24288c2ecf20Sopenharmony_ci .has_intr_prsnt_sense = true, 24298c2ecf20Sopenharmony_ci .has_cml_clk = true, 24308c2ecf20Sopenharmony_ci .has_gen2 = true, 24318c2ecf20Sopenharmony_ci .force_pca_enable = false, 24328c2ecf20Sopenharmony_ci .program_uphy = true, 24338c2ecf20Sopenharmony_ci .update_clamp_threshold = true, 24348c2ecf20Sopenharmony_ci .program_deskew_time = false, 24358c2ecf20Sopenharmony_ci .update_fc_timer = false, 24368c2ecf20Sopenharmony_ci .has_cache_bars = false, 24378c2ecf20Sopenharmony_ci .ectl.enable = false, 24388c2ecf20Sopenharmony_ci}; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_cistatic const struct tegra_pcie_soc tegra210_pcie = { 24418c2ecf20Sopenharmony_ci .num_ports = 2, 24428c2ecf20Sopenharmony_ci .ports = tegra20_pcie_ports, 24438c2ecf20Sopenharmony_ci .msi_base_shift = 8, 24448c2ecf20Sopenharmony_ci .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, 24458c2ecf20Sopenharmony_ci .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, 24468c2ecf20Sopenharmony_ci .pads_refclk_cfg0 = 0x90b890b8, 24478c2ecf20Sopenharmony_ci /* FC threshold is bit[25:18] */ 24488c2ecf20Sopenharmony_ci .update_fc_threshold = 0x01800000, 24498c2ecf20Sopenharmony_ci .has_pex_clkreq_en = true, 24508c2ecf20Sopenharmony_ci .has_pex_bias_ctrl = true, 24518c2ecf20Sopenharmony_ci .has_intr_prsnt_sense = true, 24528c2ecf20Sopenharmony_ci .has_cml_clk = true, 24538c2ecf20Sopenharmony_ci .has_gen2 = true, 24548c2ecf20Sopenharmony_ci .force_pca_enable = true, 24558c2ecf20Sopenharmony_ci .program_uphy = true, 24568c2ecf20Sopenharmony_ci .update_clamp_threshold = true, 24578c2ecf20Sopenharmony_ci .program_deskew_time = true, 24588c2ecf20Sopenharmony_ci .update_fc_timer = true, 24598c2ecf20Sopenharmony_ci .has_cache_bars = false, 24608c2ecf20Sopenharmony_ci .ectl = { 24618c2ecf20Sopenharmony_ci .regs = { 24628c2ecf20Sopenharmony_ci .rp_ectl_2_r1 = 0x0000000f, 24638c2ecf20Sopenharmony_ci .rp_ectl_4_r1 = 0x00000067, 24648c2ecf20Sopenharmony_ci .rp_ectl_5_r1 = 0x55010000, 24658c2ecf20Sopenharmony_ci .rp_ectl_6_r1 = 0x00000001, 24668c2ecf20Sopenharmony_ci .rp_ectl_2_r2 = 0x0000008f, 24678c2ecf20Sopenharmony_ci .rp_ectl_4_r2 = 0x000000c7, 24688c2ecf20Sopenharmony_ci .rp_ectl_5_r2 = 0x55010000, 24698c2ecf20Sopenharmony_ci .rp_ectl_6_r2 = 0x00000001, 24708c2ecf20Sopenharmony_ci }, 24718c2ecf20Sopenharmony_ci .enable = true, 24728c2ecf20Sopenharmony_ci }, 24738c2ecf20Sopenharmony_ci}; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_cistatic const struct tegra_pcie_port_soc tegra186_pcie_ports[] = { 24768c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 0, .pme.ack_bit = 5 }, 24778c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 8, .pme.ack_bit = 10 }, 24788c2ecf20Sopenharmony_ci { .pme.turnoff_bit = 12, .pme.ack_bit = 14 }, 24798c2ecf20Sopenharmony_ci}; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_cistatic const struct tegra_pcie_soc tegra186_pcie = { 24828c2ecf20Sopenharmony_ci .num_ports = 3, 24838c2ecf20Sopenharmony_ci .ports = tegra186_pcie_ports, 24848c2ecf20Sopenharmony_ci .msi_base_shift = 8, 24858c2ecf20Sopenharmony_ci .afi_pex2_ctrl = 0x19c, 24868c2ecf20Sopenharmony_ci .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, 24878c2ecf20Sopenharmony_ci .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, 24888c2ecf20Sopenharmony_ci .pads_refclk_cfg0 = 0x80b880b8, 24898c2ecf20Sopenharmony_ci .pads_refclk_cfg1 = 0x000480b8, 24908c2ecf20Sopenharmony_ci .has_pex_clkreq_en = true, 24918c2ecf20Sopenharmony_ci .has_pex_bias_ctrl = true, 24928c2ecf20Sopenharmony_ci .has_intr_prsnt_sense = true, 24938c2ecf20Sopenharmony_ci .has_cml_clk = false, 24948c2ecf20Sopenharmony_ci .has_gen2 = true, 24958c2ecf20Sopenharmony_ci .force_pca_enable = false, 24968c2ecf20Sopenharmony_ci .program_uphy = false, 24978c2ecf20Sopenharmony_ci .update_clamp_threshold = false, 24988c2ecf20Sopenharmony_ci .program_deskew_time = false, 24998c2ecf20Sopenharmony_ci .update_fc_timer = false, 25008c2ecf20Sopenharmony_ci .has_cache_bars = false, 25018c2ecf20Sopenharmony_ci .ectl.enable = false, 25028c2ecf20Sopenharmony_ci}; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_pcie_of_match[] = { 25058c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie }, 25068c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie }, 25078c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie }, 25088c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie }, 25098c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie }, 25108c2ecf20Sopenharmony_ci { }, 25118c2ecf20Sopenharmony_ci}; 25128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_pcie_of_match); 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_cistatic void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos) 25158c2ecf20Sopenharmony_ci{ 25168c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = s->private; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci if (list_empty(&pcie->ports)) 25198c2ecf20Sopenharmony_ci return NULL; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci seq_printf(s, "Index Status\n"); 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci return seq_list_start(&pcie->ports, *pos); 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_cistatic void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos) 25278c2ecf20Sopenharmony_ci{ 25288c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = s->private; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci return seq_list_next(v, &pcie->ports, pos); 25318c2ecf20Sopenharmony_ci} 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_cistatic void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v) 25348c2ecf20Sopenharmony_ci{ 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cistatic int tegra_pcie_ports_seq_show(struct seq_file *s, void *v) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci bool up = false, active = false; 25408c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 25418c2ecf20Sopenharmony_ci unsigned int value; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci port = list_entry(v, struct tegra_pcie_port, list); 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci value = readl(port->base + RP_VEND_XP); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci if (value & RP_VEND_XP_DL_UP) 25488c2ecf20Sopenharmony_ci up = true; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci value = readl(port->base + RP_LINK_CONTROL_STATUS); 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) 25538c2ecf20Sopenharmony_ci active = true; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci seq_printf(s, "%2u ", port->index); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci if (up) 25588c2ecf20Sopenharmony_ci seq_printf(s, "up"); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci if (active) { 25618c2ecf20Sopenharmony_ci if (up) 25628c2ecf20Sopenharmony_ci seq_printf(s, ", "); 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci seq_printf(s, "active"); 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci seq_printf(s, "\n"); 25688c2ecf20Sopenharmony_ci return 0; 25698c2ecf20Sopenharmony_ci} 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_cistatic const struct seq_operations tegra_pcie_ports_sops = { 25728c2ecf20Sopenharmony_ci .start = tegra_pcie_ports_seq_start, 25738c2ecf20Sopenharmony_ci .next = tegra_pcie_ports_seq_next, 25748c2ecf20Sopenharmony_ci .stop = tegra_pcie_ports_seq_stop, 25758c2ecf20Sopenharmony_ci .show = tegra_pcie_ports_seq_show, 25768c2ecf20Sopenharmony_ci}; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_cistatic void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie) 25818c2ecf20Sopenharmony_ci{ 25828c2ecf20Sopenharmony_ci debugfs_remove_recursive(pcie->debugfs); 25838c2ecf20Sopenharmony_ci pcie->debugfs = NULL; 25848c2ecf20Sopenharmony_ci} 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_cistatic void tegra_pcie_debugfs_init(struct tegra_pcie *pcie) 25878c2ecf20Sopenharmony_ci{ 25888c2ecf20Sopenharmony_ci pcie->debugfs = debugfs_create_dir("pcie", NULL); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie, 25918c2ecf20Sopenharmony_ci &tegra_pcie_ports_fops); 25928c2ecf20Sopenharmony_ci} 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_cistatic int tegra_pcie_probe(struct platform_device *pdev) 25958c2ecf20Sopenharmony_ci{ 25968c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 25978c2ecf20Sopenharmony_ci struct pci_host_bridge *host; 25988c2ecf20Sopenharmony_ci struct tegra_pcie *pcie; 25998c2ecf20Sopenharmony_ci int err; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); 26028c2ecf20Sopenharmony_ci if (!host) 26038c2ecf20Sopenharmony_ci return -ENOMEM; 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci pcie = pci_host_bridge_priv(host); 26068c2ecf20Sopenharmony_ci host->sysdata = pcie; 26078c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pcie); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci pcie->soc = of_device_get_match_data(dev); 26108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pcie->ports); 26118c2ecf20Sopenharmony_ci pcie->dev = dev; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci err = tegra_pcie_parse_dt(pcie); 26148c2ecf20Sopenharmony_ci if (err < 0) 26158c2ecf20Sopenharmony_ci return err; 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci err = tegra_pcie_get_resources(pcie); 26188c2ecf20Sopenharmony_ci if (err < 0) { 26198c2ecf20Sopenharmony_ci dev_err(dev, "failed to request resources: %d\n", err); 26208c2ecf20Sopenharmony_ci return err; 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci err = tegra_pcie_msi_setup(pcie); 26248c2ecf20Sopenharmony_ci if (err < 0) { 26258c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable MSI support: %d\n", err); 26268c2ecf20Sopenharmony_ci goto put_resources; 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci pm_runtime_enable(pcie->dev); 26308c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(pcie->dev); 26318c2ecf20Sopenharmony_ci if (err < 0) { 26328c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable pcie controller: %d\n", err); 26338c2ecf20Sopenharmony_ci goto pm_runtime_put; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci host->ops = &tegra_pcie_ops; 26378c2ecf20Sopenharmony_ci host->map_irq = tegra_pcie_map_irq; 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci err = pci_host_probe(host); 26408c2ecf20Sopenharmony_ci if (err < 0) { 26418c2ecf20Sopenharmony_ci dev_err(dev, "failed to register host: %d\n", err); 26428c2ecf20Sopenharmony_ci goto pm_runtime_put; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 26468c2ecf20Sopenharmony_ci tegra_pcie_debugfs_init(pcie); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci return 0; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_cipm_runtime_put: 26518c2ecf20Sopenharmony_ci pm_runtime_put_sync(pcie->dev); 26528c2ecf20Sopenharmony_ci pm_runtime_disable(pcie->dev); 26538c2ecf20Sopenharmony_ci tegra_pcie_msi_teardown(pcie); 26548c2ecf20Sopenharmony_ciput_resources: 26558c2ecf20Sopenharmony_ci tegra_pcie_put_resources(pcie); 26568c2ecf20Sopenharmony_ci return err; 26578c2ecf20Sopenharmony_ci} 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_cistatic int tegra_pcie_remove(struct platform_device *pdev) 26608c2ecf20Sopenharmony_ci{ 26618c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = platform_get_drvdata(pdev); 26628c2ecf20Sopenharmony_ci struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 26638c2ecf20Sopenharmony_ci struct tegra_pcie_port *port, *tmp; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 26668c2ecf20Sopenharmony_ci tegra_pcie_debugfs_exit(pcie); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci pci_stop_root_bus(host->bus); 26698c2ecf20Sopenharmony_ci pci_remove_root_bus(host->bus); 26708c2ecf20Sopenharmony_ci pm_runtime_put_sync(pcie->dev); 26718c2ecf20Sopenharmony_ci pm_runtime_disable(pcie->dev); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) 26748c2ecf20Sopenharmony_ci tegra_pcie_msi_teardown(pcie); 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci tegra_pcie_put_resources(pcie); 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci list_for_each_entry_safe(port, tmp, &pcie->ports, list) 26798c2ecf20Sopenharmony_ci tegra_pcie_port_free(port); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci return 0; 26828c2ecf20Sopenharmony_ci} 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_cistatic int __maybe_unused tegra_pcie_pm_suspend(struct device *dev) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = dev_get_drvdata(dev); 26878c2ecf20Sopenharmony_ci struct tegra_pcie_port *port; 26888c2ecf20Sopenharmony_ci int err; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci list_for_each_entry(port, &pcie->ports, list) 26918c2ecf20Sopenharmony_ci tegra_pcie_pme_turnoff(port); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci tegra_pcie_disable_ports(pcie); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci /* 26968c2ecf20Sopenharmony_ci * AFI_INTR is unmasked in tegra_pcie_enable_controller(), mask it to 26978c2ecf20Sopenharmony_ci * avoid unwanted interrupts raised by AFI after pex_rst is asserted. 26988c2ecf20Sopenharmony_ci */ 26998c2ecf20Sopenharmony_ci tegra_pcie_disable_interrupts(pcie); 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (pcie->soc->program_uphy) { 27028c2ecf20Sopenharmony_ci err = tegra_pcie_phy_power_off(pcie); 27038c2ecf20Sopenharmony_ci if (err < 0) 27048c2ecf20Sopenharmony_ci dev_err(dev, "failed to power off PHY(s): %d\n", err); 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci reset_control_assert(pcie->pex_rst); 27088c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->pex_clk); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) 27118c2ecf20Sopenharmony_ci tegra_pcie_disable_msi(pcie); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci pinctrl_pm_select_idle_state(dev); 27148c2ecf20Sopenharmony_ci tegra_pcie_power_off(pcie); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci return 0; 27178c2ecf20Sopenharmony_ci} 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_cistatic int __maybe_unused tegra_pcie_pm_resume(struct device *dev) 27208c2ecf20Sopenharmony_ci{ 27218c2ecf20Sopenharmony_ci struct tegra_pcie *pcie = dev_get_drvdata(dev); 27228c2ecf20Sopenharmony_ci int err; 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci err = tegra_pcie_power_on(pcie); 27258c2ecf20Sopenharmony_ci if (err) { 27268c2ecf20Sopenharmony_ci dev_err(dev, "tegra pcie power on fail: %d\n", err); 27278c2ecf20Sopenharmony_ci return err; 27288c2ecf20Sopenharmony_ci } 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci err = pinctrl_pm_select_default_state(dev); 27318c2ecf20Sopenharmony_ci if (err < 0) { 27328c2ecf20Sopenharmony_ci dev_err(dev, "failed to disable PCIe IO DPD: %d\n", err); 27338c2ecf20Sopenharmony_ci goto poweroff; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci tegra_pcie_enable_controller(pcie); 27378c2ecf20Sopenharmony_ci tegra_pcie_setup_translations(pcie); 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) 27408c2ecf20Sopenharmony_ci tegra_pcie_enable_msi(pcie); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci err = clk_prepare_enable(pcie->pex_clk); 27438c2ecf20Sopenharmony_ci if (err) { 27448c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable PEX clock: %d\n", err); 27458c2ecf20Sopenharmony_ci goto pex_dpd_enable; 27468c2ecf20Sopenharmony_ci } 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci reset_control_deassert(pcie->pex_rst); 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if (pcie->soc->program_uphy) { 27518c2ecf20Sopenharmony_ci err = tegra_pcie_phy_power_on(pcie); 27528c2ecf20Sopenharmony_ci if (err < 0) { 27538c2ecf20Sopenharmony_ci dev_err(dev, "failed to power on PHY(s): %d\n", err); 27548c2ecf20Sopenharmony_ci goto disable_pex_clk; 27558c2ecf20Sopenharmony_ci } 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci tegra_pcie_apply_pad_settings(pcie); 27598c2ecf20Sopenharmony_ci tegra_pcie_enable_ports(pcie); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci return 0; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_cidisable_pex_clk: 27648c2ecf20Sopenharmony_ci reset_control_assert(pcie->pex_rst); 27658c2ecf20Sopenharmony_ci clk_disable_unprepare(pcie->pex_clk); 27668c2ecf20Sopenharmony_cipex_dpd_enable: 27678c2ecf20Sopenharmony_ci pinctrl_pm_select_idle_state(dev); 27688c2ecf20Sopenharmony_cipoweroff: 27698c2ecf20Sopenharmony_ci tegra_pcie_power_off(pcie); 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci return err; 27728c2ecf20Sopenharmony_ci} 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_cistatic const struct dev_pm_ops tegra_pcie_pm_ops = { 27758c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(tegra_pcie_pm_suspend, tegra_pcie_pm_resume, NULL) 27768c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_pcie_pm_suspend, 27778c2ecf20Sopenharmony_ci tegra_pcie_pm_resume) 27788c2ecf20Sopenharmony_ci}; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_cistatic struct platform_driver tegra_pcie_driver = { 27818c2ecf20Sopenharmony_ci .driver = { 27828c2ecf20Sopenharmony_ci .name = "tegra-pcie", 27838c2ecf20Sopenharmony_ci .of_match_table = tegra_pcie_of_match, 27848c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 27858c2ecf20Sopenharmony_ci .pm = &tegra_pcie_pm_ops, 27868c2ecf20Sopenharmony_ci }, 27878c2ecf20Sopenharmony_ci .probe = tegra_pcie_probe, 27888c2ecf20Sopenharmony_ci .remove = tegra_pcie_remove, 27898c2ecf20Sopenharmony_ci}; 27908c2ecf20Sopenharmony_cimodule_platform_driver(tegra_pcie_driver); 27918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2792